Bluetooth: move ecdh allocation outside of ecdh_helper
authorTudor Ambarus <tudor.ambarus@microchip.com>
Thu, 28 Sep 2017 14:14:51 +0000 (17:14 +0300)
committerMarcel Holtmann <marcel@holtmann.org>
Fri, 6 Oct 2017 18:35:47 +0000 (20:35 +0200)
Before this change, a new crypto tfm was allocated, each time,
for both key generation and shared secret computation.

Allocate a single tfm for both cases.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
net/bluetooth/ecdh_helper.c
net/bluetooth/ecdh_helper.h
net/bluetooth/selftest.c
net/bluetooth/smp.c

index c7b1a9aee5793e20d28eb3f9329c0f2b579328f4..ac2c7087921d4b8d704b2f1ac9e3d20859cce2fb 100644 (file)
@@ -23,7 +23,6 @@
 #include "ecdh_helper.h"
 
 #include <linux/scatterlist.h>
-#include <crypto/kpp.h>
 #include <crypto/ecdh.h>
 
 struct ecdh_completion {
@@ -50,10 +49,9 @@ 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])
+bool compute_ecdh_secret(struct crypto_kpp *tfm, 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;
@@ -66,16 +64,9 @@ bool compute_ecdh_secret(const u8 public_key[64], const u8 private_key[32],
        if (!tmp)
                return false;
 
-       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));
-               goto free_tmp;
-       }
-
        req = kpp_request_alloc(tfm, GFP_KERNEL);
        if (!req)
-               goto free_kpp;
+               goto free_tmp;
 
        init_completion(&result.completion);
 
@@ -126,16 +117,14 @@ free_all:
        kzfree(buf);
 free_req:
        kpp_request_free(req);
-free_kpp:
-       crypto_free_kpp(tfm);
 free_tmp:
        kfree(tmp);
        return (err == 0);
 }
 
-bool generate_ecdh_keys(u8 public_key[64], u8 private_key[32])
+bool generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64],
+                       u8 private_key[32])
 {
-       struct crypto_kpp *tfm;
        struct kpp_request *req;
        struct ecdh p;
        struct ecdh_completion result;
@@ -150,16 +139,9 @@ bool generate_ecdh_keys(u8 public_key[64], u8 private_key[32])
        if (!tmp)
                return false;
 
-       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));
-               goto free_tmp;
-       }
-
        req = kpp_request_alloc(tfm, GFP_KERNEL);
        if (!req)
-               goto free_kpp;
+               goto free_tmp;
 
        init_completion(&result.completion);
 
@@ -218,8 +200,6 @@ free_all:
        kzfree(buf);
 free_req:
        kpp_request_free(req);
-free_kpp:
-       crypto_free_kpp(tfm);
 free_tmp:
        kfree(tmp);
        return (err == 0);
index 7a423faf76e5657c6a4c860031138f59eef0dcc0..5cde37d12fd9957d5c44d17376d68b4cd445ca06 100644 (file)
  * 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]);
+bool compute_ecdh_secret(struct crypto_kpp *tfm, const u8 pub_a[64],
+                        const u8 priv_b[32], u8 secret[32]);
+bool generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64],
+                       u8 private_key[32]);
index 34a1227f43910e9d728e6a312e5933a9231aed9f..126bdc5a77a72656c8e92fd744a422ed80fc3d7c 100644 (file)
@@ -138,9 +138,9 @@ 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;
@@ -152,8 +152,8 @@ 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);
+       compute_ecdh_secret(tfm, pub_b, priv_a, dhkey_a);
+       compute_ecdh_secret(tfm, pub_a, priv_b, dhkey_b);
 
        if (memcmp(dhkey_a, dhkey, 32)) {
                ret = -EINVAL;
@@ -185,30 +185,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;
        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;
index a0ef89772c366c53097c3a18760e48d302d00656..31b64bc3cf1653168a43e94d03d101eacd964605 100644 (file)
@@ -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;
 }