mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Bluetooth: convert smp and selftest to crypto kpp API
* Convert both smp and selftest to crypto kpp API * Remove module ecc as no more required * Add ecdh_helper functions for wrapping kpp async calls This patch has been tested *only* with selftest, which is called on module loading. Signed-off-by: Salvatore Benedetto <salvatore.benedetto@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
committed by
Marcel Holtmann
parent
e3a724edee
commit
58771c1cb0
@@ -13,6 +13,7 @@ menuconfig BT
|
||||
select CRYPTO_CMAC
|
||||
select CRYPTO_ECB
|
||||
select CRYPTO_SHA256
|
||||
select CRYPTO_ECDH
|
||||
help
|
||||
Bluetooth is low-cost, low-power, short-range wireless technology.
|
||||
It was designed as a replacement for cables and other short-range
|
||||
|
||||
@@ -13,7 +13,7 @@ bluetooth_6lowpan-y := 6lowpan.o
|
||||
|
||||
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
|
||||
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
|
||||
ecc.o hci_request.o mgmt_util.o
|
||||
ecdh_helper.o hci_request.o mgmt_util.o
|
||||
|
||||
bluetooth-$(CONFIG_BT_BREDR) += sco.o
|
||||
bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Kenneth MacKay
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Create a public/private key pair.
|
||||
* Outputs:
|
||||
* public_key - Will be filled in with the public key.
|
||||
* private_key - Will be filled in with the private key.
|
||||
*
|
||||
* Returns true if the key pair was generated successfully, false
|
||||
* if an error occurred. The keys are with the LSB first.
|
||||
*/
|
||||
bool ecc_make_key(u8 public_key[64], u8 private_key[32]);
|
||||
|
||||
/* Compute a shared secret given your secret key and someone else's
|
||||
* public key.
|
||||
* Note: It is recommended that you hash the result of ecdh_shared_secret
|
||||
* before using it for symmetric encryption or HMAC.
|
||||
*
|
||||
* Inputs:
|
||||
* public_key - The public key of the remote party
|
||||
* private_key - Your private key.
|
||||
*
|
||||
* Outputs:
|
||||
* secret - Will be filled in with the shared secret value.
|
||||
*
|
||||
* Returns true if the shared secret was generated successfully, false
|
||||
* if an error occurred. Both input and output parameters are with the
|
||||
* LSB first.
|
||||
*/
|
||||
bool ecdh_shared_secret(const u8 public_key[64], const u8 private_key[32],
|
||||
u8 secret[32]);
|
||||
223
net/bluetooth/ecdh_helper.c
Normal file
223
net/bluetooth/ecdh_helper.c
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* ECDH helper functions - KPP wrappings
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
|
||||
* CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
|
||||
* COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
|
||||
* SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
#include "ecdh_helper.h"
|
||||
|
||||
#include <linux/random.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <crypto/kpp.h>
|
||||
#include <crypto/ecdh.h>
|
||||
|
||||
struct ecdh_completion {
|
||||
struct completion completion;
|
||||
int err;
|
||||
};
|
||||
|
||||
static void ecdh_complete(struct crypto_async_request *req, int err)
|
||||
{
|
||||
struct ecdh_completion *res = req->data;
|
||||
|
||||
if (err == -EINPROGRESS)
|
||||
return;
|
||||
|
||||
res->err = err;
|
||||
complete(&res->completion);
|
||||
}
|
||||
|
||||
static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ndigits; i++)
|
||||
out[i] = __swab64(in[ndigits - 1 - i]);
|
||||
}
|
||||
|
||||
bool compute_ecdh_secret(const u8 public_key[64], const u8 private_key[32],
|
||||
u8 secret[32])
|
||||
{
|
||||
struct crypto_kpp *tfm;
|
||||
struct kpp_request *req;
|
||||
struct ecdh p;
|
||||
struct ecdh_completion result;
|
||||
struct scatterlist src, dst;
|
||||
u8 tmp[64];
|
||||
u8 *buf;
|
||||
unsigned int buf_len;
|
||||
int err = -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));
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
pr_err("alg: kpp: Failed to allocate %d bytes for buf\n",
|
||||
buf_len);
|
||||
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 */
|
||||
|
||||
sg_init_one(&src, tmp, 64);
|
||||
sg_init_one(&dst, secret, 32);
|
||||
kpp_request_set_input(req, &src, 64);
|
||||
kpp_request_set_output(req, &dst, 32);
|
||||
kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
|
||||
ecdh_complete, &result);
|
||||
err = crypto_kpp_compute_shared_secret(req);
|
||||
if (err == -EINPROGRESS) {
|
||||
wait_for_completion(&result.completion);
|
||||
err = result.err;
|
||||
}
|
||||
if (err < 0) {
|
||||
pr_err("alg: ecdh: compute shared secret failed. err %d\n",
|
||||
err);
|
||||
goto free_all;
|
||||
}
|
||||
|
||||
swap_digits((u64 *)secret, (u64 *)tmp, 4);
|
||||
memcpy(secret, tmp, 32);
|
||||
|
||||
free_all:
|
||||
kzfree(buf);
|
||||
free_req:
|
||||
kpp_request_free(req);
|
||||
free_kpp:
|
||||
crypto_free_kpp(tfm);
|
||||
return (err == 0);
|
||||
}
|
||||
|
||||
bool generate_ecdh_keys(u8 public_key[64], u8 private_key[32])
|
||||
{
|
||||
struct crypto_kpp *tfm;
|
||||
struct kpp_request *req;
|
||||
struct ecdh p;
|
||||
struct ecdh_completion result;
|
||||
struct scatterlist dst;
|
||||
u8 tmp[64];
|
||||
u8 *buf;
|
||||
unsigned int buf_len;
|
||||
int err = -ENOMEM;
|
||||
const unsigned short max_tries = 16;
|
||||
unsigned short tries = 0;
|
||||
|
||||
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));
|
||||
return false;
|
||||
}
|
||||
|
||||
req = kpp_request_alloc(tfm, GFP_KERNEL);
|
||||
if (!req)
|
||||
goto free_kpp;
|
||||
|
||||
init_completion(&result.completion);
|
||||
|
||||
/* 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) {
|
||||
pr_err("alg: kpp: Failed to allocate %d bytes for buf\n",
|
||||
buf_len);
|
||||
goto free_req;
|
||||
}
|
||||
|
||||
do {
|
||||
if (tries++ >= max_tries)
|
||||
goto free_all;
|
||||
|
||||
get_random_bytes(private_key, 32);
|
||||
|
||||
/* 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_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
|
||||
*/
|
||||
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);
|
||||
return (err == 0);
|
||||
}
|
||||
27
net/bluetooth/ecdh_helper.h
Normal file
27
net/bluetooth/ecdh_helper.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* ECDH helper functions - KPP wrappings
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
|
||||
* CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
|
||||
* COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
|
||||
* SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
#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]);
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#include "ecc.h"
|
||||
#include "ecdh_helper.h"
|
||||
#include "smp.h"
|
||||
#include "selftest.h"
|
||||
|
||||
@@ -144,8 +144,8 @@ static int __init test_ecdh_sample(const u8 priv_a[32], const u8 priv_b[32],
|
||||
{
|
||||
u8 dhkey_a[32], dhkey_b[32];
|
||||
|
||||
ecdh_shared_secret(pub_b, priv_a, dhkey_a);
|
||||
ecdh_shared_secret(pub_a, priv_b, dhkey_b);
|
||||
compute_ecdh_secret(pub_b, priv_a, dhkey_a);
|
||||
compute_ecdh_secret(pub_a, priv_b, dhkey_b);
|
||||
|
||||
if (memcmp(dhkey_a, dhkey, 32))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <net/bluetooth/l2cap.h>
|
||||
#include <net/bluetooth/mgmt.h>
|
||||
|
||||
#include "ecc.h"
|
||||
#include "ecdh_helper.h"
|
||||
#include "smp.h"
|
||||
|
||||
#define SMP_DEV(hdev) \
|
||||
@@ -570,7 +570,7 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16])
|
||||
} else {
|
||||
while (true) {
|
||||
/* Generate local key pair for Secure Connections */
|
||||
if (!ecc_make_key(smp->local_pk, smp->local_sk))
|
||||
if (!generate_ecdh_keys(smp->local_pk, smp->local_sk))
|
||||
return -EIO;
|
||||
|
||||
/* This is unlikely, but we need to check that
|
||||
@@ -1896,7 +1896,7 @@ static u8 sc_send_public_key(struct smp_chan *smp)
|
||||
} else {
|
||||
while (true) {
|
||||
/* Generate local key pair for Secure Connections */
|
||||
if (!ecc_make_key(smp->local_pk, smp->local_sk))
|
||||
if (!generate_ecdh_keys(smp->local_pk, smp->local_sk))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
/* This is unlikely, but we need to check that
|
||||
@@ -2670,7 +2670,7 @@ 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 (!ecdh_shared_secret(smp->remote_pk, smp->local_sk, smp->dhkey))
|
||||
if (!compute_ecdh_secret(smp->remote_pk, smp->local_sk, smp->dhkey))
|
||||
return SMP_UNSPECIFIED;
|
||||
|
||||
SMP_DBG("DHKey %32phN", smp->dhkey);
|
||||
|
||||
Reference in New Issue
Block a user