2015-05-06 12:16:45 +03:00
|
|
|
/**
|
|
|
|
* @file smp.c
|
|
|
|
* Security Manager Protocol implementation
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2015 Intel Corporation
|
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2015-05-06 12:16:45 +03:00
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2015-05-06 12:16:45 +03:00
|
|
|
*
|
2015-10-06 11:00:37 -05:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
2015-05-06 12:16:45 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <nanokernel.h>
|
2015-06-03 10:35:58 -04:00
|
|
|
#include <arch/cpu.h>
|
2015-05-06 12:16:45 +03:00
|
|
|
#include <stddef.h>
|
2015-05-19 21:12:30 +03:00
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
2015-09-15 10:08:04 +02:00
|
|
|
#include <atomic.h>
|
2015-05-19 21:12:30 +03:00
|
|
|
#include <misc/util.h>
|
2015-07-09 15:01:30 +03:00
|
|
|
#include <misc/byteorder.h>
|
2015-05-06 12:16:45 +03:00
|
|
|
|
2015-10-28 15:14:46 +02:00
|
|
|
#include <net/buf.h>
|
2015-06-16 17:25:37 +03:00
|
|
|
#include <bluetooth/log.h>
|
2015-05-06 12:16:45 +03:00
|
|
|
#include <bluetooth/hci.h>
|
|
|
|
#include <bluetooth/bluetooth.h>
|
|
|
|
|
2015-09-21 08:57:19 +02:00
|
|
|
#if defined(CONFIG_TINYCRYPT_AES)
|
2015-10-12 10:15:35 -07:00
|
|
|
#include <tinycrypt/aes.h>
|
|
|
|
#include <tinycrypt/utils.h>
|
2015-09-21 08:57:19 +02:00
|
|
|
#endif
|
|
|
|
|
2015-05-06 12:16:45 +03:00
|
|
|
#include "hci_core.h"
|
2015-05-30 18:05:26 +07:00
|
|
|
#include "keys.h"
|
2015-06-15 11:05:35 +03:00
|
|
|
#include "conn_internal.h"
|
2015-10-05 13:53:03 +03:00
|
|
|
#include "l2cap_internal.h"
|
2015-05-06 12:16:45 +03:00
|
|
|
#include "smp.h"
|
2015-09-29 10:56:58 +02:00
|
|
|
#include "stack.h"
|
2015-05-06 12:16:45 +03:00
|
|
|
|
2015-09-28 18:02:28 +02:00
|
|
|
#define SMP_TIMEOUT (30 * sys_clock_ticks_per_sec)
|
|
|
|
|
2015-09-08 14:10:31 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_SIGNING)
|
2015-07-28 15:11:44 +03:00
|
|
|
#define RECV_KEYS (BT_SMP_DIST_ID_KEY | BT_SMP_DIST_ENC_KEY | BT_SMP_DIST_SIGN)
|
|
|
|
#define SEND_KEYS (BT_SMP_DIST_ENC_KEY | BT_SMP_DIST_SIGN)
|
2015-09-08 14:10:31 +02:00
|
|
|
#else
|
|
|
|
#define RECV_KEYS (BT_SMP_DIST_ID_KEY | BT_SMP_DIST_ENC_KEY)
|
|
|
|
#define SEND_KEYS (BT_SMP_DIST_ENC_KEY)
|
|
|
|
#endif /* CONFIG_BLUETOOTH_SIGNING */
|
2015-05-31 22:58:10 +07:00
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
#define RECV_KEYS_SC (RECV_KEYS & ~(BT_SMP_DIST_ENC_KEY | BT_SMP_DIST_LINK_KEY))
|
|
|
|
#define SEND_KEYS_SC (SEND_KEYS & ~(BT_SMP_DIST_ENC_KEY | BT_SMP_DIST_LINK_KEY))
|
|
|
|
|
|
|
|
#define BT_SMP_AUTH_MASK 0x07
|
|
|
|
#define BT_SMP_AUTH_MASK_SC 0x0f
|
|
|
|
|
2015-08-17 12:19:13 +02:00
|
|
|
enum pairing_method {
|
|
|
|
JUST_WORKS, /* JustWorks pairing */
|
|
|
|
PASSKEY_INPUT, /* Passkey Entry input */
|
|
|
|
PASSKEY_DISPLAY, /* Passkey Entry display */
|
2015-10-27 09:24:46 +01:00
|
|
|
PASSKEY_CONFIRM, /* Passkey confirm */
|
2015-08-17 12:19:13 +02:00
|
|
|
PASSKEY_ROLE, /* Passkey Entry depends on role */
|
|
|
|
} ;
|
|
|
|
|
2015-08-17 17:29:48 +02:00
|
|
|
enum {
|
|
|
|
SMP_FLAG_TK_VALID, /* if TK values is valid */
|
|
|
|
SMP_FLAG_CFM_DELAYED, /* if confirm should be send when TK is valid */
|
2015-08-25 11:20:24 +02:00
|
|
|
SMP_FLAG_ENC_PENDING, /* if waiting for an encryption change event */
|
2015-09-24 17:22:40 +02:00
|
|
|
SMP_FLAG_PAIRING, /* if pairing is in progress */
|
2015-09-28 18:02:28 +02:00
|
|
|
SMP_FLAG_TIMEOUT, /* if SMP timeout occurred */
|
2015-10-27 09:24:46 +01:00
|
|
|
SMP_FLAG_SC, /* if LE Secure Connections is used */
|
|
|
|
SMP_FLAG_PKEY_PENDING, /* if waiting for P256 Public Key */
|
2015-10-28 16:02:17 +01:00
|
|
|
SMP_FLAG_DHKEY_PENDING, /* if waiting for local DHKey */
|
|
|
|
SMP_FLAG_DHKEY_SEND, /* if should send DHKey Check after generate */
|
2015-08-17 17:29:48 +02:00
|
|
|
};
|
|
|
|
|
2015-05-21 20:43:42 +03:00
|
|
|
/* SMP channel specific context */
|
|
|
|
struct bt_smp {
|
2015-10-02 16:21:18 +03:00
|
|
|
/* The channel this context is associated with */
|
|
|
|
struct bt_l2cap_chan chan;
|
2015-05-21 20:43:42 +03:00
|
|
|
|
2015-09-28 18:02:28 +02:00
|
|
|
/* SMP Timeout fiber handle */
|
|
|
|
void *timeout;
|
|
|
|
|
2015-07-01 15:07:56 +02:00
|
|
|
/* Commands that remote is allowed to send */
|
|
|
|
atomic_t allowed_cmds;
|
|
|
|
|
2015-08-17 17:29:48 +02:00
|
|
|
/* Flags for SMP state machine */
|
|
|
|
atomic_t flags;
|
|
|
|
|
2015-08-17 12:19:13 +02:00
|
|
|
/* Type of method used for pairing */
|
|
|
|
uint8_t method;
|
|
|
|
|
2015-05-21 20:43:42 +03:00
|
|
|
/* Pairing Request PDU */
|
|
|
|
uint8_t preq[7];
|
|
|
|
|
|
|
|
/* Pairing Response PDU */
|
|
|
|
uint8_t prsp[7];
|
|
|
|
|
|
|
|
/* Pairing Confirm PDU */
|
|
|
|
uint8_t pcnf[16];
|
|
|
|
|
|
|
|
/* Local random number */
|
|
|
|
uint8_t prnd[16];
|
|
|
|
|
|
|
|
/* Remote random number */
|
|
|
|
uint8_t rrnd[16];
|
|
|
|
|
|
|
|
/* Temporary key */
|
|
|
|
uint8_t tk[16];
|
2015-05-22 13:57:56 +03:00
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
/* Remote Public Key for LE SC */
|
|
|
|
uint8_t pkey[64];
|
|
|
|
|
2015-10-28 16:02:17 +01:00
|
|
|
/* DHKey */
|
|
|
|
uint8_t dhkey[32];
|
|
|
|
|
|
|
|
/* DHKey check (local or remote depends on role) */
|
|
|
|
uint8_t e[16];
|
|
|
|
|
|
|
|
/* MacKey */
|
|
|
|
uint8_t mackey[16];
|
|
|
|
|
2015-05-22 13:57:56 +03:00
|
|
|
/* Local key distribution */
|
|
|
|
uint8_t local_dist;
|
2015-07-01 16:21:37 +02:00
|
|
|
|
|
|
|
/* Remote key distribution */
|
|
|
|
uint8_t remote_dist;
|
2015-09-28 18:02:28 +02:00
|
|
|
|
|
|
|
/* stack for timeout fiber */
|
|
|
|
BT_STACK(stack, 128);
|
2015-05-21 20:43:42 +03:00
|
|
|
};
|
2015-05-19 21:12:30 +03:00
|
|
|
|
2015-08-17 12:19:13 +02:00
|
|
|
/* based on table 2.8 Core Spec 2.3.5.1 Vol. 3 Part H */
|
|
|
|
static const uint8_t gen_method[5 /* remote */][5 /* local */] = {
|
|
|
|
{ JUST_WORKS, JUST_WORKS, PASSKEY_INPUT, JUST_WORKS, PASSKEY_INPUT },
|
|
|
|
{ JUST_WORKS, JUST_WORKS, PASSKEY_INPUT, JUST_WORKS, PASSKEY_INPUT },
|
|
|
|
{ PASSKEY_DISPLAY, PASSKEY_DISPLAY, PASSKEY_INPUT, JUST_WORKS,
|
2015-09-23 11:27:05 +02:00
|
|
|
PASSKEY_DISPLAY },
|
2015-08-17 12:19:13 +02:00
|
|
|
{ JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS },
|
|
|
|
{ PASSKEY_DISPLAY, PASSKEY_DISPLAY, PASSKEY_INPUT, JUST_WORKS,
|
|
|
|
PASSKEY_ROLE },
|
|
|
|
};
|
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
/* based on table 2.8 Core Spec 2.3.5.1 Vol. 3 Part H */
|
|
|
|
static const uint8_t gen_method_sc[5 /* remote */][5 /* local */] = {
|
|
|
|
{ JUST_WORKS, JUST_WORKS, PASSKEY_INPUT, JUST_WORKS, PASSKEY_INPUT },
|
|
|
|
{ JUST_WORKS, PASSKEY_CONFIRM, PASSKEY_INPUT, JUST_WORKS,
|
|
|
|
PASSKEY_CONFIRM },
|
|
|
|
{ PASSKEY_DISPLAY, PASSKEY_DISPLAY, PASSKEY_INPUT, JUST_WORKS,
|
|
|
|
PASSKEY_DISPLAY },
|
|
|
|
{ JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS, JUST_WORKS },
|
|
|
|
{ PASSKEY_DISPLAY, PASSKEY_CONFIRM, PASSKEY_INPUT, JUST_WORKS,
|
|
|
|
PASSKEY_INPUT },
|
|
|
|
};
|
|
|
|
|
2015-11-05 21:01:20 +02:00
|
|
|
/* Pool for outgoing LE signaling packets, MTU is 65 */
|
|
|
|
static struct nano_fifo smp_buf;
|
|
|
|
static NET_BUF_POOL(smp_pool, CONFIG_BLUETOOTH_MAX_CONN,
|
|
|
|
BT_L2CAP_BUF_SIZE(65), &smp_buf, NULL, 0);
|
|
|
|
|
2015-05-21 20:43:42 +03:00
|
|
|
static struct bt_smp bt_smp_pool[CONFIG_BLUETOOTH_MAX_CONN];
|
2015-08-05 16:18:13 +02:00
|
|
|
static const struct bt_auth_cb *auth_cb;
|
|
|
|
static uint8_t bt_smp_io_capa = BT_SMP_IO_NO_INPUT_OUTPUT;
|
2015-10-27 09:24:46 +01:00
|
|
|
static bool sc_supported;
|
2015-05-21 20:43:42 +03:00
|
|
|
|
2015-08-17 12:19:13 +02:00
|
|
|
static uint8_t get_pair_method(struct bt_smp *smp, uint8_t remote_io)
|
|
|
|
{
|
2015-10-20 10:05:21 +02:00
|
|
|
struct bt_smp_pairing *req, *rsp;
|
2015-08-17 12:19:13 +02:00
|
|
|
uint8_t method;
|
|
|
|
|
|
|
|
if (remote_io > BT_SMP_IO_KEYBOARD_DISPLAY)
|
|
|
|
return JUST_WORKS;
|
|
|
|
|
2015-10-20 10:05:21 +02:00
|
|
|
req = (struct bt_smp_pairing *)&smp->preq[1];
|
|
|
|
rsp = (struct bt_smp_pairing *)&smp->prsp[1];
|
|
|
|
|
|
|
|
/* if none side requires MITM use JustWorks */
|
2015-11-05 14:05:59 +01:00
|
|
|
if (!((req->auth_req | rsp->auth_req) & BT_SMP_AUTH_MITM)) {
|
2015-10-20 10:05:21 +02:00
|
|
|
return JUST_WORKS;
|
|
|
|
}
|
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_SC)) {
|
|
|
|
return gen_method_sc[remote_io][bt_smp_io_capa];
|
|
|
|
}
|
|
|
|
|
2015-08-17 12:19:13 +02:00
|
|
|
method = gen_method[remote_io][bt_smp_io_capa];
|
|
|
|
|
|
|
|
/* if both sides have KeyboardDisplay capabilities, initiator displays
|
|
|
|
* and responder inputs
|
|
|
|
*/
|
|
|
|
if (method == PASSKEY_ROLE) {
|
2015-10-02 16:21:18 +03:00
|
|
|
if (smp->chan.conn->role == BT_HCI_ROLE_MASTER) {
|
2015-08-17 12:19:13 +02:00
|
|
|
method = PASSKEY_DISPLAY;
|
|
|
|
} else {
|
|
|
|
method = PASSKEY_INPUT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return method;
|
|
|
|
}
|
|
|
|
|
2015-05-21 20:43:42 +03:00
|
|
|
#if defined(CONFIG_BLUETOOTH_DEBUG_SMP)
|
2015-05-19 21:12:30 +03:00
|
|
|
/* Helper for printk parameters to convert from binary to hex.
|
|
|
|
* We declare multiple buffers so the helper can be used multiple times
|
|
|
|
* in a single printk call.
|
|
|
|
*/
|
|
|
|
static const char *h(const void *buf, size_t len)
|
|
|
|
{
|
|
|
|
static const char hex[] = "0123456789abcdef";
|
|
|
|
static char hexbufs[4][129];
|
|
|
|
static uint8_t curbuf;
|
|
|
|
const uint8_t *b = buf;
|
|
|
|
char *str;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
str = hexbufs[curbuf++];
|
|
|
|
curbuf %= ARRAY_SIZE(hexbufs);
|
|
|
|
|
|
|
|
len = min(len, (sizeof(hexbufs[0]) - 1) / 2);
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
str[i * 2] = hex[b[i] >> 4];
|
|
|
|
str[i * 2 + 1] = hex[b[i] & 0xf];
|
|
|
|
}
|
|
|
|
|
|
|
|
str[i * 2] = '\0';
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
#else
|
2015-05-13 14:06:34 +03:00
|
|
|
#undef BT_DBG
|
|
|
|
#define BT_DBG(fmt, ...)
|
|
|
|
#endif
|
|
|
|
|
2015-05-19 21:22:19 +03:00
|
|
|
typedef struct {
|
|
|
|
uint64_t a;
|
|
|
|
uint64_t b;
|
|
|
|
} uint128_t;
|
|
|
|
|
|
|
|
static void xor_128(const uint128_t *p, const uint128_t *q, uint128_t *r)
|
|
|
|
{
|
|
|
|
r->a = p->a ^ q->a;
|
|
|
|
r->b = p->b ^ q->b;
|
|
|
|
}
|
|
|
|
|
2015-09-21 08:57:19 +02:00
|
|
|
/* swap octets for LE encrypt */
|
2015-11-17 12:53:41 +01:00
|
|
|
static void swap_buf(uint8_t *dst, const uint8_t *src, uint16_t len)
|
2015-09-21 08:57:19 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
dst[len - 1 - i] = src[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void swap_in_place(uint8_t *buf, uint16_t len)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i = 0, j = len - 1; i < j; i++, j--) {
|
|
|
|
uint8_t tmp = buf[i];
|
|
|
|
|
|
|
|
buf[i] = buf[j];
|
|
|
|
buf[j] = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_TINYCRYPT_AES)
|
|
|
|
static int le_encrypt(const uint8_t key[16], const uint8_t plaintext[16],
|
|
|
|
uint8_t enc_data[16])
|
|
|
|
{
|
|
|
|
struct tc_aes_key_sched_struct s;
|
|
|
|
uint8_t tmp[16];
|
|
|
|
|
|
|
|
BT_DBG("key %s plaintext %s\n", h(key, 16), h(plaintext, 16));
|
|
|
|
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(tmp, key, 16);
|
2015-09-21 08:57:19 +02:00
|
|
|
|
|
|
|
if (tc_aes128_set_encrypt_key(&s, tmp) == TC_FAIL) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(tmp, plaintext, 16);
|
2015-09-21 08:57:19 +02:00
|
|
|
|
|
|
|
if (tc_aes_encrypt(enc_data, tmp, &s) == TC_FAIL) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
swap_in_place(enc_data, 16);
|
|
|
|
|
|
|
|
BT_DBG("enc_data %s\n", h(enc_data, 16));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else
|
2015-05-19 21:22:19 +03:00
|
|
|
static int le_encrypt(const uint8_t key[16], const uint8_t plaintext[16],
|
|
|
|
uint8_t enc_data[16])
|
|
|
|
{
|
|
|
|
struct bt_hci_cp_le_encrypt *cp;
|
|
|
|
struct bt_hci_rp_le_encrypt *rp;
|
2015-10-28 10:46:51 +02:00
|
|
|
struct net_buf *buf, *rsp;
|
2015-05-19 21:22:19 +03:00
|
|
|
int err;
|
|
|
|
|
|
|
|
BT_DBG("key %s plaintext %s\n", h(key, 16), h(plaintext, 16));
|
|
|
|
|
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_ENCRYPT, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
2015-05-19 21:22:19 +03:00
|
|
|
memcpy(cp->key, key, sizeof(cp->key));
|
|
|
|
memcpy(cp->plaintext, plaintext, sizeof(cp->plaintext));
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_ENCRYPT, buf, &rsp);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
rp = (void *)rsp->data;
|
|
|
|
memcpy(enc_data, rp->enc_data, sizeof(rp->enc_data));
|
2015-10-28 10:46:51 +02:00
|
|
|
net_buf_unref(rsp);
|
2015-05-19 21:22:19 +03:00
|
|
|
|
|
|
|
BT_DBG("enc_data %s\n", h(enc_data, 16));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-09-21 08:57:19 +02:00
|
|
|
#endif
|
2015-05-19 21:22:19 +03:00
|
|
|
|
2015-05-22 13:53:12 +03:00
|
|
|
static int le_rand(void *buf, size_t len)
|
2015-05-19 21:12:30 +03:00
|
|
|
{
|
2015-05-22 13:53:12 +03:00
|
|
|
uint8_t *ptr = buf;
|
|
|
|
|
|
|
|
while (len > 0) {
|
|
|
|
struct bt_hci_rp_le_rand *rp;
|
2015-10-28 10:46:51 +02:00
|
|
|
struct net_buf *rsp;
|
2015-05-22 13:53:12 +03:00
|
|
|
size_t copy;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_RAND, NULL, &rsp);
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("HCI_LE_Random failed (%d)\n", err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
rp = (void *)rsp->data;
|
|
|
|
copy = min(len, sizeof(rp->rand));
|
|
|
|
memcpy(ptr, rp->rand, copy);
|
2015-10-28 10:46:51 +02:00
|
|
|
net_buf_unref(rsp);
|
2015-05-22 13:53:12 +03:00
|
|
|
|
|
|
|
len -= copy;
|
|
|
|
ptr += copy;
|
2015-05-19 21:12:30 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-01 00:18:44 +07:00
|
|
|
static int smp_ah(const uint8_t irk[16], const uint8_t r[3], uint8_t out[3])
|
|
|
|
{
|
|
|
|
uint8_t res[16];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
BT_DBG("irk %s\n, r %s", h(irk, 16), h(r, 3));
|
|
|
|
|
|
|
|
/* r' = padding || r */
|
|
|
|
memcpy(res, r, 3);
|
|
|
|
memset(res + 3, 0, 13);
|
|
|
|
|
|
|
|
err = le_encrypt(irk, res, res);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The output of the random address function ah is:
|
|
|
|
* ah(h, r) = e(k, r') mod 2^24
|
|
|
|
* The output of the security function e is then truncated to 24 bits
|
|
|
|
* by taking the least significant 24 bits of the output of e as the
|
|
|
|
* result of ah.
|
|
|
|
*/
|
|
|
|
memcpy(out, res, 3);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-19 21:22:19 +03:00
|
|
|
static int smp_c1(const uint8_t k[16], const uint8_t r[16],
|
|
|
|
const uint8_t preq[7], const uint8_t pres[7],
|
2015-05-25 09:13:33 +03:00
|
|
|
const bt_addr_le_t *ia, const bt_addr_le_t *ra,
|
2015-05-19 21:22:19 +03:00
|
|
|
uint8_t enc_data[16])
|
|
|
|
{
|
|
|
|
uint8_t p1[16], p2[16];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
BT_DBG("k %s r %s\n", h(k, 16), h(r, 16));
|
2015-05-25 09:13:33 +03:00
|
|
|
BT_DBG("ia %s ra %s\n", bt_addr_le_str(ia), bt_addr_le_str(ra));
|
2015-05-19 21:22:19 +03:00
|
|
|
BT_DBG("preq %s pres %s\n", h(preq, 7), h(pres, 7));
|
|
|
|
|
|
|
|
/* pres, preq, rat and iat are concatenated to generate p1 */
|
2015-05-25 09:13:33 +03:00
|
|
|
p1[0] = ia->type;
|
|
|
|
p1[1] = ra->type;
|
2015-05-19 21:22:19 +03:00
|
|
|
memcpy(p1 + 2, preq, 7);
|
|
|
|
memcpy(p1 + 9, pres, 7);
|
|
|
|
|
|
|
|
BT_DBG("p1 %s\n", h(p1, 16));
|
|
|
|
|
|
|
|
/* c1 = e(k, e(k, r XOR p1) XOR p2) */
|
|
|
|
|
|
|
|
/* Using enc_data as temporary output buffer */
|
|
|
|
xor_128((uint128_t *)r, (uint128_t *)p1, (uint128_t *)enc_data);
|
|
|
|
|
|
|
|
err = le_encrypt(k, enc_data, enc_data);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ra is concatenated with ia and padding to generate p2 */
|
2015-05-25 09:13:33 +03:00
|
|
|
memcpy(p2, ra->val, 6);
|
|
|
|
memcpy(p2 + 6, ia->val, 6);
|
2015-05-19 21:22:19 +03:00
|
|
|
memset(p2 + 12, 0, 4);
|
|
|
|
|
|
|
|
BT_DBG("p2 %s\n", h(p2, 16));
|
|
|
|
|
|
|
|
xor_128((uint128_t *)enc_data, (uint128_t *)p2, (uint128_t *)enc_data);
|
|
|
|
|
|
|
|
return le_encrypt(k, enc_data, enc_data);
|
|
|
|
}
|
|
|
|
|
2015-05-21 13:13:36 +03:00
|
|
|
static int smp_s1(const uint8_t k[16], const uint8_t r1[16],
|
|
|
|
const uint8_t r2[16], uint8_t out[16])
|
|
|
|
{
|
|
|
|
/* The most significant 64-bits of r1 are discarded to generate
|
|
|
|
* r1' and the most significant 64-bits of r2 are discarded to
|
|
|
|
* generate r2'.
|
|
|
|
* r1' is concatenated with r2' to generate r' which is used as
|
|
|
|
* the 128-bit input parameter plaintextData to security function e:
|
|
|
|
*
|
|
|
|
* r' = r1' || r2'
|
|
|
|
*/
|
|
|
|
memcpy(out, r2, 8);
|
|
|
|
memcpy(out + 8, r1, 8);
|
|
|
|
|
|
|
|
/* s1(k, r1 , r2) = e(k, r') */
|
|
|
|
return le_encrypt(k, out, out);
|
|
|
|
}
|
|
|
|
|
2015-11-12 11:36:24 +01:00
|
|
|
/* 1 bit left shift */
|
|
|
|
static void array_shift(const uint8_t *in, uint8_t *out)
|
|
|
|
{
|
|
|
|
uint8_t overflow = 0;
|
|
|
|
|
|
|
|
for (int i = 15; i >= 0; i--) {
|
|
|
|
out[i] = in[i] << 1;
|
|
|
|
/* previous byte */
|
|
|
|
out[i] |= overflow;
|
|
|
|
overflow = in[i] & 0x80 ? 1 : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CMAC subkey generation algorithm */
|
|
|
|
static int cmac_subkey(const uint8_t *key, uint8_t *k1, uint8_t *k2)
|
|
|
|
{
|
2015-11-17 13:53:56 +01:00
|
|
|
static const uint8_t rb[16] = {
|
2015-11-12 11:36:24 +01:00
|
|
|
[0 ... 14] = 0x00,
|
|
|
|
[15] = 0x87,
|
|
|
|
};
|
2015-11-17 14:25:00 +01:00
|
|
|
uint8_t l[16] = { 0 };
|
2015-11-12 11:36:24 +01:00
|
|
|
int err;
|
|
|
|
|
|
|
|
/* L := AES-128(K, const_Zero) */
|
2015-11-17 14:25:00 +01:00
|
|
|
err = le_encrypt(key, l, l);
|
2015-11-12 11:36:24 +01:00
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-11-17 14:25:00 +01:00
|
|
|
swap_in_place(l, 16);
|
2015-11-12 11:36:24 +01:00
|
|
|
|
|
|
|
BT_DBG("l %s\n", h(l, 16));
|
|
|
|
|
|
|
|
/* if MSB(L) == 0 K1 = L << 1 */
|
|
|
|
if (!(l[0] & 0x80)) {
|
|
|
|
array_shift(l, k1);
|
|
|
|
/* else K1 = (L << 1) XOR rb */
|
|
|
|
} else {
|
|
|
|
array_shift(l, k1);
|
|
|
|
xor_128((uint128_t *)k1, (uint128_t *)rb, (uint128_t *)k1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if MSB(K1) == 0 K2 = K1 << 1 */
|
|
|
|
if (!(k1[0] & 0x80)) {
|
|
|
|
array_shift(k1, k2);
|
|
|
|
/* else K2 = (K1 << 1) XOR rb */
|
|
|
|
} else {
|
|
|
|
array_shift(k1, k2);
|
|
|
|
xor_128((uint128_t *)k2, (uint128_t *)rb, (uint128_t *)k2);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* padding(x) = x || 10^i where i is 128 - 8 * r - 1 */
|
|
|
|
static void add_pad(const uint8_t *in, unsigned char *out, int len)
|
|
|
|
{
|
|
|
|
memset(out, 0, 16);
|
|
|
|
memcpy(out, in, len);
|
|
|
|
out[len] = 0x80;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cypher based Message Authentication Code (CMAC) with AES 128 bit
|
|
|
|
*
|
|
|
|
* Input : key ( 128-bit key )
|
|
|
|
* : in ( message to be authenticated )
|
|
|
|
* : len ( length of the message in octets )
|
|
|
|
* Output : out ( message authentication code )
|
|
|
|
*/
|
|
|
|
static int bt_smp_aes_cmac(const uint8_t *key, const uint8_t *in, size_t len,
|
|
|
|
uint8_t *out)
|
|
|
|
{
|
|
|
|
uint8_t k1[16], k2[16], last_block[16], *pad_block = last_block;
|
|
|
|
uint8_t key_s[16];
|
|
|
|
uint8_t *x, *y;
|
|
|
|
uint8_t n, flag;
|
|
|
|
int err;
|
|
|
|
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(key_s, key, 16);
|
2015-11-12 11:36:24 +01:00
|
|
|
|
|
|
|
/* (K1,K2) = Generate_Subkey(K) */
|
|
|
|
err = cmac_subkey(key_s, k1, k2);
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("SMAC subkey generation failed\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("key %s subkeys k1 %s k2 %s\n", h(key, 16), h(k1, 16),
|
|
|
|
h(k2, 16));
|
|
|
|
|
|
|
|
/* the number of blocks, n, is calculated, the block length is 16 bytes
|
|
|
|
* n = ceil(len/const_Bsize)
|
|
|
|
*/
|
|
|
|
n = (len + 15) / 16;
|
|
|
|
|
|
|
|
/* check input length, flag indicate completed blocks */
|
|
|
|
if (n == 0) {
|
|
|
|
/* if length is 0, the number of blocks to be processed shall
|
|
|
|
* be 1,and the flag shall be marked as not-complete-block
|
|
|
|
* false
|
|
|
|
*/
|
|
|
|
n = 1;
|
|
|
|
flag = 0;
|
|
|
|
} else {
|
|
|
|
if ((len % 16) == 0) {
|
|
|
|
/* complete blocks */
|
|
|
|
flag = 1;
|
|
|
|
} else {
|
|
|
|
/* last block is not complete */
|
|
|
|
flag = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("len %u n %u flag %u\n", len, n, flag);
|
|
|
|
|
|
|
|
/* if flag is true then M_last = M_n XOR K1 */
|
|
|
|
if (flag) {
|
|
|
|
xor_128((uint128_t *)&in[16 * (n - 1)], (uint128_t *)k1,
|
|
|
|
(uint128_t *)last_block);
|
|
|
|
/* else M_last = padding(M_n) XOR K2 */
|
|
|
|
} else {
|
|
|
|
add_pad(&in[16 * (n - 1)], pad_block, len % 16);
|
|
|
|
xor_128((uint128_t *)pad_block, (uint128_t *)k2,
|
|
|
|
(uint128_t *)last_block);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reuse k1 and k2 buffers */
|
|
|
|
x = k1;
|
|
|
|
y = k2;
|
|
|
|
|
|
|
|
/* Zeroing x */
|
|
|
|
memset(x, 0, 16);
|
|
|
|
|
|
|
|
/* the basic CBC-MAC is applied to M_1,...,M_{n-1},M_last */
|
|
|
|
for (int i = 0; i < n - 1; i++) {
|
|
|
|
/* Y = X XOR M_i */
|
|
|
|
xor_128((uint128_t *)x, (uint128_t *)&in[i * 16],
|
|
|
|
(uint128_t *)y);
|
|
|
|
|
|
|
|
swap_in_place(y, 16);
|
|
|
|
|
|
|
|
/* X = AES-128(K,Y) */
|
|
|
|
err = le_encrypt(key_s, y, x);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
swap_in_place(x, 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Y = M_last XOR X */
|
|
|
|
xor_128((uint128_t *)x, (uint128_t *)last_block, (uint128_t *)y);
|
|
|
|
|
|
|
|
swap_in_place(y, 16);
|
|
|
|
|
|
|
|
/* T = AES-128(K,Y) */
|
|
|
|
err = le_encrypt(key_s, y, out);
|
|
|
|
|
|
|
|
swap_in_place(out, 16);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-10-14 15:58:23 +02:00
|
|
|
static void smp_reset(struct bt_smp *smp)
|
2015-09-28 18:02:28 +02:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
|
|
|
|
2015-10-12 14:22:09 +02:00
|
|
|
if (smp->timeout) {
|
|
|
|
fiber_fiber_delayed_start_cancel(smp->timeout);
|
|
|
|
smp->timeout = NULL;
|
|
|
|
|
|
|
|
stack_analyze("smp timeout stack", smp->stack,
|
|
|
|
sizeof(smp->stack));
|
|
|
|
}
|
|
|
|
|
2015-09-28 18:02:28 +02:00
|
|
|
smp->method = JUST_WORKS;
|
|
|
|
atomic_set(&smp->allowed_cmds, 0);
|
|
|
|
atomic_set(&smp->flags, 0);
|
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
if (conn->required_sec_level != conn->sec_level) {
|
2015-10-13 16:17:42 +02:00
|
|
|
/* TODO report error */
|
|
|
|
/* reset required security level in case of error */
|
2015-10-02 16:21:18 +03:00
|
|
|
conn->required_sec_level = conn->sec_level;
|
2015-10-13 16:17:42 +02:00
|
|
|
}
|
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
switch (conn->role) {
|
2015-09-28 18:02:28 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
|
|
|
case BT_HCI_ROLE_MASTER:
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_SECURITY_REQUEST);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
|
|
|
|
case BT_HCI_ROLE_SLAVE:
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_REQ);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void smp_timeout(int arg1, int arg2)
|
|
|
|
{
|
|
|
|
struct bt_smp *smp = (struct bt_smp *)arg1;
|
|
|
|
ARG_UNUSED(arg2);
|
|
|
|
|
|
|
|
BT_ERR("SMP Timeout\n");
|
|
|
|
|
|
|
|
smp->timeout = NULL;
|
|
|
|
|
2015-10-14 15:58:23 +02:00
|
|
|
smp_reset(smp);
|
2015-09-28 18:02:28 +02:00
|
|
|
|
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_TIMEOUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void smp_restart_timer(struct bt_smp *smp)
|
|
|
|
{
|
|
|
|
if (smp->timeout) {
|
|
|
|
fiber_fiber_delayed_start_cancel(smp->timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
smp->timeout = fiber_delayed_start(smp->stack, sizeof(smp->stack),
|
|
|
|
smp_timeout, (int) smp, 0, 7, 0,
|
|
|
|
SMP_TIMEOUT);
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
struct net_buf *bt_smp_create_pdu(struct bt_conn *conn, uint8_t op, size_t len)
|
2015-05-06 14:59:42 +03:00
|
|
|
{
|
|
|
|
struct bt_smp_hdr *hdr;
|
2015-10-28 10:46:51 +02:00
|
|
|
struct net_buf *buf;
|
2015-05-06 14:59:42 +03:00
|
|
|
|
2015-11-05 21:01:20 +02:00
|
|
|
buf = bt_l2cap_create_pdu(&smp_buf);
|
2015-05-19 21:17:27 +03:00
|
|
|
if (!buf) {
|
2015-05-06 14:59:42 +03:00
|
|
|
return NULL;
|
2015-05-19 21:17:27 +03:00
|
|
|
}
|
2015-05-06 14:59:42 +03:00
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
hdr = net_buf_add(buf, sizeof(*hdr));
|
2015-05-06 14:59:42 +03:00
|
|
|
hdr->code = op;
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2015-05-06 12:16:45 +03:00
|
|
|
static void send_err_rsp(struct bt_conn *conn, uint8_t reason)
|
|
|
|
{
|
2015-05-06 14:59:42 +03:00
|
|
|
struct bt_smp_pairing_fail *rsp;
|
2015-10-28 10:46:51 +02:00
|
|
|
struct net_buf *buf;
|
2015-05-06 14:59:42 +03:00
|
|
|
|
|
|
|
buf = bt_smp_create_pdu(conn, BT_SMP_CMD_PAIRING_FAIL, sizeof(*rsp));
|
2015-05-19 21:17:27 +03:00
|
|
|
if (!buf) {
|
2015-05-06 14:59:42 +03:00
|
|
|
return;
|
2015-05-19 21:17:27 +03:00
|
|
|
}
|
2015-05-06 14:59:42 +03:00
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
rsp = net_buf_add(buf, sizeof(*rsp));
|
2015-05-06 14:59:42 +03:00
|
|
|
rsp->reason = reason;
|
2015-05-06 12:16:45 +03:00
|
|
|
|
2015-05-20 14:58:18 +03:00
|
|
|
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, buf);
|
2015-05-06 12:16:45 +03:00
|
|
|
}
|
|
|
|
|
2015-05-21 20:43:42 +03:00
|
|
|
static int smp_init(struct bt_smp *smp)
|
2015-05-19 21:12:30 +03:00
|
|
|
{
|
|
|
|
/* Initialize SMP context */
|
2015-10-02 16:21:18 +03:00
|
|
|
memset(smp + sizeof(smp->chan), 0, sizeof(*smp) - sizeof(smp->chan));
|
2015-05-19 21:12:30 +03:00
|
|
|
|
|
|
|
/* Generate local random number */
|
2015-05-22 13:53:12 +03:00
|
|
|
if (le_rand(smp->prnd, 16)) {
|
2015-05-19 21:12:30 +03:00
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("prnd %s\n", h(smp->prnd, 16));
|
|
|
|
|
2015-07-22 18:24:10 +02:00
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_FAIL);
|
|
|
|
|
2015-05-19 21:12:30 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-05 16:18:13 +02:00
|
|
|
static uint8_t get_auth(uint8_t auth)
|
|
|
|
{
|
2015-10-27 09:24:46 +01:00
|
|
|
if (sc_supported) {
|
|
|
|
auth &= BT_SMP_AUTH_MASK_SC;
|
|
|
|
} else {
|
|
|
|
auth &= BT_SMP_AUTH_MASK;
|
|
|
|
}
|
2015-08-05 16:18:13 +02:00
|
|
|
|
|
|
|
if (bt_smp_io_capa == BT_SMP_IO_NO_INPUT_OUTPUT) {
|
|
|
|
auth &= ~(BT_SMP_AUTH_MITM);
|
|
|
|
} else {
|
|
|
|
auth |= BT_SMP_AUTH_MITM;
|
|
|
|
}
|
|
|
|
|
|
|
|
return auth;
|
|
|
|
}
|
|
|
|
|
2015-10-14 16:21:22 +02:00
|
|
|
static uint8_t smp_request_tk(struct bt_smp *smp, uint8_t remote_io)
|
2015-08-05 16:18:13 +02:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-08-26 17:57:26 +02:00
|
|
|
struct bt_keys *keys;
|
2015-08-17 12:19:13 +02:00
|
|
|
uint32_t passkey;
|
2015-08-05 16:18:13 +02:00
|
|
|
|
2015-08-17 12:19:13 +02:00
|
|
|
smp->method = get_pair_method(smp, remote_io);
|
2015-08-05 16:18:13 +02:00
|
|
|
|
2015-08-26 17:57:26 +02:00
|
|
|
/* Fail if we have keys that are stronger than keys that will be
|
|
|
|
* distributed in new pairing. This is to avoid replacing authenticated
|
|
|
|
* keys with unauthenticated ones.
|
|
|
|
*/
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_find_addr(&conn->le.dst);
|
2015-08-26 17:57:26 +02:00
|
|
|
if (keys && keys->type == BT_KEYS_AUTHENTICATED &&
|
|
|
|
smp->method == JUST_WORKS) {
|
|
|
|
BT_ERR("JustWorks failed, authenticated keys present\n");
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
2015-08-17 12:19:13 +02:00
|
|
|
switch (smp->method) {
|
|
|
|
case PASSKEY_DISPLAY:
|
|
|
|
if (le_rand(&passkey, sizeof(passkey))) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
2015-08-05 16:18:13 +02:00
|
|
|
|
2015-08-17 12:19:13 +02:00
|
|
|
passkey %= 1000000;
|
2015-08-05 16:18:13 +02:00
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
auth_cb->passkey_display(conn, passkey);
|
2015-08-05 16:18:13 +02:00
|
|
|
|
2015-08-17 12:19:13 +02:00
|
|
|
passkey = sys_cpu_to_le32(passkey);
|
|
|
|
memcpy(smp->tk, &passkey, sizeof(passkey));
|
2015-08-17 17:29:48 +02:00
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_TK_VALID);
|
2015-08-05 16:18:13 +02:00
|
|
|
|
|
|
|
break;
|
2015-08-17 12:19:13 +02:00
|
|
|
case PASSKEY_INPUT:
|
2015-10-02 16:21:18 +03:00
|
|
|
auth_cb->passkey_entry(conn);
|
2015-08-17 09:16:51 +02:00
|
|
|
break;
|
2015-08-17 12:19:13 +02:00
|
|
|
case JUST_WORKS:
|
2015-08-17 17:29:48 +02:00
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_TK_VALID);
|
2015-08-05 16:18:13 +02:00
|
|
|
break;
|
2015-08-17 12:19:13 +02:00
|
|
|
default:
|
|
|
|
BT_ERR("Unknown pairing method (%u)\n", smp->method);
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
2015-08-05 16:18:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-02 13:42:53 +02:00
|
|
|
static bool sec_level_reachable(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
switch (conn->required_sec_level) {
|
|
|
|
case BT_SECURITY_LOW:
|
|
|
|
case BT_SECURITY_MEDIUM:
|
|
|
|
return true;
|
|
|
|
case BT_SECURITY_HIGH:
|
|
|
|
return bt_smp_io_capa != BT_SMP_IO_NO_INPUT_OUTPUT;
|
|
|
|
case BT_SECURITY_FIPS:
|
2015-10-27 09:24:46 +01:00
|
|
|
return bt_smp_io_capa != BT_SMP_IO_NO_INPUT_OUTPUT &&
|
|
|
|
sc_supported;
|
2015-10-02 13:42:53 +02:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
static struct bt_smp *smp_chan_get(struct bt_conn *conn)
|
|
|
|
{
|
|
|
|
struct bt_l2cap_chan *chan;
|
|
|
|
|
|
|
|
chan = bt_l2cap_lookup_rx_cid(conn, BT_L2CAP_CID_SMP);
|
|
|
|
if (!chan) {
|
|
|
|
BT_ERR("Unable to find SMP channel");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CONTAINER_OF(chan, struct bt_smp, chan);
|
|
|
|
}
|
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
|
2015-10-02 13:42:53 +02:00
|
|
|
int bt_smp_send_security_req(struct bt_conn *conn)
|
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_smp *smp;
|
2015-10-02 13:42:53 +02:00
|
|
|
struct bt_smp_security_request *req;
|
2015-10-28 10:46:51 +02:00
|
|
|
struct net_buf *req_buf;
|
2015-10-02 13:42:53 +02:00
|
|
|
|
|
|
|
BT_DBG("\n");
|
2015-10-02 16:21:18 +03:00
|
|
|
smp = smp_chan_get(conn);
|
|
|
|
if (!smp) {
|
|
|
|
return -ENOTCONN;
|
|
|
|
}
|
2015-10-02 13:42:53 +02:00
|
|
|
|
|
|
|
/* SMP Timeout */
|
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_TIMEOUT)) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* pairing is in progress */
|
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_PAIRING)) {
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* early verify if required sec level if reachable */
|
|
|
|
if (!sec_level_reachable(conn)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
req_buf = bt_smp_create_pdu(conn, BT_SMP_CMD_SECURITY_REQUEST,
|
|
|
|
sizeof(*req));
|
|
|
|
if (!req_buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
req = net_buf_add(req_buf, sizeof(*req));
|
2015-10-27 09:24:46 +01:00
|
|
|
req->auth_req = get_auth(BT_SMP_AUTH_BONDING | BT_SMP_AUTH_SC);
|
2015-10-02 13:42:53 +02:00
|
|
|
|
|
|
|
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, req_buf);
|
|
|
|
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_FAIL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_pairing_req(struct bt_smp *smp, struct net_buf *buf)
|
2015-05-07 14:53:02 +03:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-05-07 14:53:02 +03:00
|
|
|
struct bt_smp_pairing *req = (void *)buf->data;
|
|
|
|
struct bt_smp_pairing *rsp;
|
2015-10-28 10:46:51 +02:00
|
|
|
struct net_buf *rsp_buf;
|
2015-05-19 21:12:30 +03:00
|
|
|
int ret;
|
2015-05-07 14:53:02 +03:00
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
2015-05-08 11:18:52 +03:00
|
|
|
if ((req->max_key_size > BT_SMP_MAX_ENC_KEY_SIZE) ||
|
|
|
|
(req->max_key_size < BT_SMP_MIN_ENC_KEY_SIZE)) {
|
|
|
|
return BT_SMP_ERR_ENC_KEY_SIZE;
|
|
|
|
}
|
|
|
|
|
2015-05-19 21:12:30 +03:00
|
|
|
ret = smp_init(smp);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
rsp_buf = bt_smp_create_pdu(conn, BT_SMP_CMD_PAIRING_RSP, sizeof(*rsp));
|
|
|
|
if (!rsp_buf) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
rsp = net_buf_add(rsp_buf, sizeof(*rsp));
|
2015-05-07 14:53:02 +03:00
|
|
|
|
2015-08-05 16:18:13 +02:00
|
|
|
rsp->auth_req = get_auth(req->auth_req);
|
|
|
|
rsp->io_capability = bt_smp_io_capa;
|
2015-05-07 14:53:02 +03:00
|
|
|
rsp->oob_flag = BT_SMP_OOB_NOT_PRESENT;
|
Bluetooth: SMP: Add support for encryption key size reduction
This allows to pair with devices that use reduced encryption key size.
Encryption key size is stored with keys for future use. LTKs are kept
in full form (16 bytes) and are reduced only when used.
As master:
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, No MITM, Legacy,
No Keypresses (0x01)
Max encryption key size: 16
Initiator key distribution: EncKey Sign (0x05)
Responder key distribution: EncKey IdKey Sign (0x07)
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
< HCI Command: LE Start Encryption (0x08|0x0019) plen 28
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
Long term key: df3cff52a981d6000000000000000000
As slave:
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 16
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
> HCI Event: LE Meta Event (0x3e) plen 13
LE Long Term Key Request (0x05)
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
< HCI Command: LE Long Term Key Request Reply (0x08|0x001a) plen 18
Handle: 64
Long term key: 701b431a9e17bb000000000000000000
Change-Id: Ibc70aa01c040aff0d39410d273d6880d35aa5ae0
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
2015-10-07 12:33:45 +02:00
|
|
|
rsp->max_key_size = BT_SMP_MAX_ENC_KEY_SIZE;
|
2015-05-31 22:58:10 +07:00
|
|
|
rsp->init_key_dist = (req->init_key_dist & RECV_KEYS);
|
|
|
|
rsp->resp_key_dist = (req->resp_key_dist & SEND_KEYS);
|
2015-05-22 13:57:56 +03:00
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
if ((rsp->auth_req & BT_SMP_AUTH_SC) &&
|
|
|
|
(req->auth_req & BT_SMP_AUTH_SC)) {
|
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_SC);
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PUBLIC_KEY);
|
|
|
|
|
|
|
|
rsp->init_key_dist &= RECV_KEYS_SC;
|
|
|
|
rsp->resp_key_dist &= SEND_KEYS_SC;
|
|
|
|
}
|
|
|
|
|
2015-05-22 13:57:56 +03:00
|
|
|
smp->local_dist = rsp->resp_key_dist;
|
2015-07-01 16:21:37 +02:00
|
|
|
smp->remote_dist = rsp->init_key_dist;
|
2015-05-07 14:53:02 +03:00
|
|
|
|
2015-05-19 21:19:16 +03:00
|
|
|
/* Store req/rsp for later use */
|
|
|
|
smp->preq[0] = BT_SMP_CMD_PAIRING_REQ;
|
|
|
|
memcpy(smp->preq + 1, req, sizeof(*req));
|
|
|
|
smp->prsp[0] = BT_SMP_CMD_PAIRING_RSP;
|
|
|
|
memcpy(smp->prsp + 1, rsp, sizeof(*rsp));
|
|
|
|
|
2015-05-20 14:58:18 +03:00
|
|
|
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, rsp_buf);
|
2015-05-07 14:53:02 +03:00
|
|
|
|
2015-09-24 17:22:40 +02:00
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_PAIRING);
|
2015-09-28 18:02:28 +02:00
|
|
|
smp_restart_timer(smp);
|
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_SC)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_CONFIRM);
|
|
|
|
|
2015-10-14 16:21:22 +02:00
|
|
|
return smp_request_tk(smp, req->io_capability);
|
2015-05-07 14:53:02 +03:00
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#else
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_pairing_req(struct bt_smp *smp, struct net_buf *buf)
|
2015-09-07 18:25:59 +02:00
|
|
|
{
|
|
|
|
return BT_SMP_ERR_CMD_NOTSUPP;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
2015-05-07 14:53:02 +03:00
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
static int smp_f4(const uint8_t *u, const uint8_t *v, const uint8_t *x,
|
|
|
|
uint8_t z, uint8_t res[16])
|
|
|
|
{
|
|
|
|
uint8_t xs[16];
|
|
|
|
uint8_t m[65];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
BT_DBG("u %s\n", h(u, 32));
|
|
|
|
BT_DBG("v %s\n", h(v, 32));
|
|
|
|
BT_DBG("x %s z 0x%x\n", h(x, 16), z);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* U, V and Z are concatenated and used as input m to the function
|
|
|
|
* AES-CMAC and X is used as the key k.
|
|
|
|
*
|
|
|
|
* Core Spec 4.2 Vol 3 Part H 2.2.5
|
|
|
|
*
|
|
|
|
* note:
|
|
|
|
* bt_smp_aes_cmac uses BE data and smp_f4 accept LE so we swap
|
|
|
|
*/
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(m, u, 32);
|
|
|
|
swap_buf(m + 32, v, 32);
|
2015-10-27 09:24:46 +01:00
|
|
|
m[64] = z;
|
|
|
|
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(xs, x, 16);
|
2015-10-27 09:24:46 +01:00
|
|
|
|
|
|
|
err = bt_smp_aes_cmac(xs, m, sizeof(m), res);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
swap_in_place(res, 16);
|
|
|
|
|
|
|
|
BT_DBG("res %s\n", h(res, 16));
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-10-28 16:02:17 +01:00
|
|
|
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)
|
|
|
|
{
|
2015-11-17 13:53:56 +01:00
|
|
|
static const uint8_t salt[16] = { 0x6c, 0x88, 0x83, 0x91, 0xaa, 0xf5,
|
|
|
|
0xa5, 0x38, 0x60, 0x37, 0x0b, 0xdb,
|
|
|
|
0x5a, 0x60, 0x83, 0xbe };
|
2015-10-28 16:02:17 +01:00
|
|
|
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));
|
|
|
|
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(ws, w, 32);
|
2015-10-28 16:02:17 +01:00
|
|
|
|
|
|
|
err = bt_smp_aes_cmac(salt, ws, 32, t);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("t %s\n", h(t, 16));
|
|
|
|
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(m + 5, n1, 16);
|
|
|
|
swap_buf(m + 21, n2, 16);
|
2015-10-28 16:02:17 +01:00
|
|
|
m[37] = a1->type;
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(m + 38, a1->val, 6);
|
2015-10-28 16:02:17 +01:00
|
|
|
m[44] = a2->type;
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(m + 45, a2->val, 6);
|
2015-10-28 16:02:17 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-11-12 11:31:40 +01:00
|
|
|
static int smp_f6(const uint8_t *w, const uint8_t *n1, const uint8_t *n2,
|
|
|
|
const uint8_t *r, const uint8_t *iocap, const bt_addr_le_t *a1,
|
|
|
|
const bt_addr_le_t *a2, uint8_t *check)
|
|
|
|
{
|
|
|
|
uint8_t ws[16];
|
|
|
|
uint8_t m[65];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
BT_DBG("w %s\n", h(w, 16));
|
|
|
|
BT_DBG("n1 %s n2 %s\n", h(n1, 16), h(n2, 16));
|
|
|
|
BT_DBG("r %s io_cap\n", h(r, 16), h(iocap, 3));
|
|
|
|
BT_DBG("a1 %s a2 %s\n", h(a1, 7), h(a2, 7));
|
|
|
|
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(m, n1, 16);
|
|
|
|
swap_buf(m + 16, n2, 16);
|
|
|
|
swap_buf(m + 32, r, 16);
|
|
|
|
swap_buf(m + 48, iocap, 3);
|
2015-11-12 11:31:40 +01:00
|
|
|
|
|
|
|
m[51] = a1->type;
|
|
|
|
memcpy(m + 52, a1->val, 6);
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(m + 52, a1->val, 6);
|
2015-11-12 11:31:40 +01:00
|
|
|
|
|
|
|
m[58] = a2->type;
|
|
|
|
memcpy(m + 59, a2->val, 6);
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(m + 59, a2->val, 6);
|
2015-11-12 11:31:40 +01:00
|
|
|
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(ws, w, 16);
|
2015-11-12 11:31:40 +01:00
|
|
|
|
|
|
|
err = bt_smp_aes_cmac(ws, m, sizeof(m), check);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("res %s\n", h(check, 16));
|
|
|
|
|
|
|
|
swap_in_place(check, 16);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
static uint8_t smp_send_pairing_confirm(struct bt_smp *smp)
|
2015-07-03 10:45:20 +02:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-10-02 13:42:53 +02:00
|
|
|
struct bt_smp_pairing_confirm *req;
|
2015-10-28 10:46:51 +02:00
|
|
|
struct net_buf *rsp_buf;
|
2015-10-02 13:42:53 +02:00
|
|
|
int err;
|
2015-08-17 18:20:38 +02:00
|
|
|
|
2015-10-02 13:42:53 +02:00
|
|
|
rsp_buf = bt_smp_create_pdu(conn, BT_SMP_CMD_PAIRING_CONFIRM,
|
2015-07-03 10:45:20 +02:00
|
|
|
sizeof(*req));
|
2015-10-02 13:42:53 +02:00
|
|
|
if (!rsp_buf) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
2015-07-03 10:45:20 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
req = net_buf_add(rsp_buf, sizeof(*req));
|
2015-07-03 10:45:20 +02:00
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_SC)) {
|
|
|
|
err = smp_f4(bt_dev.pkey, smp->pkey, smp->prnd, 0, req->val);
|
|
|
|
} else {
|
|
|
|
err = smp_c1(smp->tk, smp->prnd, smp->preq, smp->prsp,
|
|
|
|
&conn->le.init_addr, &conn->le.resp_addr, req->val);
|
|
|
|
}
|
|
|
|
|
2015-10-02 13:42:53 +02:00
|
|
|
if (err) {
|
2015-10-28 10:46:51 +02:00
|
|
|
net_buf_unref(rsp_buf);
|
2015-10-02 13:42:53 +02:00
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
2015-08-28 14:39:34 +02:00
|
|
|
}
|
|
|
|
|
2015-10-02 13:42:53 +02:00
|
|
|
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, rsp_buf);
|
2015-07-03 10:45:20 +02:00
|
|
|
|
2015-10-02 13:42:53 +02:00
|
|
|
atomic_clear_bit(&smp->flags, SMP_FLAG_CFM_DELAYED);
|
|
|
|
|
|
|
|
smp_restart_timer(smp);
|
2015-07-22 18:24:10 +02:00
|
|
|
|
2015-07-03 10:45:20 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
static uint8_t sc_send_public_key(struct bt_smp *smp)
|
|
|
|
{
|
|
|
|
struct bt_smp_public_key *req;
|
|
|
|
struct net_buf *req_buf;
|
|
|
|
|
|
|
|
req_buf = bt_smp_create_pdu(smp->chan.conn, BT_SMP_CMD_PUBLIC_KEY,
|
|
|
|
sizeof(*req));
|
|
|
|
if (!req_buf) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
req = net_buf_add(req_buf, sizeof(*req));
|
|
|
|
|
|
|
|
memcpy(req->x, bt_dev.pkey, sizeof(req->x));
|
|
|
|
memcpy(req->y, &bt_dev.pkey[32], sizeof(req->y));
|
|
|
|
|
|
|
|
bt_l2cap_send(smp->chan.conn, BT_L2CAP_CID_SMP, req_buf);
|
|
|
|
|
|
|
|
smp_restart_timer(smp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
2015-07-06 14:47:06 +02:00
|
|
|
int bt_smp_send_pairing_req(struct bt_conn *conn)
|
2015-06-24 16:52:19 +02:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_smp *smp;
|
2015-06-24 16:52:19 +02:00
|
|
|
struct bt_smp_pairing *req;
|
2015-10-28 10:46:51 +02:00
|
|
|
struct net_buf *req_buf;
|
2015-06-24 16:52:19 +02:00
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
smp = smp_chan_get(conn);
|
|
|
|
if (!smp) {
|
|
|
|
return -ENOTCONN;
|
|
|
|
}
|
|
|
|
|
2015-09-28 18:02:28 +02:00
|
|
|
/* SMP Timeout */
|
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_TIMEOUT)) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2015-09-24 17:31:02 +02:00
|
|
|
/* pairing is in progress */
|
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_PAIRING)) {
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
2015-08-17 18:20:38 +02:00
|
|
|
/* early verify if required sec level if reachable */
|
|
|
|
if (!sec_level_reachable(conn)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2015-06-24 16:52:19 +02:00
|
|
|
if (smp_init(smp)) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
req_buf = bt_smp_create_pdu(conn, BT_SMP_CMD_PAIRING_REQ, sizeof(*req));
|
|
|
|
if (!req_buf) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
req = net_buf_add(req_buf, sizeof(*req));
|
2015-06-24 16:52:19 +02:00
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
req->auth_req = get_auth(BT_SMP_AUTH_BONDING | BT_SMP_AUTH_SC);
|
2015-08-05 16:18:13 +02:00
|
|
|
req->io_capability = bt_smp_io_capa;
|
2015-06-24 16:52:19 +02:00
|
|
|
req->oob_flag = BT_SMP_OOB_NOT_PRESENT;
|
|
|
|
req->max_key_size = BT_SMP_MAX_ENC_KEY_SIZE;
|
|
|
|
req->init_key_dist = SEND_KEYS;
|
|
|
|
req->resp_key_dist = RECV_KEYS;
|
|
|
|
|
|
|
|
smp->local_dist = SEND_KEYS;
|
2015-07-01 16:21:37 +02:00
|
|
|
smp->remote_dist = RECV_KEYS;
|
2015-06-24 16:52:19 +02:00
|
|
|
|
|
|
|
/* Store req for later use */
|
|
|
|
smp->preq[0] = BT_SMP_CMD_PAIRING_REQ;
|
|
|
|
memcpy(smp->preq + 1, req, sizeof(*req));
|
|
|
|
|
|
|
|
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, req_buf);
|
|
|
|
|
2015-07-01 15:07:56 +02:00
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_RSP);
|
2015-09-24 17:22:40 +02:00
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_PAIRING);
|
2015-07-01 15:07:56 +02:00
|
|
|
|
2015-09-28 18:02:28 +02:00
|
|
|
smp_restart_timer(smp);
|
|
|
|
|
2015-06-24 16:52:19 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2015-06-24 21:22:36 +02:00
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_pairing_rsp(struct bt_smp *smp, struct net_buf *buf)
|
2015-06-24 16:52:19 +02:00
|
|
|
{
|
|
|
|
struct bt_smp_pairing *rsp = (void *)buf->data;
|
2015-10-27 09:24:46 +01:00
|
|
|
struct bt_smp_pairing *req = (struct bt_smp_pairing *)&smp->preq[1];
|
2015-08-05 16:18:13 +02:00
|
|
|
uint8_t ret;
|
2015-06-24 16:52:19 +02:00
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
|
|
|
if ((rsp->max_key_size > BT_SMP_MAX_ENC_KEY_SIZE) ||
|
|
|
|
(rsp->max_key_size < BT_SMP_MIN_ENC_KEY_SIZE)) {
|
|
|
|
return BT_SMP_ERR_ENC_KEY_SIZE;
|
|
|
|
}
|
|
|
|
|
2015-07-01 18:39:33 +02:00
|
|
|
smp->local_dist &= rsp->init_key_dist;
|
2015-07-01 16:21:37 +02:00
|
|
|
smp->remote_dist &= rsp->resp_key_dist;
|
2015-06-24 16:52:19 +02:00
|
|
|
|
|
|
|
/* Store rsp for later use */
|
|
|
|
smp->prsp[0] = BT_SMP_CMD_PAIRING_RSP;
|
|
|
|
memcpy(smp->prsp + 1, rsp, sizeof(*rsp));
|
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
if ((rsp->auth_req & BT_SMP_AUTH_SC) &&
|
|
|
|
(req->auth_req & BT_SMP_AUTH_SC)) {
|
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_SC);
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PUBLIC_KEY);
|
|
|
|
|
|
|
|
smp->local_dist &= SEND_KEYS_SC;
|
|
|
|
smp->remote_dist &= RECV_KEYS_SC;
|
|
|
|
|
|
|
|
return sc_send_public_key(smp);
|
|
|
|
}
|
|
|
|
|
2015-10-14 16:21:22 +02:00
|
|
|
ret = smp_request_tk(smp, rsp->io_capability);
|
2015-08-05 16:18:13 +02:00
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-17 17:29:48 +02:00
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_TK_VALID)) {
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_CONFIRM);
|
2015-10-02 16:21:18 +03:00
|
|
|
return smp_send_pairing_confirm(smp);
|
2015-08-17 09:16:51 +02:00
|
|
|
}
|
|
|
|
|
2015-08-17 17:29:48 +02:00
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_CFM_DELAYED);
|
|
|
|
|
|
|
|
return 0;
|
2015-06-24 16:52:19 +02:00
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#else
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_pairing_rsp(struct bt_smp *smp, struct net_buf *buf)
|
2015-09-07 18:25:59 +02:00
|
|
|
{
|
|
|
|
return BT_SMP_ERR_CMD_NOTSUPP;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
2015-06-24 16:52:19 +02:00
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
static uint8_t smp_send_pairing_random(struct bt_smp *smp)
|
2015-06-24 22:52:25 +02:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-06-24 22:52:25 +02:00
|
|
|
struct bt_smp_pairing_random *req;
|
2015-10-28 10:46:51 +02:00
|
|
|
struct net_buf *rsp_buf;
|
2015-06-24 22:52:25 +02:00
|
|
|
|
|
|
|
rsp_buf = bt_smp_create_pdu(conn, BT_SMP_CMD_PAIRING_RANDOM,
|
|
|
|
sizeof(*req));
|
|
|
|
if (!rsp_buf) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
req = net_buf_add(rsp_buf, sizeof(*req));
|
2015-06-24 22:52:25 +02:00
|
|
|
memcpy(req->val, smp->prnd, sizeof(req->val));
|
|
|
|
|
|
|
|
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, rsp_buf);
|
|
|
|
|
2015-09-28 18:02:28 +02:00
|
|
|
smp_restart_timer(smp);
|
|
|
|
|
2015-06-24 22:52:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_pairing_confirm(struct bt_smp *smp, struct net_buf *buf)
|
2015-05-07 16:37:50 +03:00
|
|
|
{
|
|
|
|
struct bt_smp_pairing_confirm *req = (void *)buf->data;
|
2015-05-19 21:22:19 +03:00
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
|
|
|
memcpy(smp->pcnf, req->val, sizeof(smp->pcnf));
|
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
2015-10-02 16:21:18 +03:00
|
|
|
if (smp->chan.conn->role == BT_HCI_ROLE_MASTER) {
|
2015-08-17 17:29:48 +02:00
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_RANDOM);
|
2015-10-02 16:21:18 +03:00
|
|
|
return smp_send_pairing_random(smp);
|
2015-08-17 17:29:48 +02:00
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
2015-07-01 15:07:56 +02:00
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
|
2015-08-17 17:29:48 +02:00
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_TK_VALID)) {
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_RANDOM);
|
2015-10-02 16:21:18 +03:00
|
|
|
return smp_send_pairing_confirm(smp);
|
2015-05-19 21:22:19 +03:00
|
|
|
}
|
|
|
|
|
2015-08-17 17:29:48 +02:00
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_CFM_DELAYED);
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
2015-08-17 17:29:48 +02:00
|
|
|
return 0;
|
2015-05-19 21:22:19 +03:00
|
|
|
}
|
|
|
|
|
2015-08-17 18:01:03 +02:00
|
|
|
static uint8_t get_keys_type(uint8_t method)
|
|
|
|
{
|
|
|
|
switch (method) {
|
|
|
|
case PASSKEY_DISPLAY:
|
|
|
|
case PASSKEY_INPUT:
|
2015-10-27 09:24:46 +01:00
|
|
|
case PASSKEY_CONFIRM:
|
2015-08-17 18:01:03 +02:00
|
|
|
return BT_KEYS_AUTHENTICATED;
|
|
|
|
case JUST_WORKS:
|
|
|
|
default:
|
|
|
|
return BT_KEYS_UNAUTHENTICATED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Bluetooth: SMP: Add support for encryption key size reduction
This allows to pair with devices that use reduced encryption key size.
Encryption key size is stored with keys for future use. LTKs are kept
in full form (16 bytes) and are reduced only when used.
As master:
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, No MITM, Legacy,
No Keypresses (0x01)
Max encryption key size: 16
Initiator key distribution: EncKey Sign (0x05)
Responder key distribution: EncKey IdKey Sign (0x07)
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
< HCI Command: LE Start Encryption (0x08|0x0019) plen 28
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
Long term key: df3cff52a981d6000000000000000000
As slave:
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 16
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
> HCI Event: LE Meta Event (0x3e) plen 13
LE Long Term Key Request (0x05)
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
< HCI Command: LE Long Term Key Request Reply (0x08|0x001a) plen 18
Handle: 64
Long term key: 701b431a9e17bb000000000000000000
Change-Id: Ibc70aa01c040aff0d39410d273d6880d35aa5ae0
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
2015-10-07 12:33:45 +02:00
|
|
|
static uint8_t get_encryption_key_size(struct bt_smp *smp)
|
|
|
|
{
|
|
|
|
struct bt_smp_pairing *req, *rsp;
|
|
|
|
|
|
|
|
req = (struct bt_smp_pairing *)&smp->preq[1];
|
|
|
|
rsp = (struct bt_smp_pairing *)&smp->prsp[1];
|
|
|
|
|
|
|
|
/* The smaller value of the initiating and responding devices maximum
|
|
|
|
* encryption key length parameters shall be used as the encryption key
|
|
|
|
* size.
|
|
|
|
*/
|
|
|
|
return min(req->max_key_size, rsp->max_key_size);
|
|
|
|
}
|
|
|
|
|
2015-10-28 16:02:17 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t smp_sc_calculate_ltk_mac_dhcheck(struct bt_smp *smp, uint8_t *e)
|
|
|
|
{
|
2015-11-12 11:31:40 +01:00
|
|
|
uint8_t r[16];
|
|
|
|
|
2015-10-28 16:02:17 +01:00
|
|
|
BT_DBG("\n");
|
|
|
|
|
2015-11-12 11:31:40 +01:00
|
|
|
/* TODO currently only NumComparison/JustWorks */
|
|
|
|
memset(r, 0, sizeof(r));
|
|
|
|
|
2015-10-28 16:02:17 +01:00
|
|
|
#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;
|
|
|
|
}
|
2015-11-12 11:31:40 +01:00
|
|
|
/* calculate local DHKey check */
|
|
|
|
if (smp_f6(smp->mackey, smp->prnd, smp->rrnd, r, &smp->preq[1],
|
|
|
|
&smp->chan.conn->le.init_addr,
|
|
|
|
&smp->chan.conn->le.resp_addr, e)) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2015-10-28 16:02:17 +01:00
|
|
|
}
|
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
2015-11-12 11:31:40 +01:00
|
|
|
/* calculate local DHKey check */
|
|
|
|
if (smp_f6(smp->mackey, smp->prnd, smp->rrnd, r, &smp->prsp[1],
|
|
|
|
&smp->chan.conn->le.resp_addr,
|
|
|
|
&smp->chan.conn->le.init_addr, e)) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
2015-10-28 16:02:17 +01:00
|
|
|
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
2015-11-12 11:31:40 +01:00
|
|
|
return 0;
|
2015-10-28 16:02:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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)) {
|
2015-11-12 11:31:40 +01:00
|
|
|
uint8_t r[16], e[16], re[16];
|
2015-10-28 16:02:17 +01:00
|
|
|
|
|
|
|
/* calculate mac, ltk and local dhcheck */
|
|
|
|
smp_sc_calculate_ltk_mac_dhcheck(smp, e);
|
2015-11-12 11:31:40 +01:00
|
|
|
|
|
|
|
/* TODO currently only NumComparison/JustWorks */
|
|
|
|
memset(r, 0, sizeof(r));
|
|
|
|
|
|
|
|
/* calculate remote DHKey check */
|
|
|
|
if (smp_f6(smp->mackey, smp->prnd, smp->rrnd, r, &smp->preq[1],
|
|
|
|
&smp->chan.conn->le.init_addr,
|
|
|
|
&smp->chan.conn->le.resp_addr, re)) {
|
|
|
|
send_err_rsp(smp->chan.conn, BT_SMP_ERR_UNSPECIFIED);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compare received E with calculated remote */
|
|
|
|
if (memcmp(smp->e, re, 16)) {
|
|
|
|
send_err_rsp(smp->chan.conn,
|
|
|
|
BT_SMP_ERR_DHKEY_CHECK_FAILED);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* send local e */
|
|
|
|
sc_smp_send_dhkey_check(smp, e);
|
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_ENC_PENDING);
|
2015-10-28 16:02:17 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
|
|
|
}
|
2015-10-28 13:25:44 +01:00
|
|
|
static uint8_t sc_smp_pairing_random(struct bt_smp *smp, struct net_buf *buf)
|
|
|
|
{
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
|
|
|
/* TODO */
|
|
|
|
if (smp->method != JUST_WORKS) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
|
|
|
if (smp->chan.conn->role == BT_HCI_ROLE_MASTER) {
|
|
|
|
uint8_t cfm[16];
|
2015-10-28 16:02:17 +01:00
|
|
|
uint8_t e[16];
|
2015-10-28 13:25:44 +01:00
|
|
|
int err;
|
|
|
|
|
|
|
|
err = smp_f4(smp->pkey, bt_dev.pkey, smp->rrnd, 0, cfm);
|
|
|
|
if (err) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("pcnf %s cfm %s\n", h(smp->pcnf, 16), h(cfm, 16));
|
|
|
|
|
|
|
|
if (memcmp(smp->pcnf, cfm, 16)) {
|
|
|
|
return BT_SMP_ERR_CONFIRM_FAILED;
|
|
|
|
}
|
|
|
|
|
2015-10-28 16:02:17 +01:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2015-10-28 13:25:44 +01:00
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_DHKEY_CHECK);
|
2015-10-28 16:02:17 +01:00
|
|
|
return sc_smp_send_dhkey_check(smp, e);
|
2015-10-28 13:25:44 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
|
|
|
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_DHKEY_CHECK);
|
|
|
|
smp_send_pairing_random(smp);
|
|
|
|
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_pairing_random(struct bt_smp *smp, struct net_buf *buf)
|
2015-05-19 21:22:19 +03:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-05-19 21:22:19 +03:00
|
|
|
struct bt_smp_pairing_random *req = (void *)buf->data;
|
2015-05-21 15:28:24 +03:00
|
|
|
struct bt_keys *keys;
|
|
|
|
uint8_t cfm[16];
|
2015-05-19 21:22:19 +03:00
|
|
|
int err;
|
2015-05-07 16:37:50 +03:00
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
2015-05-19 21:22:19 +03:00
|
|
|
memcpy(smp->rrnd, req->val, sizeof(smp->rrnd));
|
2015-05-07 16:37:50 +03:00
|
|
|
|
2015-10-28 13:25:44 +01:00
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_SC)) {
|
|
|
|
return sc_smp_pairing_random(smp, buf);
|
|
|
|
}
|
|
|
|
|
2015-11-03 12:19:01 +01:00
|
|
|
err = smp_c1(smp->tk, smp->rrnd, smp->preq, smp->prsp,
|
|
|
|
&conn->le.init_addr, &conn->le.resp_addr, cfm);
|
2015-05-19 21:22:19 +03:00
|
|
|
if (err) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_DBG("pcnf %s cfm %s\n", h(smp->pcnf, 16), h(cfm, 16));
|
|
|
|
|
|
|
|
if (memcmp(smp->pcnf, cfm, sizeof(smp->pcnf))) {
|
|
|
|
return BT_SMP_ERR_CONFIRM_FAILED;
|
|
|
|
}
|
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
2015-06-24 22:52:25 +02:00
|
|
|
if (conn->role == BT_HCI_ROLE_MASTER) {
|
2015-06-29 18:45:40 +02:00
|
|
|
uint8_t stk[16];
|
|
|
|
|
|
|
|
/* No need to store master STK */
|
|
|
|
err = smp_s1(smp->tk, smp->rrnd, smp->prnd, stk);
|
|
|
|
if (err) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_get_addr(&conn->le.dst);
|
2015-08-26 17:26:28 +02:00
|
|
|
if (!keys) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* store key type deducted from pairing method used
|
|
|
|
* it is important to store it since type is used to determine
|
|
|
|
* security level upon encryption
|
|
|
|
*/
|
|
|
|
keys->type = get_keys_type(smp->method);
|
Bluetooth: SMP: Add support for encryption key size reduction
This allows to pair with devices that use reduced encryption key size.
Encryption key size is stored with keys for future use. LTKs are kept
in full form (16 bytes) and are reduced only when used.
As master:
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, No MITM, Legacy,
No Keypresses (0x01)
Max encryption key size: 16
Initiator key distribution: EncKey Sign (0x05)
Responder key distribution: EncKey IdKey Sign (0x07)
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
< HCI Command: LE Start Encryption (0x08|0x0019) plen 28
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
Long term key: df3cff52a981d6000000000000000000
As slave:
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 16
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
> HCI Event: LE Meta Event (0x3e) plen 13
LE Long Term Key Request (0x05)
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
< HCI Command: LE Long Term Key Request Reply (0x08|0x001a) plen 18
Handle: 64
Long term key: 701b431a9e17bb000000000000000000
Change-Id: Ibc70aa01c040aff0d39410d273d6880d35aa5ae0
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
2015-10-07 12:33:45 +02:00
|
|
|
keys->enc_size = get_encryption_key_size(smp);
|
2015-08-26 17:26:28 +02:00
|
|
|
|
2015-06-29 18:45:40 +02:00
|
|
|
/* Rand and EDiv are 0 for the STK */
|
Bluetooth: SMP: Add support for encryption key size reduction
This allows to pair with devices that use reduced encryption key size.
Encryption key size is stored with keys for future use. LTKs are kept
in full form (16 bytes) and are reduced only when used.
As master:
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, No MITM, Legacy,
No Keypresses (0x01)
Max encryption key size: 16
Initiator key distribution: EncKey Sign (0x05)
Responder key distribution: EncKey IdKey Sign (0x07)
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
< HCI Command: LE Start Encryption (0x08|0x0019) plen 28
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
Long term key: df3cff52a981d6000000000000000000
As slave:
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 16
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
> HCI Event: LE Meta Event (0x3e) plen 13
LE Long Term Key Request (0x05)
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
< HCI Command: LE Long Term Key Request Reply (0x08|0x001a) plen 18
Handle: 64
Long term key: 701b431a9e17bb000000000000000000
Change-Id: Ibc70aa01c040aff0d39410d273d6880d35aa5ae0
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
2015-10-07 12:33:45 +02:00
|
|
|
if (bt_conn_le_start_encryption(conn, 0, 0, stk,
|
|
|
|
keys->enc_size)) {
|
2015-06-29 18:45:40 +02:00
|
|
|
BT_ERR("Failed to start encryption\n");
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
2015-08-25 11:20:24 +02:00
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_ENC_PENDING);
|
2015-06-29 18:45:40 +02:00
|
|
|
|
|
|
|
return 0;
|
2015-06-24 22:52:25 +02:00
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
2015-06-24 22:52:25 +02:00
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_get_type(BT_KEYS_SLAVE_LTK, &conn->le.dst);
|
2015-05-21 15:28:24 +03:00
|
|
|
if (!keys) {
|
|
|
|
BT_ERR("Unable to create new keys\n");
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
2015-05-22 13:54:41 +03:00
|
|
|
err = smp_s1(smp->tk, smp->prnd, smp->rrnd, keys->slave_ltk.val);
|
2015-05-21 13:13:36 +03:00
|
|
|
if (err) {
|
2015-05-31 22:17:19 +07:00
|
|
|
bt_keys_clear(keys, BT_KEYS_SLAVE_LTK);
|
2015-05-21 13:13:36 +03:00
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
2015-08-26 17:26:28 +02:00
|
|
|
/* store key type deducted from pairing method used
|
|
|
|
* it is important to store it since type is used to determine
|
|
|
|
* security level upon encryption
|
|
|
|
*/
|
|
|
|
keys->type = get_keys_type(smp->method);
|
Bluetooth: SMP: Add support for encryption key size reduction
This allows to pair with devices that use reduced encryption key size.
Encryption key size is stored with keys for future use. LTKs are kept
in full form (16 bytes) and are reduced only when used.
As master:
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, No MITM, Legacy,
No Keypresses (0x01)
Max encryption key size: 16
Initiator key distribution: EncKey Sign (0x05)
Responder key distribution: EncKey IdKey Sign (0x07)
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
< HCI Command: LE Start Encryption (0x08|0x0019) plen 28
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
Long term key: df3cff52a981d6000000000000000000
As slave:
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 16
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
> HCI Event: LE Meta Event (0x3e) plen 13
LE Long Term Key Request (0x05)
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
< HCI Command: LE Long Term Key Request Reply (0x08|0x001a) plen 18
Handle: 64
Long term key: 701b431a9e17bb000000000000000000
Change-Id: Ibc70aa01c040aff0d39410d273d6880d35aa5ae0
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
2015-10-07 12:33:45 +02:00
|
|
|
keys->enc_size = get_encryption_key_size(smp);
|
2015-08-17 18:01:03 +02:00
|
|
|
|
2015-05-22 13:54:41 +03:00
|
|
|
/* Rand and EDiv are 0 for the STK */
|
|
|
|
keys->slave_ltk.rand = 0;
|
|
|
|
keys->slave_ltk.ediv = 0;
|
|
|
|
|
|
|
|
BT_DBG("generated STK %s\n", h(keys->slave_ltk.val, 16));
|
2015-05-21 13:13:36 +03:00
|
|
|
|
2015-08-25 11:20:24 +02:00
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_ENC_PENDING);
|
2015-06-01 00:15:42 +07:00
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
smp_send_pairing_random(smp);
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
2015-05-19 21:22:19 +03:00
|
|
|
|
2015-05-07 16:37:50 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_pairing_failed(struct bt_smp *smp, struct net_buf *buf)
|
2015-07-01 21:10:18 +02:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-07-01 21:10:18 +02:00
|
|
|
struct bt_smp_pairing_fail *req = (void *)buf->data;
|
|
|
|
|
|
|
|
BT_ERR("reason 0x%x\n", req->reason);
|
|
|
|
|
|
|
|
/* TODO report error
|
|
|
|
* for now this to avoid warning about unused variable when debugs are
|
|
|
|
* disabled
|
|
|
|
*/
|
|
|
|
ARG_UNUSED(req);
|
|
|
|
|
2015-08-17 17:49:46 +02:00
|
|
|
switch (smp->method) {
|
|
|
|
case PASSKEY_INPUT:
|
|
|
|
case PASSKEY_DISPLAY:
|
2015-10-27 09:24:46 +01:00
|
|
|
case PASSKEY_CONFIRM:
|
2015-08-05 16:18:13 +02:00
|
|
|
auth_cb->cancel(conn);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-10-14 15:58:23 +02:00
|
|
|
smp_reset(smp);
|
2015-08-17 17:49:46 +02:00
|
|
|
|
2015-07-01 21:10:18 +02:00
|
|
|
/* return no error to avoid sending Pairing Failed in response */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
static void bt_smp_distribute_keys(struct bt_smp *smp)
|
2015-07-01 15:34:24 +02:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-07-01 15:34:24 +02:00
|
|
|
struct bt_keys *keys;
|
2015-10-28 10:46:51 +02:00
|
|
|
struct net_buf *buf;
|
2015-07-01 15:34:24 +02:00
|
|
|
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_get_addr(&conn->le.dst);
|
2015-07-01 15:34:24 +02:00
|
|
|
if (!keys) {
|
|
|
|
BT_ERR("Unable to look up keys for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&conn->le.dst));
|
2015-07-01 15:34:24 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-26 18:39:02 +02:00
|
|
|
/* Store key type deducted from pairing method used. It is important
|
|
|
|
* to restore it here since all key info is cleared after encryption
|
|
|
|
* was enabled before key distribution.
|
|
|
|
*
|
|
|
|
* All keys from pairing have same type so it is enough to store it
|
|
|
|
* on local distribution only.
|
|
|
|
*/
|
|
|
|
keys->type = get_keys_type(smp->method);
|
Bluetooth: SMP: Add support for encryption key size reduction
This allows to pair with devices that use reduced encryption key size.
Encryption key size is stored with keys for future use. LTKs are kept
in full form (16 bytes) and are reduced only when used.
As master:
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, No MITM, Legacy,
No Keypresses (0x01)
Max encryption key size: 16
Initiator key distribution: EncKey Sign (0x05)
Responder key distribution: EncKey IdKey Sign (0x07)
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
< HCI Command: LE Start Encryption (0x08|0x0019) plen 28
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
Long term key: df3cff52a981d6000000000000000000
As slave:
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 16
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
> HCI Event: LE Meta Event (0x3e) plen 13
LE Long Term Key Request (0x05)
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
< HCI Command: LE Long Term Key Request Reply (0x08|0x001a) plen 18
Handle: 64
Long term key: 701b431a9e17bb000000000000000000
Change-Id: Ibc70aa01c040aff0d39410d273d6880d35aa5ae0
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
2015-10-07 12:33:45 +02:00
|
|
|
keys->enc_size = get_encryption_key_size(smp);
|
2015-07-01 15:34:24 +02:00
|
|
|
|
2015-10-28 16:02:17 +01:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2015-07-01 15:34:24 +02:00
|
|
|
if (smp->local_dist & BT_SMP_DIST_ENC_KEY) {
|
|
|
|
struct bt_smp_encrypt_info *info;
|
|
|
|
struct bt_smp_master_ident *ident;
|
|
|
|
|
2015-09-24 17:22:40 +02:00
|
|
|
smp->local_dist &= ~BT_SMP_DIST_ENC_KEY;
|
|
|
|
|
2015-07-08 11:52:38 +02:00
|
|
|
bt_keys_add_type(keys, BT_KEYS_SLAVE_LTK);
|
|
|
|
|
2015-07-01 15:34:24 +02:00
|
|
|
le_rand(keys->slave_ltk.val, sizeof(keys->slave_ltk.val));
|
|
|
|
le_rand(&keys->slave_ltk.rand, sizeof(keys->slave_ltk.rand));
|
|
|
|
le_rand(&keys->slave_ltk.ediv, sizeof(keys->slave_ltk.ediv));
|
|
|
|
|
|
|
|
buf = bt_smp_create_pdu(conn, BT_SMP_CMD_ENCRYPT_INFO,
|
|
|
|
sizeof(*info));
|
|
|
|
if (!buf) {
|
|
|
|
BT_ERR("Unable to allocate Encrypt Info buffer\n");
|
2015-10-07 14:00:16 +02:00
|
|
|
return;
|
2015-07-01 15:34:24 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
info = net_buf_add(buf, sizeof(*info));
|
Bluetooth: SMP: Add support for encryption key size reduction
This allows to pair with devices that use reduced encryption key size.
Encryption key size is stored with keys for future use. LTKs are kept
in full form (16 bytes) and are reduced only when used.
As master:
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, No MITM, Legacy,
No Keypresses (0x01)
Max encryption key size: 16
Initiator key distribution: EncKey Sign (0x05)
Responder key distribution: EncKey IdKey Sign (0x07)
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
< HCI Command: LE Start Encryption (0x08|0x0019) plen 28
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
Long term key: df3cff52a981d6000000000000000000
As slave:
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 16
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
> HCI Event: LE Meta Event (0x3e) plen 13
LE Long Term Key Request (0x05)
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
< HCI Command: LE Long Term Key Request Reply (0x08|0x001a) plen 18
Handle: 64
Long term key: 701b431a9e17bb000000000000000000
Change-Id: Ibc70aa01c040aff0d39410d273d6880d35aa5ae0
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
2015-10-07 12:33:45 +02:00
|
|
|
|
|
|
|
/* distributed only enc_size bytes of key */
|
|
|
|
memcpy(info->ltk, keys->slave_ltk.val, keys->enc_size);
|
|
|
|
if (keys->enc_size < sizeof(info->ltk)) {
|
|
|
|
memset(info->ltk + keys->enc_size, 0,
|
|
|
|
sizeof(info->ltk) - keys->enc_size);
|
|
|
|
}
|
2015-07-01 15:34:24 +02:00
|
|
|
|
|
|
|
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, buf);
|
|
|
|
|
|
|
|
buf = bt_smp_create_pdu(conn, BT_SMP_CMD_MASTER_IDENT,
|
|
|
|
sizeof(*ident));
|
|
|
|
if (!buf) {
|
|
|
|
BT_ERR("Unable to allocate Master Ident buffer\n");
|
2015-10-07 14:00:16 +02:00
|
|
|
return;
|
2015-07-01 15:34:24 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
ident = net_buf_add(buf, sizeof(*ident));
|
2015-07-01 15:34:24 +02:00
|
|
|
ident->rand = keys->slave_ltk.rand;
|
|
|
|
ident->ediv = keys->slave_ltk.ediv;
|
|
|
|
|
|
|
|
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, buf);
|
2015-09-28 18:02:28 +02:00
|
|
|
|
|
|
|
smp_restart_timer(smp);
|
2015-07-01 15:34:24 +02:00
|
|
|
}
|
2015-07-28 15:08:06 +03:00
|
|
|
|
2015-09-08 14:10:31 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_SIGNING)
|
2015-07-28 15:08:06 +03:00
|
|
|
if (smp->local_dist & BT_SMP_DIST_SIGN) {
|
|
|
|
struct bt_smp_signing_info *info;
|
|
|
|
|
2015-09-24 17:22:40 +02:00
|
|
|
smp->local_dist &= ~BT_SMP_DIST_SIGN;
|
|
|
|
|
2015-07-28 15:08:06 +03:00
|
|
|
bt_keys_add_type(keys, BT_KEYS_LOCAL_CSRK);
|
|
|
|
|
|
|
|
le_rand(keys->local_csrk.val, sizeof(keys->local_csrk.val));
|
|
|
|
keys->local_csrk.cnt = 0;
|
|
|
|
|
|
|
|
buf = bt_smp_create_pdu(conn, BT_SMP_CMD_SIGNING_INFO,
|
|
|
|
sizeof(*info));
|
|
|
|
if (!buf) {
|
|
|
|
BT_ERR("Unable to allocate Signing Info buffer\n");
|
2015-10-07 14:00:16 +02:00
|
|
|
return;
|
2015-07-28 15:08:06 +03:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
info = net_buf_add(buf, sizeof(*info));
|
2015-07-28 15:08:06 +03:00
|
|
|
memcpy(info->csrk, keys->local_csrk.val, sizeof(info->csrk));
|
|
|
|
|
|
|
|
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, buf);
|
2015-09-28 18:02:28 +02:00
|
|
|
|
|
|
|
smp_restart_timer(smp);
|
2015-07-28 15:08:06 +03:00
|
|
|
}
|
2015-09-08 14:10:31 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_SIGNING */
|
2015-07-01 15:34:24 +02:00
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_encrypt_info(struct bt_smp *smp, struct net_buf *buf)
|
2015-06-29 23:25:48 +02:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-06-29 23:25:48 +02:00
|
|
|
struct bt_smp_encrypt_info *req = (void *)buf->data;
|
|
|
|
struct bt_keys *keys;
|
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_get_type(BT_KEYS_LTK, &conn->le.dst);
|
2015-06-29 23:25:48 +02:00
|
|
|
if (!keys) {
|
|
|
|
BT_ERR("Unable to get keys for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&conn->le.dst));
|
2015-06-29 23:25:48 +02:00
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(keys->ltk.val, req->ltk, 16);
|
|
|
|
|
2015-07-01 15:07:56 +02:00
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_MASTER_IDENT);
|
|
|
|
|
2015-06-29 23:25:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_master_ident(struct bt_smp *smp, struct net_buf *buf)
|
2015-06-29 23:53:12 +02:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-06-29 23:53:12 +02:00
|
|
|
struct bt_smp_master_ident *req = (void *)buf->data;
|
|
|
|
struct bt_keys *keys;
|
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_get_type(BT_KEYS_LTK, &conn->le.dst);
|
2015-06-29 23:53:12 +02:00
|
|
|
if (!keys) {
|
|
|
|
BT_ERR("Unable to get keys for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&conn->le.dst));
|
2015-06-29 23:53:12 +02:00
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
keys->ltk.ediv = req->ediv;
|
|
|
|
keys->ltk.rand = req->rand;
|
|
|
|
|
2015-08-27 13:15:31 +03:00
|
|
|
smp->remote_dist &= ~BT_SMP_DIST_ENC_KEY;
|
2015-07-01 15:07:56 +02:00
|
|
|
|
|
|
|
if (smp->remote_dist & BT_SMP_DIST_ID_KEY) {
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_IDENT_INFO);
|
2015-07-29 10:11:34 +03:00
|
|
|
} else if (smp->remote_dist & BT_SMP_DIST_SIGN) {
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_SIGNING_INFO);
|
2015-07-01 16:21:37 +02:00
|
|
|
}
|
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
2015-08-27 13:15:31 +03:00
|
|
|
if (conn->role == BT_HCI_ROLE_MASTER && !smp->remote_dist) {
|
2015-10-02 16:21:18 +03:00
|
|
|
bt_smp_distribute_keys(smp);
|
2015-08-27 13:15:31 +03:00
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
2015-08-27 13:15:31 +03:00
|
|
|
|
2015-10-07 14:00:16 +02:00
|
|
|
/* if all keys were distributed, pairing is done */
|
|
|
|
if (!smp->local_dist && !smp->remote_dist) {
|
2015-10-14 15:58:23 +02:00
|
|
|
smp_reset(smp);
|
2015-10-07 14:00:16 +02:00
|
|
|
}
|
|
|
|
|
2015-06-29 23:53:12 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_ident_info(struct bt_smp *smp, struct net_buf *buf)
|
2015-05-31 22:58:10 +07:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-05-31 22:58:10 +07:00
|
|
|
struct bt_smp_ident_info *req = (void *)buf->data;
|
|
|
|
struct bt_keys *keys;
|
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_get_type(BT_KEYS_IRK, &conn->le.dst);
|
2015-05-31 22:58:10 +07:00
|
|
|
if (!keys) {
|
2015-06-01 10:53:42 +03:00
|
|
|
BT_ERR("Unable to get keys for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&conn->le.dst));
|
2015-05-31 22:58:10 +07:00
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(keys->irk.val, req->irk, 16);
|
|
|
|
|
2015-07-01 15:07:56 +02:00
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_IDENT_ADDR_INFO);
|
|
|
|
|
2015-05-31 22:58:10 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_ident_addr_info(struct bt_smp *smp, struct net_buf *buf)
|
2015-05-31 22:58:10 +07:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-05-31 22:58:10 +07:00
|
|
|
struct bt_smp_ident_addr_info *req = (void *)buf->data;
|
2015-09-02 16:12:53 +02:00
|
|
|
const bt_addr_le_t *dst;
|
2015-05-31 22:58:10 +07:00
|
|
|
struct bt_keys *keys;
|
|
|
|
|
|
|
|
BT_DBG("identity %s\n", bt_addr_le_str(&req->addr));
|
|
|
|
|
|
|
|
if (!bt_addr_le_is_identity(&req->addr)) {
|
|
|
|
BT_ERR("Invalid identity %s for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&req->addr), bt_addr_le_str(&conn->le.dst));
|
2015-05-31 22:58:10 +07:00
|
|
|
return BT_SMP_ERR_INVALID_PARAMS;
|
|
|
|
}
|
|
|
|
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_get_type(BT_KEYS_IRK, &conn->le.dst);
|
2015-05-31 22:58:10 +07:00
|
|
|
if (!keys) {
|
2015-06-01 10:53:42 +03:00
|
|
|
BT_ERR("Unable to get keys for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&conn->le.dst));
|
2015-05-31 22:58:10 +07:00
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
2015-09-02 16:12:53 +02:00
|
|
|
/* We can't use conn->dst here as this might already contain identity
|
|
|
|
* address known from previous pairing. Since all keys are cleared on
|
|
|
|
* re-pairing we wouldn't store IRK distributed in new pairing.
|
|
|
|
*/
|
|
|
|
if (conn->role == BT_HCI_ROLE_MASTER) {
|
2015-11-03 12:19:01 +01:00
|
|
|
dst = &conn->le.resp_addr;
|
2015-09-02 16:12:53 +02:00
|
|
|
} else {
|
2015-11-03 12:19:01 +01:00
|
|
|
dst = &conn->le.init_addr;
|
2015-09-02 16:12:53 +02:00
|
|
|
}
|
2015-09-01 18:06:35 +02:00
|
|
|
|
2015-09-02 16:12:53 +02:00
|
|
|
if (bt_addr_le_is_rpa(dst)) {
|
|
|
|
/* always update last use RPA */
|
|
|
|
bt_addr_copy(&keys->irk.rpa, (bt_addr_t *)&dst->val);
|
|
|
|
|
|
|
|
/* Update connection address and notify about identity
|
|
|
|
* resolved only if connection wasn't already reported with
|
|
|
|
* identity address. This may happen if IRK was present before
|
|
|
|
* ie. due to re-pairing.
|
|
|
|
*/
|
2015-11-03 12:19:01 +01:00
|
|
|
if (!bt_addr_le_is_identity(&conn->le.dst)) {
|
2015-09-02 16:12:53 +02:00
|
|
|
bt_addr_le_copy(&keys->addr, &req->addr);
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_copy(&conn->le.dst, &req->addr);
|
2015-09-02 16:12:53 +02:00
|
|
|
|
|
|
|
bt_conn_identity_resolved(conn);
|
|
|
|
}
|
2015-05-31 22:58:10 +07:00
|
|
|
}
|
|
|
|
|
2015-08-27 13:15:31 +03:00
|
|
|
smp->remote_dist &= ~BT_SMP_DIST_ID_KEY;
|
2015-07-29 10:11:34 +03:00
|
|
|
|
|
|
|
if (smp->remote_dist & BT_SMP_DIST_SIGN) {
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_SIGNING_INFO);
|
2015-07-01 16:21:37 +02:00
|
|
|
}
|
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
2015-08-27 13:15:31 +03:00
|
|
|
if (conn->role == BT_HCI_ROLE_MASTER && !smp->remote_dist) {
|
2015-10-02 16:21:18 +03:00
|
|
|
bt_smp_distribute_keys(smp);
|
2015-08-27 13:15:31 +03:00
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
2015-08-27 13:15:31 +03:00
|
|
|
|
2015-10-07 14:00:16 +02:00
|
|
|
/* if all keys were distributed, pairing is done */
|
|
|
|
if (!smp->local_dist && !smp->remote_dist) {
|
2015-10-14 15:58:23 +02:00
|
|
|
smp_reset(smp);
|
2015-10-07 14:00:16 +02:00
|
|
|
}
|
|
|
|
|
2015-05-31 22:58:10 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-08 14:10:31 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_SIGNING)
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_signing_info(struct bt_smp *smp, struct net_buf *buf)
|
2015-07-28 16:11:55 +03:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-07-28 16:11:55 +03:00
|
|
|
struct bt_smp_signing_info *req = (void *)buf->data;
|
|
|
|
struct bt_keys *keys;
|
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_get_type(BT_KEYS_REMOTE_CSRK, &conn->le.dst);
|
2015-07-28 16:11:55 +03:00
|
|
|
if (!keys) {
|
|
|
|
BT_ERR("Unable to get keys for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&conn->le.dst));
|
2015-07-28 16:11:55 +03:00
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(keys->remote_csrk.val, req->csrk, sizeof(keys->remote_csrk.val));
|
|
|
|
|
2015-08-27 13:15:31 +03:00
|
|
|
smp->remote_dist &= ~BT_SMP_DIST_SIGN;
|
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
2015-08-27 13:15:31 +03:00
|
|
|
if (conn->role == BT_HCI_ROLE_MASTER && !smp->remote_dist) {
|
2015-10-02 16:21:18 +03:00
|
|
|
bt_smp_distribute_keys(smp);
|
2015-07-28 16:11:55 +03:00
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
2015-07-28 16:11:55 +03:00
|
|
|
|
2015-10-07 14:00:16 +02:00
|
|
|
/* if all keys were distributed, pairing is done */
|
|
|
|
if (!smp->local_dist && !smp->remote_dist) {
|
2015-10-14 15:58:23 +02:00
|
|
|
smp_reset(smp);
|
2015-10-07 14:00:16 +02:00
|
|
|
}
|
|
|
|
|
2015-07-28 16:11:55 +03:00
|
|
|
return 0;
|
|
|
|
}
|
2015-09-08 14:10:31 +02:00
|
|
|
#else
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_signing_info(struct bt_smp *smp, struct net_buf *buf)
|
2015-09-08 14:10:31 +02:00
|
|
|
{
|
|
|
|
return BT_SMP_ERR_CMD_NOTSUPP;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_SIGNING */
|
2015-07-28 16:11:55 +03:00
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_security_request(struct bt_smp *smp, struct net_buf *buf)
|
2015-06-30 11:47:25 +02:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_conn *conn = smp->chan.conn;
|
2015-06-30 11:47:25 +02:00
|
|
|
struct bt_smp_security_request *req = (void *)buf->data;
|
|
|
|
struct bt_keys *keys;
|
|
|
|
uint8_t auth;
|
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
if (sc_supported) {
|
|
|
|
auth = req->auth_req & BT_SMP_AUTH_MASK_SC;
|
|
|
|
} else {
|
|
|
|
auth = req->auth_req & BT_SMP_AUTH_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
keys = bt_keys_find(BT_KEYS_LTK_P256, &conn->le.dst);
|
2015-06-30 11:47:25 +02:00
|
|
|
if (!keys) {
|
2015-10-27 09:24:46 +01:00
|
|
|
keys = bt_keys_find(BT_KEYS_LTK, &conn->le.dst);
|
2015-06-30 11:47:25 +02:00
|
|
|
}
|
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
if (!keys) {
|
|
|
|
goto pair;
|
|
|
|
}
|
2015-08-17 19:12:50 +02:00
|
|
|
|
2015-08-26 17:26:28 +02:00
|
|
|
if ((auth & BT_SMP_AUTH_MITM) && keys->type != BT_KEYS_AUTHENTICATED) {
|
2015-08-17 19:12:50 +02:00
|
|
|
if (bt_smp_io_capa != BT_SMP_IO_NO_INPUT_OUTPUT) {
|
2015-10-15 11:52:59 +02:00
|
|
|
BT_INFO("New auth requirements: 0x%x, repairing\n",
|
|
|
|
auth);
|
2015-08-17 19:12:50 +02:00
|
|
|
goto pair;
|
|
|
|
}
|
|
|
|
|
2015-10-15 11:52:59 +02:00
|
|
|
BT_WARN("Unsupported auth requirements: 0x%x, repairing\n",
|
|
|
|
auth);
|
2015-06-30 11:47:25 +02:00
|
|
|
goto pair;
|
|
|
|
}
|
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
if ((auth & BT_SMP_AUTH_SC) && !(keys->keys & BT_KEYS_LTK_P256)) {
|
|
|
|
BT_INFO("New auth requirements: 0x%x, repairing\n", auth);
|
|
|
|
goto pair;
|
|
|
|
}
|
|
|
|
|
2015-07-15 14:04:52 +03:00
|
|
|
if (bt_conn_le_start_encryption(conn, keys->ltk.rand, keys->ltk.ediv,
|
Bluetooth: SMP: Add support for encryption key size reduction
This allows to pair with devices that use reduced encryption key size.
Encryption key size is stored with keys for future use. LTKs are kept
in full form (16 bytes) and are reduced only when used.
As master:
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: Bonding, No MITM, Legacy,
No Keypresses (0x01)
Max encryption key size: 16
Initiator key distribution: EncKey Sign (0x05)
Responder key distribution: EncKey IdKey Sign (0x07)
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
< HCI Command: LE Start Encryption (0x08|0x0019) plen 28
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
Long term key: df3cff52a981d6000000000000000000
As slave:
> ACL Data RX: Handle 64 flags 0x02 dlen 11
SMP: Pairing Request (0x01) len 6
IO capability: KeyboardDisplay (0x04)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 7
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
< ACL Data TX: Handle 64 flags 0x00 dlen 11
SMP: Pairing Response (0x02) len 6
IO capability: NoInputNoOutput (0x03)
OOB data: Authentication data not present (0x00)
Authentication requirement: No bonding, No MITM, Legacy,
No Keypresses (0x00)
Max encryption key size: 16
Initiator key distribution: <none> (0x00)
Responder key distribution: <none> (0x00)
...
> HCI Event: LE Meta Event (0x3e) plen 13
LE Long Term Key Request (0x05)
Handle: 64
Random number: 0x0000000000000000
Encrypted diversifier: 0x0000
< HCI Command: LE Long Term Key Request Reply (0x08|0x001a) plen 18
Handle: 64
Long term key: 701b431a9e17bb000000000000000000
Change-Id: Ibc70aa01c040aff0d39410d273d6880d35aa5ae0
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
2015-10-07 12:33:45 +02:00
|
|
|
keys->ltk.val, keys->enc_size) < 0) {
|
2015-06-30 11:47:25 +02:00
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
2015-10-13 11:41:25 +02:00
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_ENC_PENDING);
|
|
|
|
|
2015-06-30 11:47:25 +02:00
|
|
|
return 0;
|
|
|
|
pair:
|
2015-07-06 14:47:06 +02:00
|
|
|
if (bt_smp_send_pairing_req(conn) < 0) {
|
2015-06-30 11:47:25 +02:00
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#else
|
2015-10-28 10:46:51 +02:00
|
|
|
static uint8_t smp_security_request(struct bt_smp *smp, struct net_buf *buf)
|
2015-09-07 18:25:59 +02:00
|
|
|
{
|
|
|
|
return BT_SMP_ERR_CMD_NOTSUPP;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
2015-06-30 11:47:25 +02:00
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
static uint8_t smp_public_key(struct bt_smp *smp, struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_smp_public_key *req = (void *)buf->data;
|
2015-11-12 11:27:52 +01:00
|
|
|
struct bt_hci_cp_le_generate_dhkey *cp;
|
2015-10-27 09:24:46 +01:00
|
|
|
uint8_t err;
|
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
|
|
|
memcpy(smp->pkey, req->x, 32);
|
|
|
|
memcpy(&smp->pkey[32], req->y, 32);
|
|
|
|
|
|
|
|
if (smp->chan.conn->role == BT_HCI_ROLE_MASTER) {
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_CONFIRM);
|
|
|
|
} else {
|
|
|
|
err = sc_send_public_key(smp);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_RANDOM);
|
|
|
|
|
|
|
|
err = smp_send_pairing_confirm(smp);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-12 11:27:52 +01:00
|
|
|
buf = bt_hci_cmd_create(BT_HCI_OP_LE_GENERATE_DHKEY, sizeof(*cp));
|
|
|
|
if (!buf) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = net_buf_add(buf, sizeof(*cp));
|
|
|
|
memcpy(cp->key, smp->pkey, sizeof(cp->key));
|
|
|
|
|
|
|
|
if (bt_hci_cmd_send_sync(BT_HCI_OP_LE_GENERATE_DHKEY, buf, NULL)) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_DHKEY_PENDING);
|
2015-10-27 09:24:46 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-12 11:31:40 +01:00
|
|
|
static uint8_t smp_dhkey_check(struct bt_smp *smp, struct net_buf *buf)
|
|
|
|
{
|
|
|
|
struct bt_smp_dhkey_check *req = (void *)buf->data;
|
|
|
|
struct bt_keys *keys;
|
|
|
|
uint8_t e[16], r[16];
|
|
|
|
|
|
|
|
BT_DBG("\n");
|
|
|
|
|
|
|
|
keys = bt_keys_get_addr(&smp->chan.conn->le.dst);
|
|
|
|
if (!keys) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO currently only NumComparison/JustWorks */
|
|
|
|
memset(r, 0, sizeof(r));
|
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
|
|
|
if (smp->chan.conn->role == BT_HCI_ROLE_MASTER) {
|
|
|
|
/* calculate remote DHKey check for comparison */
|
|
|
|
if (smp_f6(smp->mackey, smp->rrnd, smp->prnd, r, &smp->prsp[1],
|
|
|
|
&smp->chan.conn->le.resp_addr,
|
|
|
|
&smp->chan.conn->le.init_addr, e)) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memcmp(e, req->e, 16)) {
|
|
|
|
return BT_SMP_ERR_DHKEY_CHECK_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* store key type deducted from pairing method used
|
|
|
|
* it is important to store it since type is used to determine
|
|
|
|
* security level upon encryption
|
|
|
|
*/
|
|
|
|
keys->type = get_keys_type(smp->method);
|
|
|
|
keys->enc_size = get_encryption_key_size(smp);
|
|
|
|
|
|
|
|
if (bt_conn_le_start_encryption(smp->chan.conn, 0, 0, smp->tk,
|
|
|
|
keys->enc_size) < 0) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_ENC_PENDING);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
|
|
|
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
|
|
|
|
if (smp->chan.conn->role == BT_HCI_ROLE_SLAVE) {
|
|
|
|
uint8_t re[16];
|
|
|
|
|
|
|
|
/* wait for DHKey being generated */
|
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_DHKEY_PENDING)) {
|
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_DHKEY_SEND);
|
|
|
|
memcpy(smp->e, req->e, sizeof(smp->e));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate mac, ltk and local dhcheck */
|
|
|
|
smp_sc_calculate_ltk_mac_dhcheck(smp, e);
|
|
|
|
|
|
|
|
/* calculate remote DHKey check */
|
|
|
|
if (smp_f6(smp->mackey, smp->rrnd, smp->prnd, r, &smp->preq[1],
|
|
|
|
&smp->chan.conn->le.init_addr,
|
|
|
|
&smp->chan.conn->le.resp_addr, re)) {
|
|
|
|
return BT_SMP_ERR_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compare received E with calculated remote */
|
|
|
|
if (memcmp(req->e, re, 16)) {
|
|
|
|
return BT_SMP_ERR_DHKEY_CHECK_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* store key type deducted from pairing method used
|
|
|
|
* it is important to store it since type is used to determine
|
|
|
|
* security level upon encryption
|
|
|
|
*/
|
|
|
|
keys->type = get_keys_type(smp->method);
|
|
|
|
keys->enc_size = get_encryption_key_size(smp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* this is safe since LE SC is mutually exclusive with legacy
|
|
|
|
* pairing
|
|
|
|
*/
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* send local e */
|
|
|
|
sc_smp_send_dhkey_check(smp, e);
|
|
|
|
|
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_ENC_PENDING);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-02 12:33:09 +07:00
|
|
|
static const struct {
|
2015-10-28 10:46:51 +02:00
|
|
|
uint8_t (*func)(struct bt_smp *smp, struct net_buf *buf);
|
2015-06-02 12:33:09 +07:00
|
|
|
uint8_t expect_len;
|
|
|
|
} handlers[] = {
|
|
|
|
{ }, /* No op-code defined for 0x00 */
|
|
|
|
{ smp_pairing_req, sizeof(struct bt_smp_pairing) },
|
2015-06-24 16:52:19 +02:00
|
|
|
{ smp_pairing_rsp, sizeof(struct bt_smp_pairing) },
|
2015-06-02 12:33:09 +07:00
|
|
|
{ smp_pairing_confirm, sizeof(struct bt_smp_pairing_confirm) },
|
|
|
|
{ smp_pairing_random, sizeof(struct bt_smp_pairing_random) },
|
2015-07-01 21:10:18 +02:00
|
|
|
{ smp_pairing_failed, sizeof(struct bt_smp_pairing_fail) },
|
2015-07-08 10:08:07 +03:00
|
|
|
{ smp_encrypt_info, sizeof(struct bt_smp_encrypt_info) },
|
|
|
|
{ smp_master_ident, sizeof(struct bt_smp_master_ident) },
|
2015-06-02 12:33:09 +07:00
|
|
|
{ smp_ident_info, sizeof(struct bt_smp_ident_info) },
|
|
|
|
{ smp_ident_addr_info, sizeof(struct bt_smp_ident_addr_info) },
|
2015-07-28 16:11:55 +03:00
|
|
|
{ smp_signing_info, sizeof(struct bt_smp_signing_info) },
|
2015-06-30 11:47:25 +02:00
|
|
|
{ smp_security_request, sizeof(struct bt_smp_security_request) },
|
2015-10-27 09:24:46 +01:00
|
|
|
{ smp_public_key, sizeof(struct bt_smp_public_key) },
|
2015-11-12 11:31:40 +01:00
|
|
|
{ smp_dhkey_check, sizeof(struct bt_smp_dhkey_check) },
|
2015-06-02 12:33:09 +07:00
|
|
|
};
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
static void bt_smp_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
|
2015-05-06 12:16:45 +03:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_smp *smp = CONTAINER_OF(chan, struct bt_smp, chan);
|
2015-05-06 12:16:45 +03:00
|
|
|
struct bt_smp_hdr *hdr = (void *)buf->data;
|
2015-06-02 12:33:09 +07:00
|
|
|
uint8_t err;
|
2015-05-06 12:16:45 +03:00
|
|
|
|
|
|
|
if (buf->len < sizeof(*hdr)) {
|
|
|
|
BT_ERR("Too small SMP PDU received\n");
|
2015-11-02 16:11:15 +02:00
|
|
|
return;
|
2015-05-06 12:16:45 +03:00
|
|
|
}
|
|
|
|
|
2015-05-21 15:58:32 +03:00
|
|
|
BT_DBG("Received SMP code 0x%02x len %u\n", hdr->code, buf->len);
|
2015-05-06 12:16:45 +03:00
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
net_buf_pull(buf, sizeof(*hdr));
|
2015-05-06 12:16:45 +03:00
|
|
|
|
2015-09-28 18:02:28 +02:00
|
|
|
/*
|
|
|
|
* If SMP timeout occurred "no further SMP commands shall be sent over
|
|
|
|
* the L2CAP Security Manager Channel. A new SM procedure shall only be
|
|
|
|
* performed when a new physical link has been established."
|
|
|
|
*/
|
|
|
|
if (atomic_test_bit(&smp->flags, SMP_FLAG_TIMEOUT)) {
|
|
|
|
BT_WARN("SMP command (code 0x%02x) received after timeout\n",
|
|
|
|
hdr->code);
|
2015-11-02 16:11:15 +02:00
|
|
|
return;
|
2015-09-28 18:02:28 +02:00
|
|
|
}
|
|
|
|
|
2015-06-02 12:33:09 +07:00
|
|
|
if (hdr->code >= ARRAY_SIZE(handlers) || !handlers[hdr->code].func) {
|
2015-05-21 15:58:32 +03:00
|
|
|
BT_WARN("Unhandled SMP code 0x%02x\n", hdr->code);
|
2015-05-07 14:53:02 +03:00
|
|
|
err = BT_SMP_ERR_CMD_NOTSUPP;
|
2015-06-02 12:33:09 +07:00
|
|
|
} else {
|
2015-07-01 15:07:56 +02:00
|
|
|
if (!atomic_test_and_clear_bit(&smp->allowed_cmds, hdr->code)) {
|
|
|
|
BT_WARN("Unexpected SMP code 0x%02x\n", hdr->code);
|
2015-11-02 16:11:15 +02:00
|
|
|
return;
|
2015-07-01 15:07:56 +02:00
|
|
|
}
|
|
|
|
|
2015-06-02 12:33:09 +07:00
|
|
|
if (buf->len != handlers[hdr->code].expect_len) {
|
|
|
|
BT_ERR("Invalid len %u for code 0x%02x\n", buf->len,
|
|
|
|
hdr->code);
|
|
|
|
err = BT_SMP_ERR_INVALID_PARAMS;
|
|
|
|
} else {
|
2015-10-02 16:21:18 +03:00
|
|
|
err = handlers[hdr->code].func(smp, buf);
|
2015-06-02 12:33:09 +07:00
|
|
|
}
|
2015-05-06 12:16:45 +03:00
|
|
|
}
|
|
|
|
|
2015-05-07 14:53:02 +03:00
|
|
|
if (err) {
|
2015-10-02 16:21:18 +03:00
|
|
|
send_err_rsp(chan->conn, err);
|
2015-07-01 15:07:56 +02:00
|
|
|
|
2015-10-14 15:58:23 +02:00
|
|
|
smp_reset(smp);
|
2015-05-07 14:53:02 +03:00
|
|
|
}
|
2015-05-06 12:16:45 +03:00
|
|
|
}
|
2015-05-21 18:53:13 +03:00
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
static void bt_smp_connected(struct bt_l2cap_chan *chan)
|
2015-05-21 20:43:42 +03:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_smp *smp = CONTAINER_OF(chan, struct bt_smp, chan);
|
2015-07-01 15:07:56 +02:00
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
BT_DBG("chan %p cid 0x%04x\n", chan, chan->tx.cid);
|
2015-07-01 15:07:56 +02:00
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
smp_reset(smp);
|
2015-05-21 20:43:42 +03:00
|
|
|
}
|
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
static void bt_smp_disconnected(struct bt_l2cap_chan *chan)
|
2015-05-21 20:43:42 +03:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_smp *smp = CONTAINER_OF(chan, struct bt_smp, chan);
|
2015-05-21 20:43:42 +03:00
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
BT_DBG("chan %p cid 0x%04x\n", chan, chan->tx.cid);
|
2015-09-28 18:02:28 +02:00
|
|
|
|
2015-10-12 14:22:09 +02:00
|
|
|
if (smp->timeout) {
|
|
|
|
fiber_fiber_delayed_start_cancel(smp->timeout);
|
|
|
|
}
|
|
|
|
|
2015-05-21 20:43:42 +03:00
|
|
|
memset(smp, 0, sizeof(*smp));
|
|
|
|
}
|
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
static void bt_smp_encrypt_change(struct bt_l2cap_chan *chan)
|
2015-05-22 13:57:56 +03:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_smp *smp = CONTAINER_OF(chan, struct bt_smp, chan);
|
|
|
|
struct bt_conn *conn = chan->conn;
|
2015-08-26 18:39:02 +02:00
|
|
|
struct bt_keys *keys;
|
2015-05-22 13:57:56 +03:00
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
BT_DBG("chan %p conn %p handle %u encrypt 0x%02x\n", chan, conn,
|
|
|
|
conn->handle, conn->encrypt);
|
2015-05-22 13:57:56 +03:00
|
|
|
|
|
|
|
if (!smp || !conn->encrypt) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-25 11:20:24 +02:00
|
|
|
if (!atomic_test_and_clear_bit(&smp->flags, SMP_FLAG_ENC_PENDING)) {
|
2015-06-01 00:15:42 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-13 11:41:25 +02:00
|
|
|
/* We were waiting for encryption but with no pairing in progress.
|
|
|
|
* This can happen if paired slave sent Security Request and we
|
|
|
|
* enabled encryption.
|
|
|
|
*
|
|
|
|
* Since it is possible that slave might sent another Security Request
|
|
|
|
* eg with different AuthReq we should allow it.
|
|
|
|
*/
|
|
|
|
if (!atomic_test_bit(&smp->flags, SMP_FLAG_PAIRING)) {
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_SECURITY_REQUEST);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-07-01 15:07:56 +02:00
|
|
|
if (smp->remote_dist & BT_SMP_DIST_ENC_KEY) {
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_ENCRYPT_INFO);
|
|
|
|
} else if (smp->remote_dist & BT_SMP_DIST_ID_KEY) {
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_IDENT_INFO);
|
2015-07-29 10:11:34 +03:00
|
|
|
} else if (smp->remote_dist & BT_SMP_DIST_SIGN) {
|
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_SIGNING_INFO);
|
2015-07-01 15:07:56 +02:00
|
|
|
}
|
|
|
|
|
2015-08-26 18:39:02 +02:00
|
|
|
/* If link was successfully encrypted cleanup old keys as from now on
|
|
|
|
* only keys distributed in this pairing will be used. This includes
|
|
|
|
* STK as it will be replaced by LTK.
|
|
|
|
*/
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_find_addr(&conn->le.dst);
|
2015-08-26 18:39:02 +02:00
|
|
|
if (keys) {
|
|
|
|
bt_keys_clear(keys, BT_KEYS_ALL);
|
|
|
|
}
|
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
2015-07-01 16:21:37 +02:00
|
|
|
/* Slave distributes it's keys first */
|
|
|
|
if (conn->role == BT_HCI_ROLE_MASTER && smp->remote_dist) {
|
|
|
|
return;
|
|
|
|
}
|
2015-09-07 18:25:59 +02:00
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
2015-07-01 16:21:37 +02:00
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
bt_smp_distribute_keys(smp);
|
2015-10-07 14:00:16 +02:00
|
|
|
|
|
|
|
/* if all keys were distributed, pairing is done */
|
|
|
|
if (!smp->local_dist && !smp->remote_dist) {
|
2015-10-14 15:58:23 +02:00
|
|
|
smp_reset(smp);
|
2015-10-07 14:00:16 +02:00
|
|
|
}
|
2015-05-22 13:57:56 +03:00
|
|
|
}
|
|
|
|
|
2015-06-01 00:18:44 +07:00
|
|
|
bool bt_smp_irk_matches(const uint8_t irk[16], const bt_addr_t *addr)
|
|
|
|
{
|
|
|
|
uint8_t hash[3];
|
|
|
|
int err;
|
|
|
|
|
2015-06-05 12:26:23 +02:00
|
|
|
BT_DBG("IRK %s bdaddr %s", h(irk, 16), bt_addr_str(addr));
|
2015-06-01 00:18:44 +07:00
|
|
|
|
|
|
|
err = smp_ah(irk, addr->val + 3, hash);
|
|
|
|
if (err) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return !memcmp(addr->val, hash, 3);
|
|
|
|
}
|
|
|
|
|
2015-09-08 14:10:31 +02:00
|
|
|
#if defined(CONFIG_BLUETOOTH_SIGNING)
|
2015-07-09 15:01:30 +03:00
|
|
|
/* Sign message using msg as a buffer, len is a size of the message,
|
|
|
|
* msg buffer contains message itself, 32 bit count and signature,
|
|
|
|
* so total buffer size is len + 4 + 8 octets.
|
|
|
|
* API is Little Endian to make it suitable for Bluetooth.
|
|
|
|
*/
|
|
|
|
static int smp_sign_buf(const uint8_t *key, uint8_t *msg, uint16_t len)
|
|
|
|
{
|
|
|
|
uint8_t *m = msg;
|
|
|
|
uint32_t cnt = UNALIGNED_GET((uint32_t *)&msg[len]);
|
|
|
|
uint8_t *sig = msg + len;
|
|
|
|
uint8_t key_s[16], tmp[16];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
BT_DBG("Signing msg %s len %u key %s\n", h(msg, len), len, h(key, 16));
|
|
|
|
|
|
|
|
swap_in_place(m, len + sizeof(cnt));
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(key_s, key, 16);
|
2015-07-09 15:01:30 +03:00
|
|
|
|
|
|
|
err = bt_smp_aes_cmac(key_s, m, len + sizeof(cnt), tmp);
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("Data signing failed\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
swap_in_place(tmp, sizeof(tmp));
|
|
|
|
memcpy(tmp + 4, &cnt, sizeof(cnt));
|
|
|
|
|
|
|
|
/* Swap original message back */
|
|
|
|
swap_in_place(m, len + sizeof(cnt));
|
|
|
|
|
|
|
|
memcpy(sig, tmp + 4, 12);
|
|
|
|
|
|
|
|
BT_DBG("sig %s\n", h(sig, 12));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
int bt_smp_sign_verify(struct bt_conn *conn, struct net_buf *buf)
|
2015-07-15 17:06:35 +03:00
|
|
|
{
|
|
|
|
struct bt_keys *keys;
|
|
|
|
uint8_t sig[12];
|
|
|
|
uint32_t cnt;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* Store signature incl. count */
|
2015-10-28 10:46:51 +02:00
|
|
|
memcpy(sig, net_buf_tail(buf) - sizeof(sig), sizeof(sig));
|
2015-07-15 17:06:35 +03:00
|
|
|
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_get_type(BT_KEYS_REMOTE_CSRK, &conn->le.dst);
|
2015-07-15 17:06:35 +03:00
|
|
|
if (!keys) {
|
|
|
|
BT_ERR("Unable to get keys for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&conn->le.dst));
|
2015-07-15 17:06:35 +03:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy signing count */
|
|
|
|
cnt = sys_cpu_to_le32(keys->remote_csrk.cnt);
|
2015-10-28 10:46:51 +02:00
|
|
|
memcpy(net_buf_tail(buf) - sizeof(sig), &cnt, sizeof(cnt));
|
2015-07-15 17:06:35 +03:00
|
|
|
|
|
|
|
BT_DBG("Sign data len %u key %s count %u\n", buf->len - sizeof(sig),
|
2015-08-14 11:12:14 +03:00
|
|
|
h(keys->remote_csrk.val, 16), keys->remote_csrk.cnt);
|
2015-07-15 17:06:35 +03:00
|
|
|
|
|
|
|
err = smp_sign_buf(keys->remote_csrk.val, buf->data,
|
|
|
|
buf->len - sizeof(sig));
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("Unable to create signature for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&conn->le.dst));
|
2015-07-15 17:06:35 +03:00
|
|
|
return -EIO;
|
|
|
|
};
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
if (memcmp(sig, net_buf_tail(buf) - sizeof(sig), sizeof(sig))) {
|
2015-07-15 17:06:35 +03:00
|
|
|
BT_ERR("Unable to verify signature for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&conn->le.dst));
|
2015-07-15 17:06:35 +03:00
|
|
|
return -EBADMSG;
|
|
|
|
};
|
|
|
|
|
2015-08-14 11:10:46 +03:00
|
|
|
keys->remote_csrk.cnt++;
|
|
|
|
|
2015-07-30 13:56:04 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
int bt_smp_sign(struct bt_conn *conn, struct net_buf *buf)
|
2015-07-30 13:56:04 +03:00
|
|
|
{
|
|
|
|
struct bt_keys *keys;
|
|
|
|
uint32_t cnt;
|
|
|
|
int err;
|
|
|
|
|
2015-11-03 12:19:01 +01:00
|
|
|
keys = bt_keys_get_type(BT_KEYS_LOCAL_CSRK, &conn->le.dst);
|
2015-07-30 13:56:04 +03:00
|
|
|
if (!keys) {
|
|
|
|
BT_ERR("Unable to get keys for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&conn->le.dst));
|
2015-07-30 13:56:04 +03:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reserve space for data signature */
|
2015-10-28 10:46:51 +02:00
|
|
|
net_buf_add(buf, 12);
|
2015-07-30 13:56:04 +03:00
|
|
|
|
|
|
|
/* Copy signing count */
|
|
|
|
cnt = sys_cpu_to_le32(keys->local_csrk.cnt);
|
2015-10-28 10:46:51 +02:00
|
|
|
memcpy(net_buf_tail(buf) - 12, &cnt, sizeof(cnt));
|
2015-07-30 13:56:04 +03:00
|
|
|
|
|
|
|
BT_DBG("Sign data len %u key %s count %u\n", buf->len,
|
|
|
|
h(keys->local_csrk.val, 16), keys->local_csrk.cnt);
|
|
|
|
|
|
|
|
err = smp_sign_buf(keys->local_csrk.val, buf->data, buf->len - 12);
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("Unable to create signature for %s\n",
|
2015-11-03 12:19:01 +01:00
|
|
|
bt_addr_le_str(&conn->le.dst));
|
2015-07-30 13:56:04 +03:00
|
|
|
return -EIO;
|
|
|
|
};
|
|
|
|
|
|
|
|
keys->local_csrk.cnt++;
|
|
|
|
|
2015-07-15 17:06:35 +03:00
|
|
|
return 0;
|
|
|
|
}
|
2015-09-08 14:10:31 +02:00
|
|
|
#else
|
2015-10-28 10:46:51 +02:00
|
|
|
int bt_smp_sign_verify(struct bt_conn *conn, struct net_buf *buf)
|
2015-09-08 14:10:31 +02:00
|
|
|
{
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:46:51 +02:00
|
|
|
int bt_smp_sign(struct bt_conn *conn, struct net_buf *buf)
|
2015-09-08 14:10:31 +02:00
|
|
|
{
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_BLUETOOTH_SIGNING */
|
2015-07-15 17:06:35 +03:00
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_SMP_SELFTEST)
|
2015-07-07 16:04:51 +03:00
|
|
|
/* Test vectors are taken from RFC 4493
|
|
|
|
* https://tools.ietf.org/html/rfc4493
|
|
|
|
* Same mentioned in the Bluetooth Spec.
|
|
|
|
*/
|
|
|
|
static const uint8_t key[] = {
|
|
|
|
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
|
|
|
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
|
|
|
|
};
|
|
|
|
|
|
|
|
static const uint8_t M[] = {
|
|
|
|
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
|
|
|
|
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
|
|
|
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
|
|
|
|
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
|
|
|
|
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
|
|
|
|
0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
|
|
|
|
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
|
|
|
|
0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
|
|
|
|
};
|
|
|
|
|
|
|
|
static int aes_test(const char *prefix, const uint8_t *key, const uint8_t *m,
|
|
|
|
uint16_t len, const uint8_t *mac)
|
|
|
|
{
|
|
|
|
uint8_t out[16];
|
|
|
|
|
|
|
|
BT_DBG("%s: AES CMAC of message with len %u\n", prefix, len);
|
|
|
|
|
|
|
|
bt_smp_aes_cmac(key, m, len, out);
|
|
|
|
if (!memcmp(out, mac, 16)) {
|
|
|
|
BT_DBG("%s: Success\n", prefix);
|
|
|
|
} else {
|
|
|
|
BT_ERR("%s: Failed\n", prefix);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int smp_aes_cmac_test(void)
|
|
|
|
{
|
|
|
|
uint8_t mac1[] = {
|
|
|
|
0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
|
|
|
|
0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46
|
|
|
|
};
|
|
|
|
uint8_t mac2[] = {
|
|
|
|
0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
|
|
|
|
0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c
|
|
|
|
};
|
|
|
|
uint8_t mac3[] = {
|
|
|
|
0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
|
|
|
|
0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27
|
|
|
|
};
|
|
|
|
uint8_t mac4[] = {
|
|
|
|
0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
|
|
|
|
0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe
|
|
|
|
};
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = aes_test("Test aes-cmac0", key, M, 0, mac1);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = aes_test("Test aes-cmac16", key, M, 16, mac2);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = aes_test("Test aes-cmac40", key, M, 40, mac3);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = aes_test("Test aes-cmac64", key, M, 64, mac4);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-09 15:01:30 +03:00
|
|
|
static int sign_test(const char *prefix, const uint8_t *key, const uint8_t *m,
|
|
|
|
uint16_t len, const uint8_t *sig)
|
|
|
|
{
|
|
|
|
uint8_t msg[len + sizeof(uint32_t) + 8];
|
|
|
|
uint8_t orig[len + sizeof(uint32_t) + 8];
|
|
|
|
uint8_t *out = msg + len;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
BT_DBG("%s: Sign message with len %u\n", prefix, len);
|
|
|
|
|
|
|
|
memset(msg, 0, sizeof(msg));
|
|
|
|
memcpy(msg, m, len);
|
|
|
|
memset(msg + len, 0, sizeof(uint32_t));
|
|
|
|
|
|
|
|
memcpy(orig, msg, sizeof(msg));
|
|
|
|
|
|
|
|
err = smp_sign_buf(key, msg, len);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check original message */
|
|
|
|
if (!memcmp(msg, orig, len + sizeof(uint32_t))) {
|
|
|
|
BT_DBG("%s: Original message intact\n", prefix);
|
|
|
|
} else {
|
|
|
|
BT_ERR("%s: Original message modified\n", prefix);
|
|
|
|
BT_DBG("%s: orig %s\n", prefix, h(orig, sizeof(orig)));
|
|
|
|
BT_DBG("%s: msg %s\n", prefix, h(msg, sizeof(msg)));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!memcmp(out, sig, 12)) {
|
|
|
|
BT_DBG("%s: Success\n", prefix);
|
|
|
|
} else {
|
|
|
|
BT_ERR("%s: Failed\n", prefix);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int smp_sign_test(void)
|
|
|
|
{
|
|
|
|
const uint8_t sig1[] = {
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0xb3, 0xa8, 0x59, 0x41,
|
|
|
|
0x27, 0xeb, 0xc2, 0xc0
|
|
|
|
};
|
|
|
|
const uint8_t sig2[] = {
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x27, 0x39, 0x74, 0xf4,
|
|
|
|
0x39, 0x2a, 0x23, 0x2a
|
|
|
|
};
|
|
|
|
const uint8_t sig3[] = {
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0xb7, 0xca, 0x94, 0xab,
|
|
|
|
0x87, 0xc7, 0x82, 0x18
|
|
|
|
};
|
|
|
|
const uint8_t sig4[] = {
|
|
|
|
0x00, 0x00, 0x00, 0x00, 0x44, 0xe1, 0xe6, 0xce,
|
|
|
|
0x1d, 0xf5, 0x13, 0x68
|
|
|
|
};
|
|
|
|
uint8_t key_s[16];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* Use the same key as aes-cmac but swap bytes */
|
2015-11-17 12:53:41 +01:00
|
|
|
swap_buf(key_s, key, 16);
|
2015-07-09 15:01:30 +03:00
|
|
|
|
|
|
|
err = sign_test("Test sign0", key_s, M, 0, sig1);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = sign_test("Test sign16", key_s, M, 16, sig2);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = sign_test("Test sign40", key_s, M, 40, sig3);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = sign_test("Test sign64", key_s, M, 64, sig4);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-29 16:32:29 +01:00
|
|
|
static int smp_f4_test(void)
|
|
|
|
{
|
|
|
|
uint8_t u[32] = { 0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
|
|
|
|
0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
|
|
|
|
0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
|
|
|
|
0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20 };
|
|
|
|
uint8_t v[32] = { 0xfd, 0xc5, 0x7f, 0xf4, 0x49, 0xdd, 0x4f, 0x6b,
|
|
|
|
0xfb, 0x7c, 0x9d, 0xf1, 0xc2, 0x9a, 0xcb, 0x59,
|
|
|
|
0x2a, 0xe7, 0xd4, 0xee, 0xfb, 0xfc, 0x0a, 0x90,
|
|
|
|
0x9a, 0xbb, 0xf6, 0x32, 0x3d, 0x8b, 0x18, 0x55 };
|
|
|
|
uint8_t x[16] = { 0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff,
|
|
|
|
0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 };
|
|
|
|
uint8_t z = 0x00;
|
|
|
|
uint8_t exp[16] = { 0x2d, 0x87, 0x74, 0xa9, 0xbe, 0xa1, 0xed, 0xf1,
|
|
|
|
0x1c, 0xbd, 0xa9, 0x07, 0xf1, 0x16, 0xc9, 0xf2 };
|
|
|
|
uint8_t res[16];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = smp_f4(u, v, x, z, res);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memcmp(res, exp, 16)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-09 10:14:43 +01:00
|
|
|
static int smp_f5_test(void)
|
|
|
|
{
|
|
|
|
uint8_t w[32] = { 0x98, 0xa6, 0xbf, 0x73, 0xf3, 0x34, 0x8d, 0x86,
|
|
|
|
0xf1, 0x66, 0xf8, 0xb4, 0x13, 0x6b, 0x79, 0x99,
|
|
|
|
0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,
|
|
|
|
0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec };
|
|
|
|
uint8_t n1[16] = { 0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff,
|
|
|
|
0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 };
|
|
|
|
uint8_t n2[16] = { 0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21,
|
|
|
|
0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 };
|
|
|
|
bt_addr_le_t a1 = { .type = 0x00,
|
|
|
|
.val = { 0xce, 0xbf, 0x37, 0x37, 0x12, 0x56 } };
|
|
|
|
bt_addr_le_t a2 = { .type = 0x00,
|
|
|
|
.val = {0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7 } };
|
|
|
|
uint8_t exp_ltk[16] = { 0x38, 0x0a, 0x75, 0x94, 0xb5, 0x22, 0x05,
|
|
|
|
0x98, 0x23, 0xcd, 0xd7, 0x69, 0x11, 0x79,
|
|
|
|
0x86, 0x69 };
|
|
|
|
uint8_t exp_mackey[16] = { 0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f,
|
|
|
|
0xfd, 0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1,
|
|
|
|
0x65, 0x29 };
|
|
|
|
uint8_t mackey[16], ltk[16];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = smp_f5(w, n1, n2, &a1, &a2, mackey, ltk);
|
|
|
|
if (err) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memcmp(mackey, exp_mackey, 16) || memcmp(ltk, exp_ltk, 16)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-10 08:45:28 +01:00
|
|
|
static int smp_f6_test(void)
|
|
|
|
{
|
|
|
|
uint8_t w[16] = { 0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd,
|
|
|
|
0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29 };
|
|
|
|
uint8_t n1[16] = { 0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff,
|
|
|
|
0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 };
|
|
|
|
uint8_t n2[16] = { 0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21,
|
|
|
|
0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 };
|
|
|
|
uint8_t r[16] = { 0xc8, 0x0f, 0x2d, 0x0c, 0xd2, 0x42, 0xda, 0x08,
|
|
|
|
0x54, 0xbb, 0x53, 0xb4, 0x3b, 0x34, 0xa3, 0x12 };
|
|
|
|
uint8_t io_cap[3] = { 0x02, 0x01, 0x01 };
|
|
|
|
bt_addr_le_t a1 = { .type = 0x00,
|
|
|
|
.val = { 0xce, 0xbf, 0x37, 0x37, 0x12, 0x56 } };
|
|
|
|
bt_addr_le_t a2 = { .type = 0x00,
|
|
|
|
.val = {0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7 } };
|
|
|
|
uint8_t exp[16] = { 0x61, 0x8f, 0x95, 0xda, 0x09, 0x0b, 0x6c, 0xd2,
|
|
|
|
0xc5, 0xe8, 0xd0, 0x9c, 0x98, 0x73, 0xc4, 0xe3 };
|
|
|
|
uint8_t res[16];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = smp_f6(w, n1, n2, r, io_cap, &a1, &a2, res);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
if (memcmp(res, exp, 16))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-07 16:04:51 +03:00
|
|
|
static int smp_self_test(void)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = smp_aes_cmac_test();
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("SMP AES-CMAC self tests failed\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-07-09 15:01:30 +03:00
|
|
|
err = smp_sign_test();
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("SMP signing self tests failed\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-10-29 16:32:29 +01:00
|
|
|
err = smp_f4_test();
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("SMP f4 self test failed\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-11-09 10:14:43 +01:00
|
|
|
err = smp_f5_test();
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("SMP f5 self test failed\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-11-10 08:45:28 +01:00
|
|
|
err = smp_f6_test();
|
|
|
|
if (err) {
|
|
|
|
BT_ERR("SMP f6 self test failed\n");
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-07-07 16:04:51 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static inline int smp_self_test(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-08-05 16:18:13 +02:00
|
|
|
static uint8_t get_io_capa(const struct bt_auth_cb *cb)
|
2015-08-05 16:18:13 +02:00
|
|
|
{
|
2015-10-12 17:03:10 +02:00
|
|
|
if (cb->passkey_display && cb->passkey_entry) {
|
2015-08-17 09:16:51 +02:00
|
|
|
return BT_SMP_IO_KEYBOARD_DISPLAY;
|
|
|
|
}
|
|
|
|
|
2015-10-12 17:03:10 +02:00
|
|
|
if (cb->passkey_entry) {
|
2015-08-17 09:16:51 +02:00
|
|
|
return BT_SMP_IO_KEYBOARD_ONLY;
|
|
|
|
}
|
|
|
|
|
2015-10-12 17:03:10 +02:00
|
|
|
if (cb->passkey_display) {
|
2015-08-05 16:18:13 +02:00
|
|
|
return BT_SMP_IO_DISPLAY_ONLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return BT_SMP_IO_NO_INPUT_OUTPUT;
|
|
|
|
}
|
2015-08-05 16:18:13 +02:00
|
|
|
|
2015-08-05 16:18:13 +02:00
|
|
|
int bt_auth_cb_register(const struct bt_auth_cb *cb)
|
|
|
|
{
|
|
|
|
if (!cb) {
|
2015-08-05 16:18:13 +02:00
|
|
|
bt_smp_io_capa = BT_SMP_IO_NO_INPUT_OUTPUT;
|
2015-08-05 16:18:13 +02:00
|
|
|
auth_cb = NULL;
|
|
|
|
return 0;
|
2015-08-05 16:18:13 +02:00
|
|
|
}
|
|
|
|
|
2015-08-05 16:18:13 +02:00
|
|
|
/* cancel callback should always be provided */
|
|
|
|
if (!cb->cancel) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auth_cb) {
|
|
|
|
return -EALREADY;
|
2015-08-05 16:18:13 +02:00
|
|
|
}
|
|
|
|
|
2015-08-05 16:18:13 +02:00
|
|
|
bt_smp_io_capa = get_io_capa(cb);
|
|
|
|
auth_cb = cb;
|
|
|
|
|
|
|
|
return 0;
|
2015-08-05 16:18:13 +02:00
|
|
|
}
|
|
|
|
|
2015-08-17 09:16:51 +02:00
|
|
|
void bt_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey)
|
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_smp *smp;
|
|
|
|
|
|
|
|
smp = smp_chan_get(conn);
|
|
|
|
if (!smp) {
|
|
|
|
return;
|
|
|
|
}
|
2015-08-17 09:16:51 +02:00
|
|
|
|
|
|
|
passkey = sys_cpu_to_le32(passkey);
|
|
|
|
memcpy(smp->tk, &passkey, sizeof(passkey));
|
2015-08-17 17:29:48 +02:00
|
|
|
atomic_set_bit(&smp->flags, SMP_FLAG_TK_VALID);
|
|
|
|
|
|
|
|
if (!atomic_test_and_clear_bit(&smp->flags, SMP_FLAG_CFM_DELAYED)) {
|
|
|
|
return;
|
|
|
|
}
|
2015-08-17 09:16:51 +02:00
|
|
|
|
|
|
|
/* if confirm failed ie. due to invalid passkey, cancel pairing */
|
2015-10-02 16:21:18 +03:00
|
|
|
if (smp_send_pairing_confirm(smp)) {
|
2015-08-17 09:16:51 +02:00
|
|
|
bt_auth_cancel(conn);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-07 18:25:59 +02:00
|
|
|
switch(conn->role) {
|
|
|
|
#if defined(CONFIG_BLUETOOTH_CENTRAL)
|
|
|
|
case BT_HCI_ROLE_MASTER:
|
2015-08-17 09:16:51 +02:00
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_CONFIRM);
|
2015-09-07 18:25:59 +02:00
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_CENTRAL */
|
|
|
|
|
|
|
|
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
|
|
|
|
case BT_HCI_ROLE_SLAVE:
|
2015-08-17 09:16:51 +02:00
|
|
|
atomic_set_bit(&smp->allowed_cmds, BT_SMP_CMD_PAIRING_RANDOM);
|
2015-09-07 18:25:59 +02:00
|
|
|
break;
|
|
|
|
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
|
|
|
|
default:
|
|
|
|
break;
|
2015-08-17 09:16:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-05 16:18:13 +02:00
|
|
|
void bt_auth_cancel(struct bt_conn *conn)
|
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
struct bt_smp *smp;
|
|
|
|
|
|
|
|
smp = smp_chan_get(conn);
|
|
|
|
if (!smp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-05 16:18:13 +02:00
|
|
|
send_err_rsp(conn, BT_SMP_ERR_PASSKEY_ENTRY_FAILED);
|
2015-10-02 16:21:18 +03:00
|
|
|
|
|
|
|
smp_reset(smp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bt_smp_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
static struct bt_l2cap_chan_ops ops = {
|
|
|
|
.connected = bt_smp_connected,
|
|
|
|
.disconnected = bt_smp_disconnected,
|
|
|
|
.encrypt_change = bt_smp_encrypt_change,
|
|
|
|
.recv = bt_smp_recv,
|
|
|
|
};
|
|
|
|
|
|
|
|
BT_DBG("conn %p handle %u\n", conn, conn->handle);
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(bt_smp_pool); i++) {
|
|
|
|
struct bt_smp *smp = &bt_smp_pool[i];
|
|
|
|
|
|
|
|
if (smp->chan.conn) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
smp->chan.ops = &ops;
|
|
|
|
|
|
|
|
*chan = &smp->chan;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
BT_ERR("No available SMP context for conn %p\n", conn);
|
|
|
|
|
|
|
|
return -ENOMEM;
|
2015-08-05 16:18:13 +02:00
|
|
|
}
|
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
/* TODO check tinycrypt define when ECC is added */
|
|
|
|
#if defined(CONFIG_TINYCRYPT_ECC)
|
|
|
|
static bool le_sc_supported(void)
|
|
|
|
{
|
|
|
|
/* TODO */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static bool le_sc_supported(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If controller based ECC is to be used it must support
|
|
|
|
* "LE Read Local P-256 Public Key" and "LE Generate DH Key" commands.
|
|
|
|
* Otherwise LE SC are not supported.
|
|
|
|
*/
|
|
|
|
return (bt_dev.supported_commands[34] & 0x02) &&
|
|
|
|
(bt_dev.supported_commands[34] & 0x04);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-07-07 16:04:51 +03:00
|
|
|
int bt_smp_init(void)
|
2015-05-21 18:53:13 +03:00
|
|
|
{
|
2015-10-02 16:21:18 +03:00
|
|
|
static struct bt_l2cap_fixed_chan chan = {
|
2015-05-21 18:53:13 +03:00
|
|
|
.cid = BT_L2CAP_CID_SMP,
|
2015-10-02 16:21:18 +03:00
|
|
|
.accept = bt_smp_accept,
|
2015-05-21 18:53:13 +03:00
|
|
|
};
|
|
|
|
|
2015-11-05 21:01:20 +02:00
|
|
|
net_buf_pool_init(smp_pool);
|
|
|
|
|
2015-10-02 16:21:18 +03:00
|
|
|
bt_l2cap_fixed_chan_register(&chan);
|
2015-07-07 16:04:51 +03:00
|
|
|
|
2015-10-27 09:24:46 +01:00
|
|
|
sc_supported = le_sc_supported();
|
|
|
|
|
|
|
|
BT_DBG("LE SC %s\n", sc_supported ? "enabled" : "disabled");
|
|
|
|
|
2015-07-07 16:04:51 +03:00
|
|
|
return smp_self_test();
|
2015-05-21 18:53:13 +03:00
|
|
|
}
|