Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 47eb2ac8 authored by Tudor Ambarus's avatar Tudor Ambarus Committed by Marcel Holtmann
Browse files

Bluetooth: move ecdh allocation outside of ecdh_helper



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: default avatarTudor Ambarus <tudor.ambarus@microchip.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 24a3a32a
Loading
Loading
Loading
Loading
+6 −26
Original line number Diff line number Diff line
@@ -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 @@ bool compute_ecdh_secret(const u8 public_key[64], const u8 private_key[32],
	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 @@ bool generate_ecdh_keys(u8 public_key[64], u8 private_key[32])
	kzfree(buf);
free_req:
	kpp_request_free(req);
free_kpp:
	crypto_free_kpp(tfm);
free_tmp:
	kfree(tmp);
	return (err == 0);
+5 −3
Original line number Diff line number Diff line
@@ -20,8 +20,10 @@
 * 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]);
+21 −8
Original line number Diff line number Diff line
@@ -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;
+55 −13
Original line number Diff line number Diff line
@@ -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 @@ 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 +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;
}