Commit f730cc9f authored by David S. Miller's avatar David S. Miller

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Johan Hedberg says:

====================
pull request: bluetooth-next 2017-10-19

Here's the first bluetooth-next pull request targeting the 4.15 kernel
release.

 - Multiple fixes & improvements to the hci_bcm driver
 - DT improvements, e.g. new local-bd-address property
 - Fixes & improvements to ECDH usage. Private key is now generated by
   the crypto subsystem.
 - gcc-4.9 warning fixes

Please let me know if there are any issues pulling. Thanks.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 164a5e7a fac72b24
The following properties are common to the Bluetooth controllers:
- local-bd-address: array of 6 bytes, specifies the BD address that was
uniquely assigned to the Bluetooth device, formatted with least significant
byte first (little-endian).
......@@ -37,6 +37,11 @@ The following properties are defined to the bluetooth node:
Definition: must be:
"qcom,wcnss-bt"
- local-bd-address:
Usage: optional
Value type: <u8 array>
Definition: see Documentation/devicetree/bindings/net/bluetooth.txt
== WiFi
The following properties are defined to the WiFi node:
......@@ -91,6 +96,9 @@ smd {
bt {
compatible = "qcom,wcnss-bt";
/* BD address 00:11:22:33:44:55 */
local-bd-address = [ 55 44 33 22 11 00 ];
};
wlan {
......
......@@ -65,6 +65,7 @@ config BT_HCIBTSDIO
config BT_HCIUART
tristate "HCI UART driver"
depends on SERIAL_DEV_BUS || !SERIAL_DEV_BUS
depends on TTY
help
Bluetooth HCI UART driver.
......@@ -79,7 +80,6 @@ config BT_HCIUART
config BT_HCIUART_SERDEV
bool
depends on SERIAL_DEV_BUS && BT_HCIUART
depends on SERIAL_DEV_BUS=y || SERIAL_DEV_BUS=BT_HCIUART
default y
config BT_HCIUART_H4
......@@ -169,6 +169,7 @@ config BT_HCIUART_BCM
bool "Broadcom protocol support"
depends on BT_HCIUART
depends on BT_HCIUART_SERDEV
depends on (!ACPI || SERIAL_DEV_CTRL_TTYPORT)
select BT_HCIUART_H4
select BT_BCM
help
......
......@@ -121,7 +121,7 @@ static void bcm203x_complete(struct urb *urb)
}
data->state = BCM203X_LOAD_FIRMWARE;
/* fall through */
case BCM203X_LOAD_FIRMWARE:
if (data->fw_sent == data->fw_size) {
usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP),
......
......@@ -156,9 +156,9 @@ static void bluecard_detach(struct pcmcia_device *p_dev);
/* ======================== LED handling routines ======================== */
static void bluecard_activity_led_timeout(u_long arg)
static void bluecard_activity_led_timeout(struct timer_list *t)
{
struct bluecard_info *info = (struct bluecard_info *)arg;
struct bluecard_info *info = from_timer(info, t, timer);
unsigned int iobase = info->p_dev->resource[0]->start;
if (test_bit(CARD_ACTIVITY, &(info->hw_state))) {
......@@ -691,8 +691,7 @@ static int bluecard_open(struct bluecard_info *info)
spin_lock_init(&(info->lock));
setup_timer(&(info->timer), &bluecard_activity_led_timeout,
(u_long)info);
timer_setup(&info->timer, bluecard_activity_led_timeout, 0);
skb_queue_head_init(&(info->txq));
......
......@@ -327,6 +327,8 @@ static const struct {
{ 0x4406, "BCM4324B3" }, /* 002.004.006 */
{ 0x610c, "BCM4354" }, /* 003.001.012 */
{ 0x2209, "BCM43430A1" }, /* 001.002.009 */
{ 0x6119, "BCM4345C0" }, /* 003.001.025 */
{ 0x230f, "BCM4356A2" }, /* 001.003.015 */
{ }
};
......@@ -361,6 +363,7 @@ int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len)
switch ((rev & 0xf000) >> 12) {
case 0:
case 1:
case 2:
case 3:
for (i = 0; bcm_uart_subver_table[i].name; i++) {
if (subver == bcm_uart_subver_table[i].subver) {
......
......@@ -64,7 +64,7 @@ static irqreturn_t btmrvl_wake_irq_bt(int irq, void *priv)
struct btmrvl_sdio_card *card = priv;
struct btmrvl_plt_wake_cfg *cfg = card->plt_wake_cfg;
pr_info("%s: wake by bt", __func__);
pr_info("%s: wake by bt\n", __func__);
cfg->wake_by_bt = true;
disable_irq_nosync(irq);
......@@ -87,7 +87,7 @@ static int btmrvl_sdio_probe_of(struct device *dev,
if (!dev->of_node ||
!of_match_node(btmrvl_sdio_of_match_table, dev->of_node)) {
pr_err("sdio platform data not available");
pr_err("sdio platform data not available\n");
return -1;
}
......@@ -99,7 +99,7 @@ static int btmrvl_sdio_probe_of(struct device *dev,
if (cfg && card->plt_of_node) {
cfg->irq_bt = irq_of_parse_and_map(card->plt_of_node, 0);
if (!cfg->irq_bt) {
dev_err(dev, "fail to parse irq_bt from device tree");
dev_err(dev, "fail to parse irq_bt from device tree\n");
cfg->irq_bt = -1;
} else {
ret = devm_request_irq(dev, cfg->irq_bt,
......
......@@ -15,6 +15,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/rpmsg.h>
#include <linux/of.h>
#include <linux/soc/qcom/wcnss_ctrl.h>
#include <linux/platform_device.h>
......@@ -26,6 +28,7 @@
struct btqcomsmd {
struct hci_dev *hdev;
bdaddr_t bdaddr;
struct rpmsg_endpoint *acl_channel;
struct rpmsg_endpoint *cmd_channel;
};
......@@ -100,6 +103,38 @@ static int btqcomsmd_close(struct hci_dev *hdev)
return 0;
}
static int btqcomsmd_setup(struct hci_dev *hdev)
{
struct btqcomsmd *btq = hci_get_drvdata(hdev);
struct sk_buff *skb;
int err;
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb))
return PTR_ERR(skb);
kfree_skb(skb);
/* Devices do not have persistent storage for BD address. If no
* BD address has been retrieved during probe, mark the device
* as having an invalid BD address.
*/
if (!bacmp(&btq->bdaddr, BDADDR_ANY)) {
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
return 0;
}
/* When setting a configured BD address fails, mark the device
* as having an invalid BD address.
*/
err = qca_set_bdaddr_rome(hdev, &btq->bdaddr);
if (err) {
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
return 0;
}
return 0;
}
static int btqcomsmd_probe(struct platform_device *pdev)
{
struct btqcomsmd *btq;
......@@ -123,6 +158,15 @@ static int btqcomsmd_probe(struct platform_device *pdev)
if (IS_ERR(btq->cmd_channel))
return PTR_ERR(btq->cmd_channel);
/* The local-bd-address property is usually injected by the
* bootloader which has access to the allocated BD address.
*/
if (!of_property_read_u8_array(pdev->dev.of_node, "local-bd-address",
(u8 *)&btq->bdaddr, sizeof(bdaddr_t))) {
dev_info(&pdev->dev, "BD address %pMR retrieved from device-tree",
&btq->bdaddr);
}
hdev = hci_alloc_dev();
if (!hdev)
return -ENOMEM;
......@@ -135,6 +179,7 @@ static int btqcomsmd_probe(struct platform_device *pdev)
hdev->open = btqcomsmd_open;
hdev->close = btqcomsmd_close;
hdev->send = btqcomsmd_send;
hdev->setup = btqcomsmd_setup;
hdev->set_bdaddr = qca_set_bdaddr_rome;
ret = hci_register_dev(hdev);
......
......@@ -66,7 +66,6 @@ static struct usb_driver btusb_driver;
#define BTUSB_BCM2045 0x40000
#define BTUSB_IFNUM_2 0x80000
#define BTUSB_CW6622 0x100000
#define BTUSB_BCM_NO_PRODID 0x200000
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
......@@ -171,10 +170,6 @@ static const struct usb_device_id btusb_table[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(0x0930, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_PATCHRAM },
/* Broadcom devices with missing product id */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0000, 0x0000, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_PATCHRAM | BTUSB_BCM_NO_PRODID },
/* Intel Bluetooth USB Bootloader (RAM module) */
{ USB_DEVICE(0x8087, 0x0a5a),
.driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC },
......@@ -2909,19 +2904,6 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info == BTUSB_IGNORE)
return -ENODEV;
if (id->driver_info & BTUSB_BCM_NO_PRODID) {
struct usb_device *udev = interface_to_usbdev(intf);
/* For the broken Broadcom devices that show 0000:0000
* as USB vendor and product information, check that the
* manufacturer string identifies them as Broadcom based
* devices.
*/
if (!udev->manufacturer ||
strcmp(udev->manufacturer, "Broadcom Corp"))
return -ENODEV;
}
if (id->driver_info & BTUSB_ATH3012) {
struct usb_device *udev = interface_to_usbdev(intf);
......
This diff is collapsed.
......@@ -65,6 +65,7 @@ struct bcsp_struct {
u8 rxseq_txack; /* rxseq == txack. */
u8 rxack; /* Last packet sent by us that the peer ack'ed */
struct timer_list tbcsp;
struct hci_uart *hu;
enum {
BCSP_W4_PKT_DELIMITER,
......@@ -697,10 +698,10 @@ static int bcsp_recv(struct hci_uart *hu, const void *data, int count)
}
/* Arrange to retransmit all messages in the relq. */
static void bcsp_timed_event(unsigned long arg)
static void bcsp_timed_event(struct timer_list *t)
{
struct hci_uart *hu = (struct hci_uart *)arg;
struct bcsp_struct *bcsp = hu->priv;
struct bcsp_struct *bcsp = from_timer(bcsp, t, tbcsp);
struct hci_uart *hu = bcsp->hu;
struct sk_buff *skb;
unsigned long flags;
......@@ -729,11 +730,12 @@ static int bcsp_open(struct hci_uart *hu)
return -ENOMEM;
hu->priv = bcsp;
bcsp->hu = hu;
skb_queue_head_init(&bcsp->unack);
skb_queue_head_init(&bcsp->rel);
skb_queue_head_init(&bcsp->unrel);
setup_timer(&bcsp->tbcsp, bcsp_timed_event, (u_long)hu);
timer_setup(&bcsp->tbcsp, bcsp_timed_event, 0);
bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
......
......@@ -78,6 +78,7 @@ struct h5 {
int (*rx_func)(struct hci_uart *hu, u8 c);
struct timer_list timer; /* Retransmission timer */
struct hci_uart *hu; /* Parent HCI UART */
u8 tx_seq; /* Next seq number to send */
u8 tx_ack; /* Next ack number to send */
......@@ -120,12 +121,12 @@ static u8 h5_cfg_field(struct h5 *h5)
return h5->tx_win & 0x07;
}
static void h5_timed_event(unsigned long arg)
static void h5_timed_event(struct timer_list *t)
{
const unsigned char sync_req[] = { 0x01, 0x7e };
unsigned char conf_req[3] = { 0x03, 0xfc };
struct hci_uart *hu = (struct hci_uart *)arg;
struct h5 *h5 = hu->priv;
struct h5 *h5 = from_timer(h5, t, timer);
struct hci_uart *hu = h5->hu;
struct sk_buff *skb;
unsigned long flags;
......@@ -197,6 +198,7 @@ static int h5_open(struct hci_uart *hu)
return -ENOMEM;
hu->priv = h5;
h5->hu = hu;
skb_queue_head_init(&h5->unack);
skb_queue_head_init(&h5->rel);
......@@ -204,7 +206,7 @@ static int h5_open(struct hci_uart *hu)
h5_reset_rx(h5);
setup_timer(&h5->timer, h5_timed_event, (unsigned long)hu);
timer_setup(&h5->timer, h5_timed_event, 0);
h5->tx_win = H5_TX_WIN_MAX;
......
......@@ -41,6 +41,7 @@
#include <linux/ioctl.h>
#include <linux/skbuff.h>
#include <linux/firmware.h>
#include <linux/serdev.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
......@@ -298,6 +299,12 @@ void hci_uart_set_flow_control(struct hci_uart *hu, bool enable)
unsigned int set = 0;
unsigned int clear = 0;
if (hu->serdev) {
serdev_device_set_flow_control(hu->serdev, !enable);
serdev_device_set_rts(hu->serdev, !enable);
return;
}
if (enable) {
/* Disable hardware flow control */
ktermios = tty->termios;
......
......@@ -242,7 +242,7 @@ static void ll_device_want_to_wakeup(struct hci_uart *hu)
* perfectly safe to always send one.
*/
BT_DBG("dual wake-up-indication");
/* deliberate fall-through - do not add break */
/* fall through */
case HCILL_ASLEEP:
/* acknowledge device wake up */
if (send_hcill_cmd(HCILL_WAKE_UP_ACK, hu) < 0) {
......
......@@ -307,10 +307,10 @@ static void qca_wq_serial_tx_clock_vote_off(struct work_struct *work)
serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
}
static void hci_ibs_tx_idle_timeout(unsigned long arg)
static void hci_ibs_tx_idle_timeout(struct timer_list *t)
{
struct hci_uart *hu = (struct hci_uart *)arg;
struct qca_data *qca = hu->priv;
struct qca_data *qca = from_timer(qca, t, tx_idle_timer);
struct hci_uart *hu = qca->hu;
unsigned long flags;
BT_DBG("hu %p idle timeout in %d state", hu, qca->tx_ibs_state);
......@@ -342,10 +342,10 @@ static void hci_ibs_tx_idle_timeout(unsigned long arg)
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
}
static void hci_ibs_wake_retrans_timeout(unsigned long arg)
static void hci_ibs_wake_retrans_timeout(struct timer_list *t)
{
struct hci_uart *hu = (struct hci_uart *)arg;
struct qca_data *qca = hu->priv;
struct qca_data *qca = from_timer(qca, t, wake_retrans_timer);
struct hci_uart *hu = qca->hu;
unsigned long flags, retrans_delay;
bool retransmit = false;
......@@ -438,11 +438,10 @@ static int qca_open(struct hci_uart *hu)
hu->priv = qca;
setup_timer(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout,
(u_long)hu);
timer_setup(&qca->wake_retrans_timer, hci_ibs_wake_retrans_timeout, 0);
qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
setup_timer(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, (u_long)hu);
timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
......
......@@ -1944,7 +1944,7 @@ static int ca8210_skb_tx(
)
{
int status;
struct ieee802154_hdr header = { 0 };
struct ieee802154_hdr header = { };
struct secspec secspec;
unsigned int mac_len;
......
......@@ -23,7 +23,6 @@
#include "ecdh_helper.h"
#include <linux/scatterlist.h>
#include <crypto/kpp.h>
#include <crypto/ecdh.h>
struct ecdh_completion {
......@@ -50,55 +49,35 @@ static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits)
out[i] = __swab64(in[ndigits - 1 - i]);
}
bool compute_ecdh_secret(const u8 public_key[64], const u8 private_key[32],
u8 secret[32])
/* compute_ecdh_secret() - function assumes that the private key was
* already set.
* @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
* @public_key: pair's ecc public key.
* secret: memory where the ecdh computed shared secret will be saved.
*
* Return: zero on success; error code in case of error.
*/
int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64],
u8 secret[32])
{
struct crypto_kpp *tfm;
struct kpp_request *req;
struct ecdh p;
u8 *tmp;
struct ecdh_completion result;
struct scatterlist src, dst;
u8 *tmp, *buf;
unsigned int buf_len;
int err = -ENOMEM;
int err;
tmp = kmalloc(64, GFP_KERNEL);
if (!tmp)
return false;
return -ENOMEM;
tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
if (IS_ERR(tfm)) {
pr_err("alg: kpp: Failed to load tfm for kpp: %ld\n",
PTR_ERR(tfm));
req = kpp_request_alloc(tfm, GFP_KERNEL);
if (!req) {
err = -ENOMEM;
goto free_tmp;
}
req = kpp_request_alloc(tfm, GFP_KERNEL);
if (!req)
goto free_kpp;
init_completion(&result.completion);
/* Security Manager Protocol holds digits in litte-endian order
* while ECC API expect big-endian data
*/
swap_digits((u64 *)private_key, (u64 *)tmp, 4);
p.key = (char *)tmp;
p.key_size = 32;
/* Set curve_id */
p.curve_id = ECC_CURVE_NIST_P256;
buf_len = crypto_ecdh_key_len(&p);
buf = kmalloc(buf_len, GFP_KERNEL);
if (!buf)
goto free_req;
crypto_ecdh_encode_key(buf, buf_len, &p);
/* Set A private Key */
err = crypto_kpp_set_secret(tfm, (void *)buf, buf_len);
if (err)
goto free_all;
swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */
swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */
......@@ -123,104 +102,129 @@ bool compute_ecdh_secret(const u8 public_key[64], const u8 private_key[32],
memcpy(secret, tmp, 32);
free_all:
kzfree(buf);
free_req:
kpp_request_free(req);
free_kpp:
crypto_free_kpp(tfm);
free_tmp:
kfree(tmp);
return (err == 0);
kzfree(tmp);
return err;
}
bool generate_ecdh_keys(u8 public_key[64], u8 private_key[32])
/* set_ecdh_privkey() - set or generate ecc private key.
*
* Function generates an ecc private key in the crypto subsystem when receiving
* a NULL private key or sets the received key when not NULL.
*
* @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
* @private_key: user's ecc private key. When not NULL, the key is expected
* in little endian format.
*
* Return: zero on success; error code in case of error.
*/
int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 private_key[32])
{
u8 *buf, *tmp = NULL;
unsigned int buf_len;
int err;
struct ecdh p = {0};
p.curve_id = ECC_CURVE_NIST_P256;
if (private_key) {
tmp = kmalloc(32, GFP_KERNEL);
if (!tmp)
return -ENOMEM;
swap_digits((u64 *)private_key, (u64 *)tmp, 4);
p.key = tmp;
p.key_size = 32;
}
buf_len = crypto_ecdh_key_len(&p);
buf = kmalloc(buf_len, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto free_tmp;
}
err = crypto_ecdh_encode_key(buf, buf_len, &p);
if (err)
goto free_all;
err = crypto_kpp_set_secret(tfm, buf, buf_len);
/* fall through */
free_all:
kzfree(buf);
free_tmp:
kzfree(tmp);
return err;
}
/* generate_ecdh_public_key() - function assumes that the private key was
* already set.
*
* @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
* @public_key: memory where the computed ecc public key will be saved.
*
* Return: zero on success; error code in case of error.
*/
int generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64])
{
struct crypto_kpp *tfm;
struct kpp_request *req;
struct ecdh p;
u8 *tmp;
struct ecdh_completion result;
struct scatterlist dst;
u8 *tmp, *buf;
unsigned int buf_len;
int err = -ENOMEM;
const unsigned short max_tries = 16;
unsigned short tries = 0;
int err;
tmp = kmalloc(64, GFP_KERNEL);
if (!tmp)
return false;
return -ENOMEM;
tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
if (IS_ERR(tfm)) {
pr_err("alg: kpp: Failed to load tfm for kpp: %ld\n",
PTR_ERR(tfm));
req = kpp_request_alloc(tfm, GFP_KERNEL);
if (!req) {
err = -ENOMEM;
goto free_tmp;
}
req = kpp_request_alloc(tfm, GFP_KERNEL);
if (!req)
goto free_kpp;
init_completion(&result.completion);
sg_init_one(&dst, tmp, 64);
kpp_request_set_input(req, NULL, 0);
kpp_request_set_output(req, &dst, 64);
kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
ecdh_complete, &result);
/* Set curve_id */
p.curve_id = ECC_CURVE_NIST_P256;
p.key_size = 32;
buf_len = crypto_ecdh_key_len(&p);
buf = kmalloc(buf_len, GFP_KERNEL);
if (!buf)
goto free_req;
do {
if (tries++ >= max_tries)
goto free_all;
/* Set private Key */
p.key = (char *)private_key;
crypto_ecdh_encode_key(buf, buf_len, &p);
err = crypto_kpp_set_secret(tfm, buf, buf_len);
if (err)
goto free_all;
sg_init_one(&dst, tmp, 64);
kpp_request_set_input(req, NULL, 0);
kpp_request_set_output(req, &dst, 64);
kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
ecdh_complete, &result);
err = crypto_kpp_generate_public_key(req);
if (err == -EINPROGRESS) {
wait_for_completion(&result.completion);
err = result.err;
}
/* Private key is not valid. Regenerate */
if (err == -EINVAL)
continue;
if (err < 0)
goto free_all;
else
break;
} while (true);
/* Keys are handed back in little endian as expected by Security
* Manager Protocol
err = crypto_kpp_generate_public_key(req);
if (err == -EINPROGRESS) {
wait_for_completion(&result.completion);
err = result.err;
}
if (err < 0)
goto free_all;
/* The public key is handed back in little endian as expected by
* the Security Manager Protocol.
*/
swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */
swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */
swap_digits((u64 *)private_key, (u64 *)tmp, 4);
memcpy(private_key, tmp, 32);
free_all:
kzfree(buf);
free_req:
kpp_request_free(req);
free_kpp:
crypto_free_kpp(tfm);
free_tmp:
kfree(tmp);
return (err == 0);
return err;
}
/* generate_ecdh_keys() - generate ecc key pair.
*
* @tfm: KPP tfm handle allocated with crypto_alloc_kpp().
* @public_key: memory where the computed ecc public key will be saved.
*
* Return: zero on success; error code in case of error.
*/
int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64])
{
int err;
err = set_ecdh_privkey(tfm, NULL);
if (err)
return err;
return generate_ecdh_public_key(tfm, public_key);
}
......@@ -20,8 +20,11 @@
* COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
* SOFTWARE IS DISCLAIMED.
*/
#include <crypto/kpp.h>
#include <linux/types.h>
bool compute_ecdh_secret(const u8 pub_a[64], const u8 priv_b[32],
u8 secret[32]);
bool generate_ecdh_keys(u8 public_key[64], u8 private_key[32]);
int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 pair_public_key[64],
u8 secret[32]);
int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 *private_key);
int generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64]);
int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64]);
......@@ -138,12 +138,12 @@ static const u8 dhkey_3[32] __initconst = {
0x7c, 0x1c, 0xf9, 0x49, 0xe6, 0xd7, 0xaa, 0x70,
};
static int __init test_ecdh_sample(const u8 priv_a[32], const u8 priv_b[32],
const u8 pub_a[64], const u8 pub_b[64],
const u8 dhkey[32])
static int __init test_ecdh_sample(struct crypto_kpp *tfm, const u8 priv_a[32],
const u8 priv_b[32], const u8 pub_a[64],
const u8 pub_b[64], const u8 dhkey[32])
{
u8 *tmp, *dhkey_a, *dhkey_b;
int ret = 0;
int ret;
tmp = kmalloc(64, GFP_KERNEL);
if (!tmp)
......@@ -152,17 +152,30 @@ static int __init test_ecdh_sample(const u8 priv_a[32], const u8 priv_b[32],
dhkey_a = &tmp[0];
dhkey_b = &tmp[32];
compute_ecdh_secret(pub_b, priv_a, dhkey_a);
compute_ecdh_secret(pub_a, priv_b, dhkey_b);
ret = set_ecdh_privkey(tfm, priv_a);
if (ret)
goto out;
ret = compute_ecdh_secret(tfm, pub_b, dhkey_a);
if (ret)
goto out;
if (memcmp(dhkey_a, dhkey, 32)) {
ret = -EINVAL;
goto out;
}
ret = set_ecdh_privkey(tfm, priv_b);
if (ret)
goto out;
ret = compute_ecdh_secret(tfm, pub_a, dhkey_b);
if (ret)
goto out;
if (memcmp(dhkey_b, dhkey, 32))
ret = -EINVAL;
/* fall through*/
out:
kfree(tmp);
return ret;
......@@ -185,30 +198,43 @@ static const struct file_operations test_ecdh_fops = {
static int __init test_ecdh(void)
{
struct crypto_kpp *tfm;
ktime_t calltime, delta, rettime;
unsigned long long duration;
unsigned long long duration = 0;
int err;
calltime = ktime_get();
err = test_ecdh_sample(priv_a_1, priv_b_1, pub_a_1, pub_b_1, dhkey_1);
tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
if (IS_ERR(tfm)) {
BT_ERR("Unable to create ECDH crypto context");
err = PTR_ERR(tfm);
goto done;
}
err = test_ecdh_sample(tfm, priv_a_1, priv_b_1, pub_a_1, pub_b_1,
dhkey_1);
if (err) {
BT_ERR("ECDH sample 1 failed");
goto done;
}
err = test_ecdh_sample(priv_a_2, priv_b_2, pub_a_2, pub_b_2, dhkey_2);
err = test_ecdh_sample(tfm, priv_a_2, priv_b_2, pub_a_2, pub_b_2,
dhkey_2);
if (err) {
BT_ERR("ECDH sample 2 failed");
goto done;
}
err = test_ecdh_sample(priv_a_3, priv_a_3, pub_a_3, pub_a_3, dhkey_3);
err = test_ecdh_sample(tfm, priv_a_3, priv_a_3, pub_a_3, pub_a_3,
dhkey_3);
if (err) {
BT_ERR("ECDH sample 3 failed");
goto done;
}
crypto_free_kpp(tfm);
rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
duration = (unsigned long long) ktime_to_ns(delta) >> 10;
......
......@@ -26,6 +26,7 @@
#include <crypto/algapi.h>
#include <crypto/b128ops.h>
#include <crypto/hash.h>
#include <crypto/kpp.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
......@@ -83,7 +84,6 @@ enum {
struct smp_dev {
/* Secure Connections OOB data */
u8 local_pk[64];
u8 local_sk[32];
u8 local_rand[16];
bool debug_key;
......@@ -92,6 +92,7 @@ struct smp_dev {
struct crypto_cipher *tfm_aes;
struct crypto_shash *tfm_cmac;
struct crypto_kpp *tfm_ecdh;
};
struct smp_chan {
......@@ -124,13 +125,13 @@ struct smp_chan {
/* Secure Connections variables */
u8 local_pk[64];
u8 local_sk[32];
u8 remote_pk[64];
u8 dhkey[32];
u8 mackey[16];
struct crypto_cipher *tfm_aes;
struct crypto_shash *tfm_cmac;
struct crypto_kpp *tfm_ecdh;
};
/* These debug key values are defined in the SMP section of the core
......@@ -565,22 +566,22 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16])
if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) {
BT_DBG("Using debug keys");
err = set_ecdh_privkey(smp->tfm_ecdh, debug_sk);
if (err)
return err;
memcpy(smp->local_pk, debug_pk, 64);
memcpy(smp->local_sk, debug_sk, 32);
smp->debug_key = true;
} else {
while (true) {
/* Seed private key with random number */
get_random_bytes(smp->local_sk, 32);
/* Generate local key pair for Secure Connections */
if (!generate_ecdh_keys(smp->local_pk, smp->local_sk))
return -EIO;
/* Generate key pair for Secure Connections */
err = generate_ecdh_keys(smp->tfm_ecdh, smp->local_pk);
if (err)
return err;
/* This is unlikely, but we need to check that
* we didn't accidentially generate a debug key.
*/
if (crypto_memneq(smp->local_sk, debug_sk, 32))
if (crypto_memneq(smp->local_pk, debug_pk, 64))
break;
}
smp->debug_key = false;
......@@ -588,7 +589,6 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16])
SMP_DBG("OOB Public Key X: %32phN", smp->local_pk);
SMP_DBG("OOB Public Key Y: %32phN", smp->local_pk + 32);
SMP_DBG("OOB Private Key: %32phN", smp->local_sk);
get_random_bytes(smp->local_rand, 16);
......@@ -771,6 +771,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
crypto_free_cipher(smp->tfm_aes);
crypto_free_shash(smp->tfm_cmac);
crypto_free_kpp(smp->tfm_ecdh);
/* Ensure that we don't leave any debug key around if debug key
* support hasn't been explicitly enabled.
......@@ -1391,16 +1392,19 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
smp->tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(smp->tfm_aes)) {
BT_ERR("Unable to create AES crypto context");
kzfree(smp);
return NULL;
goto zfree_smp;
}
smp->tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0);
if (IS_ERR(smp->tfm_cmac)) {
BT_ERR("Unable to create CMAC crypto context");
crypto_free_cipher(smp->tfm_aes);
kzfree(smp);
return NULL;
goto free_cipher;
}
smp->tfm_ecdh = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
if (IS_ERR(smp->tfm_ecdh)) {
BT_ERR("Unable to create ECDH crypto context");
goto free_shash;
}
smp->conn = conn;
......@@ -1413,6 +1417,14 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
hci_conn_hold(conn->hcon);
return smp;
free_shash:
crypto_free_shash(smp->tfm_cmac);
free_cipher:
crypto_free_cipher(smp->tfm_aes);
zfree_smp:
kzfree(smp);
return NULL;
}
static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16])
......@@ -1883,7 +1895,6 @@ static u8 sc_send_public_key(struct smp_chan *smp)
smp_dev = chan->data;
memcpy(smp->local_pk, smp_dev->local_pk, 64);
memcpy(smp->local_sk, smp_dev->local_sk, 32);
memcpy(smp->lr, smp_dev->local_rand, 16);
if (smp_dev->debug_key)
......@@ -1894,22 +1905,20 @@ static u8 sc_send_public_key(struct smp_chan *smp)
if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) {
BT_DBG("Using debug keys");
if (set_ecdh_privkey(smp->tfm_ecdh, debug_sk))
return SMP_UNSPECIFIED;
memcpy(smp->local_pk, debug_pk, 64);
memcpy(smp->local_sk, debug_sk, 32);
set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags);
} else {
while (true) {
/* Seed private key with random number */
get_random_bytes(smp->local_sk, 32);
/* Generate local key pair for Secure Connections */
if (!generate_ecdh_keys(smp->local_pk, smp->local_sk))
/* Generate key pair for Secure Connections */
if (generate_ecdh_keys(smp->tfm_ecdh, smp->local_pk))
return SMP_UNSPECIFIED;
/* This is unlikely, but we need to check that
* we didn't accidentially generate a debug key.
*/
if (crypto_memneq(smp->local_sk, debug_sk, 32))
if (crypto_memneq(smp->local_pk, debug_pk, 64))
break;
}
}
......@@ -1917,7 +1926,6 @@ static u8 sc_send_public_key(struct smp_chan *smp)
done:
SMP_DBG("Local Public Key X: %32phN", smp->local_pk);
SMP_DBG("Local Public Key Y: %32phN", smp->local_pk + 32);
SMP_DBG("Local Private Key: %32phN", smp->local_sk);
smp_send_cmd(smp->conn, SMP_CMD_PUBLIC_KEY, 64, smp->local_pk);
......@@ -2645,6 +2653,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
struct l2cap_chan *chan = conn->smp;
struct smp_chan *smp = chan->data;
struct hci_dev *hdev = hcon->hdev;
struct crypto_kpp *tfm_ecdh;
struct smp_cmd_pairing_confirm cfm;
int err;
......@@ -2677,7 +2686,18 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
SMP_DBG("Remote Public Key X: %32phN", smp->remote_pk);
SMP_DBG("Remote Public Key Y: %32phN", smp->remote_pk + 32);
if (!compute_ecdh_secret(smp->remote_pk, smp->local_sk, smp->dhkey))
/* Compute the shared secret on the same crypto tfm on which the private
* key was set/generated.
*/
if (test_bit(SMP_FLAG_LOCAL_OOB, &smp->flags)) {
struct smp_dev *smp_dev = chan->data;
tfm_ecdh = smp_dev->tfm_ecdh;
} else {
tfm_ecdh = smp->tfm_ecdh;
}
if (compute_ecdh_secret(tfm_ecdh, smp->remote_pk, smp->dhkey))
return SMP_UNSPECIFIED;
SMP_DBG("DHKey %32phN", smp->dhkey);
......@@ -3169,6 +3189,7 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
struct smp_dev *smp;
struct crypto_cipher *tfm_aes;
struct crypto_shash *tfm_cmac;
struct crypto_kpp *tfm_ecdh;
if (cid == L2CAP_CID_SMP_BREDR) {
smp = NULL;
......@@ -3194,8 +3215,18 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
return ERR_CAST(tfm_cmac);
}
tfm_ecdh = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
if (IS_ERR(tfm_ecdh)) {
BT_ERR("Unable to create ECDH crypto context");
crypto_free_shash(tfm_cmac);
crypto_free_cipher(tfm_aes);
kzfree(smp);
return ERR_CAST(tfm_ecdh);
}
smp->tfm_aes = tfm_aes;
smp->tfm_cmac = tfm_cmac;
smp->tfm_ecdh = tfm_ecdh;
smp->min_key_size = SMP_MIN_ENC_KEY_SIZE;
smp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
......@@ -3205,6 +3236,7 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
if (smp) {
crypto_free_cipher(smp->tfm_aes);
crypto_free_shash(smp->tfm_cmac);
crypto_free_kpp(smp->tfm_ecdh);
kzfree(smp);
}
return ERR_PTR(-ENOMEM);
......@@ -3252,6 +3284,7 @@ static void smp_del_chan(struct l2cap_chan *chan)
chan->data = NULL;
crypto_free_cipher(smp->tfm_aes);
crypto_free_shash(smp->tfm_cmac);
crypto_free_kpp(smp->tfm_ecdh);
kzfree(smp);
}
......@@ -3490,25 +3523,18 @@ void smp_unregister(struct hci_dev *hdev)
#if IS_ENABLED(CONFIG_BT_SELFTEST_SMP)
static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits)
static int __init test_debug_key(struct crypto_kpp *tfm_ecdh)
{
int i;
for (i = 0; i < ndigits; i++)
out[i] = __swab64(in[ndigits - 1 - i]);
}
static int __init test_debug_key(void)
{
u8 pk[64], sk[32];
swap_digits((u64 *)debug_sk, (u64 *)sk, 4);
u8 pk[64];
int err;
if (!generate_ecdh_keys(pk, sk))
return -EINVAL;
err = set_ecdh_privkey(tfm_ecdh, debug_sk);
if (err)
return err;
if (crypto_memneq(sk, debug_sk, 32))
return -EINVAL;
err = generate_ecdh_public_key(tfm_ecdh, pk);
if (err)
return err;
if (crypto_memneq(pk, debug_pk, 64))
return -EINVAL;
......@@ -3763,7 +3789,8 @@ static const struct file_operations test_smp_fops = {
};
static int __init run_selftests(struct crypto_cipher *tfm_aes,
struct crypto_shash *tfm_cmac)
struct crypto_shash *tfm_cmac,
struct crypto_kpp *tfm_ecdh)
{
ktime_t calltime, delta, rettime;
unsigned long long duration;
......@@ -3771,7 +3798,7 @@ static int __init run_selftests(struct crypto_cipher *tfm_aes,
calltime = ktime_get();
err = test_debug_key();
err = test_debug_key(tfm_ecdh);
if (err) {
BT_ERR("debug_key test failed");
goto done;
......@@ -3848,6 +3875,7 @@ int __init bt_selftest_smp(void)
{
struct crypto_cipher *tfm_aes;
struct crypto_shash *tfm_cmac;
struct crypto_kpp *tfm_ecdh;
int err;
tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
......@@ -3863,10 +3891,19 @@ int __init bt_selftest_smp(void)
return PTR_ERR(tfm_cmac);
}
err = run_selftests(tfm_aes, tfm_cmac);
tfm_ecdh = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
if (IS_ERR(tfm_ecdh)) {
BT_ERR("Unable to create ECDH crypto context");
crypto_free_shash(tfm_cmac);
crypto_free_cipher(tfm_aes);
return PTR_ERR(tfm_ecdh);
}
err = run_selftests(tfm_aes, tfm_cmac, tfm_ecdh);
crypto_free_shash(tfm_cmac);
crypto_free_cipher(tfm_aes);
crypto_free_kpp(tfm_ecdh);
return err;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment