|
@@ -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>
|
|
@@ -92,6 +93,7 @@ struct smp_dev {
|
|
|
|
|
|
struct crypto_cipher *tfm_aes;
|
|
|
struct crypto_shash *tfm_cmac;
|
|
|
+ struct crypto_kpp *tfm_ecdh;
|
|
|
};
|
|
|
|
|
|
struct smp_chan {
|
|
@@ -131,6 +133,7 @@ struct smp_chan {
|
|
|
|
|
|
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
|
|
@@ -574,7 +577,8 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16])
|
|
|
get_random_bytes(smp->local_sk, 32);
|
|
|
|
|
|
/* Generate local key pair for Secure Connections */
|
|
|
- if (!generate_ecdh_keys(smp->local_pk, smp->local_sk))
|
|
|
+ if (!generate_ecdh_keys(smp->tfm_ecdh, smp->local_pk,
|
|
|
+ smp->local_sk))
|
|
|
return -EIO;
|
|
|
|
|
|
/* This is unlikely, but we need to check that
|
|
@@ -771,6 +775,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 +1396,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 +1421,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])
|
|
@@ -1903,7 +1919,8 @@ static u8 sc_send_public_key(struct smp_chan *smp)
|
|
|
get_random_bytes(smp->local_sk, 32);
|
|
|
|
|
|
/* Generate local key pair for Secure Connections */
|
|
|
- if (!generate_ecdh_keys(smp->local_pk, smp->local_sk))
|
|
|
+ if (!generate_ecdh_keys(smp->tfm_ecdh, smp->local_pk,
|
|
|
+ smp->local_sk))
|
|
|
return SMP_UNSPECIFIED;
|
|
|
|
|
|
/* This is unlikely, but we need to check that
|
|
@@ -2677,7 +2694,8 @@ 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))
|
|
|
+ if (!compute_ecdh_secret(smp->tfm_ecdh, smp->remote_pk, smp->local_sk,
|
|
|
+ smp->dhkey))
|
|
|
return SMP_UNSPECIFIED;
|
|
|
|
|
|
SMP_DBG("DHKey %32phN", smp->dhkey);
|
|
@@ -3169,6 +3187,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 +3213,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 +3234,7 @@ create_chan:
|
|
|
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 +3282,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);
|
|
|
}
|
|
|
|
|
@@ -3498,13 +3529,13 @@ static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits)
|
|
|
out[i] = __swab64(in[ndigits - 1 - i]);
|
|
|
}
|
|
|
|
|
|
-static int __init test_debug_key(void)
|
|
|
+static int __init test_debug_key(struct crypto_kpp *tfm_ecdh)
|
|
|
{
|
|
|
u8 pk[64], sk[32];
|
|
|
|
|
|
swap_digits((u64 *)debug_sk, (u64 *)sk, 4);
|
|
|
|
|
|
- if (!generate_ecdh_keys(pk, sk))
|
|
|
+ if (!generate_ecdh_keys(tfm_ecdh, pk, sk))
|
|
|
return -EINVAL;
|
|
|
|
|
|
if (crypto_memneq(sk, debug_sk, 32))
|
|
@@ -3763,7 +3794,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 +3803,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 +3880,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 +3896,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;
|
|
|
}
|