xref: /openbmc/linux/net/bluetooth/ecdh_helper.c (revision f958315358bc37aede49dc3cd7e27e037994ae84)
158771c1cSSalvatore Benedetto /*
258771c1cSSalvatore Benedetto  * ECDH helper functions - KPP wrappings
358771c1cSSalvatore Benedetto  *
458771c1cSSalvatore Benedetto  * Copyright (C) 2017 Intel Corporation
558771c1cSSalvatore Benedetto  *
658771c1cSSalvatore Benedetto  * This program is free software; you can redistribute it and/or modify
758771c1cSSalvatore Benedetto  * it under the terms of the GNU General Public License version 2 as
858771c1cSSalvatore Benedetto  * published by the Free Software Foundation;
958771c1cSSalvatore Benedetto  *
1058771c1cSSalvatore Benedetto  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1158771c1cSSalvatore Benedetto  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1258771c1cSSalvatore Benedetto  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
1358771c1cSSalvatore Benedetto  * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
1458771c1cSSalvatore Benedetto  * CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
1558771c1cSSalvatore Benedetto  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1658771c1cSSalvatore Benedetto  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1758771c1cSSalvatore Benedetto  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1858771c1cSSalvatore Benedetto  *
1958771c1cSSalvatore Benedetto  * ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
2058771c1cSSalvatore Benedetto  * COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
2158771c1cSSalvatore Benedetto  * SOFTWARE IS DISCLAIMED.
2258771c1cSSalvatore Benedetto  */
2358771c1cSSalvatore Benedetto #include "ecdh_helper.h"
2458771c1cSSalvatore Benedetto 
2558771c1cSSalvatore Benedetto #include <linux/random.h>
2658771c1cSSalvatore Benedetto #include <linux/scatterlist.h>
2758771c1cSSalvatore Benedetto #include <crypto/kpp.h>
2858771c1cSSalvatore Benedetto #include <crypto/ecdh.h>
2958771c1cSSalvatore Benedetto 
3058771c1cSSalvatore Benedetto struct ecdh_completion {
3158771c1cSSalvatore Benedetto 	struct completion completion;
3258771c1cSSalvatore Benedetto 	int err;
3358771c1cSSalvatore Benedetto };
3458771c1cSSalvatore Benedetto 
3558771c1cSSalvatore Benedetto static void ecdh_complete(struct crypto_async_request *req, int err)
3658771c1cSSalvatore Benedetto {
3758771c1cSSalvatore Benedetto 	struct ecdh_completion *res = req->data;
3858771c1cSSalvatore Benedetto 
3958771c1cSSalvatore Benedetto 	if (err == -EINPROGRESS)
4058771c1cSSalvatore Benedetto 		return;
4158771c1cSSalvatore Benedetto 
4258771c1cSSalvatore Benedetto 	res->err = err;
4358771c1cSSalvatore Benedetto 	complete(&res->completion);
4458771c1cSSalvatore Benedetto }
4558771c1cSSalvatore Benedetto 
4658771c1cSSalvatore Benedetto static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits)
4758771c1cSSalvatore Benedetto {
4858771c1cSSalvatore Benedetto 	int i;
4958771c1cSSalvatore Benedetto 
5058771c1cSSalvatore Benedetto 	for (i = 0; i < ndigits; i++)
5158771c1cSSalvatore Benedetto 		out[i] = __swab64(in[ndigits - 1 - i]);
5258771c1cSSalvatore Benedetto }
5358771c1cSSalvatore Benedetto 
5458771c1cSSalvatore Benedetto bool compute_ecdh_secret(const u8 public_key[64], const u8 private_key[32],
5558771c1cSSalvatore Benedetto 			 u8 secret[32])
5658771c1cSSalvatore Benedetto {
5758771c1cSSalvatore Benedetto 	struct crypto_kpp *tfm;
5858771c1cSSalvatore Benedetto 	struct kpp_request *req;
5958771c1cSSalvatore Benedetto 	struct ecdh p;
6058771c1cSSalvatore Benedetto 	struct ecdh_completion result;
6158771c1cSSalvatore Benedetto 	struct scatterlist src, dst;
62763d9a30SSalvatore Benedetto 	u8 *tmp, *buf;
6358771c1cSSalvatore Benedetto 	unsigned int buf_len;
6458771c1cSSalvatore Benedetto 	int err = -ENOMEM;
6558771c1cSSalvatore Benedetto 
66763d9a30SSalvatore Benedetto 	tmp = kmalloc(64, GFP_KERNEL);
67763d9a30SSalvatore Benedetto 	if (!tmp)
68763d9a30SSalvatore Benedetto 		return false;
69763d9a30SSalvatore Benedetto 
7058771c1cSSalvatore Benedetto 	tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
7158771c1cSSalvatore Benedetto 	if (IS_ERR(tfm)) {
7258771c1cSSalvatore Benedetto 		pr_err("alg: kpp: Failed to load tfm for kpp: %ld\n",
7358771c1cSSalvatore Benedetto 		       PTR_ERR(tfm));
74763d9a30SSalvatore Benedetto 		goto free_tmp;
7558771c1cSSalvatore Benedetto 	}
7658771c1cSSalvatore Benedetto 
7758771c1cSSalvatore Benedetto 	req = kpp_request_alloc(tfm, GFP_KERNEL);
7858771c1cSSalvatore Benedetto 	if (!req)
7958771c1cSSalvatore Benedetto 		goto free_kpp;
8058771c1cSSalvatore Benedetto 
8158771c1cSSalvatore Benedetto 	init_completion(&result.completion);
8258771c1cSSalvatore Benedetto 
8358771c1cSSalvatore Benedetto 	/* Security Manager Protocol holds digits in litte-endian order
8458771c1cSSalvatore Benedetto 	 * while ECC API expect big-endian data
8558771c1cSSalvatore Benedetto 	 */
8658771c1cSSalvatore Benedetto 	swap_digits((u64 *)private_key, (u64 *)tmp, 4);
8758771c1cSSalvatore Benedetto 	p.key = (char *)tmp;
8858771c1cSSalvatore Benedetto 	p.key_size = 32;
8958771c1cSSalvatore Benedetto 	/* Set curve_id */
9058771c1cSSalvatore Benedetto 	p.curve_id = ECC_CURVE_NIST_P256;
9158771c1cSSalvatore Benedetto 	buf_len = crypto_ecdh_key_len(&p);
9258771c1cSSalvatore Benedetto 	buf = kmalloc(buf_len, GFP_KERNEL);
9358771c1cSSalvatore Benedetto 	if (!buf) {
9458771c1cSSalvatore Benedetto 		pr_err("alg: kpp: Failed to allocate %d bytes for buf\n",
9558771c1cSSalvatore Benedetto 		       buf_len);
9658771c1cSSalvatore Benedetto 		goto free_req;
9758771c1cSSalvatore Benedetto 	}
9858771c1cSSalvatore Benedetto 	crypto_ecdh_encode_key(buf, buf_len, &p);
9958771c1cSSalvatore Benedetto 
10058771c1cSSalvatore Benedetto 	/* Set A private Key */
10158771c1cSSalvatore Benedetto 	err = crypto_kpp_set_secret(tfm, (void *)buf, buf_len);
10258771c1cSSalvatore Benedetto 	if (err)
10358771c1cSSalvatore Benedetto 		goto free_all;
10458771c1cSSalvatore Benedetto 
10558771c1cSSalvatore Benedetto 	swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */
10658771c1cSSalvatore Benedetto 	swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */
10758771c1cSSalvatore Benedetto 
10858771c1cSSalvatore Benedetto 	sg_init_one(&src, tmp, 64);
10958771c1cSSalvatore Benedetto 	sg_init_one(&dst, secret, 32);
11058771c1cSSalvatore Benedetto 	kpp_request_set_input(req, &src, 64);
11158771c1cSSalvatore Benedetto 	kpp_request_set_output(req, &dst, 32);
11258771c1cSSalvatore Benedetto 	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
11358771c1cSSalvatore Benedetto 				 ecdh_complete, &result);
11458771c1cSSalvatore Benedetto 	err = crypto_kpp_compute_shared_secret(req);
11558771c1cSSalvatore Benedetto 	if (err == -EINPROGRESS) {
11658771c1cSSalvatore Benedetto 		wait_for_completion(&result.completion);
11758771c1cSSalvatore Benedetto 		err = result.err;
11858771c1cSSalvatore Benedetto 	}
11958771c1cSSalvatore Benedetto 	if (err < 0) {
12058771c1cSSalvatore Benedetto 		pr_err("alg: ecdh: compute shared secret failed. err %d\n",
12158771c1cSSalvatore Benedetto 		       err);
12258771c1cSSalvatore Benedetto 		goto free_all;
12358771c1cSSalvatore Benedetto 	}
12458771c1cSSalvatore Benedetto 
12558771c1cSSalvatore Benedetto 	swap_digits((u64 *)secret, (u64 *)tmp, 4);
12658771c1cSSalvatore Benedetto 	memcpy(secret, tmp, 32);
12758771c1cSSalvatore Benedetto 
12858771c1cSSalvatore Benedetto free_all:
12958771c1cSSalvatore Benedetto 	kzfree(buf);
13058771c1cSSalvatore Benedetto free_req:
13158771c1cSSalvatore Benedetto 	kpp_request_free(req);
13258771c1cSSalvatore Benedetto free_kpp:
13358771c1cSSalvatore Benedetto 	crypto_free_kpp(tfm);
134763d9a30SSalvatore Benedetto free_tmp:
135763d9a30SSalvatore Benedetto 	kfree(tmp);
13658771c1cSSalvatore Benedetto 	return (err == 0);
13758771c1cSSalvatore Benedetto }
13858771c1cSSalvatore Benedetto 
13958771c1cSSalvatore Benedetto bool generate_ecdh_keys(u8 public_key[64], u8 private_key[32])
14058771c1cSSalvatore Benedetto {
14158771c1cSSalvatore Benedetto 	struct crypto_kpp *tfm;
14258771c1cSSalvatore Benedetto 	struct kpp_request *req;
14358771c1cSSalvatore Benedetto 	struct ecdh p;
14458771c1cSSalvatore Benedetto 	struct ecdh_completion result;
14558771c1cSSalvatore Benedetto 	struct scatterlist dst;
146763d9a30SSalvatore Benedetto 	u8 *tmp, *buf;
14758771c1cSSalvatore Benedetto 	unsigned int buf_len;
14858771c1cSSalvatore Benedetto 	int err = -ENOMEM;
14958771c1cSSalvatore Benedetto 	const unsigned short max_tries = 16;
15058771c1cSSalvatore Benedetto 	unsigned short tries = 0;
15158771c1cSSalvatore Benedetto 
152763d9a30SSalvatore Benedetto 	tmp = kmalloc(64, GFP_KERNEL);
153763d9a30SSalvatore Benedetto 	if (!tmp)
154763d9a30SSalvatore Benedetto 		return false;
155763d9a30SSalvatore Benedetto 
15658771c1cSSalvatore Benedetto 	tfm = crypto_alloc_kpp("ecdh", CRYPTO_ALG_INTERNAL, 0);
15758771c1cSSalvatore Benedetto 	if (IS_ERR(tfm)) {
15858771c1cSSalvatore Benedetto 		pr_err("alg: kpp: Failed to load tfm for kpp: %ld\n",
15958771c1cSSalvatore Benedetto 		       PTR_ERR(tfm));
160763d9a30SSalvatore Benedetto 		goto free_tmp;
16158771c1cSSalvatore Benedetto 	}
16258771c1cSSalvatore Benedetto 
16358771c1cSSalvatore Benedetto 	req = kpp_request_alloc(tfm, GFP_KERNEL);
16458771c1cSSalvatore Benedetto 	if (!req)
16558771c1cSSalvatore Benedetto 		goto free_kpp;
16658771c1cSSalvatore Benedetto 
16758771c1cSSalvatore Benedetto 	init_completion(&result.completion);
16858771c1cSSalvatore Benedetto 
16958771c1cSSalvatore Benedetto 	/* Set curve_id */
17058771c1cSSalvatore Benedetto 	p.curve_id = ECC_CURVE_NIST_P256;
17158771c1cSSalvatore Benedetto 	p.key_size = 32;
17258771c1cSSalvatore Benedetto 	buf_len = crypto_ecdh_key_len(&p);
17358771c1cSSalvatore Benedetto 	buf = kmalloc(buf_len, GFP_KERNEL);
17458771c1cSSalvatore Benedetto 	if (!buf) {
17558771c1cSSalvatore Benedetto 		pr_err("alg: kpp: Failed to allocate %d bytes for buf\n",
17658771c1cSSalvatore Benedetto 		       buf_len);
17758771c1cSSalvatore Benedetto 		goto free_req;
17858771c1cSSalvatore Benedetto 	}
17958771c1cSSalvatore Benedetto 
18058771c1cSSalvatore Benedetto 	do {
18158771c1cSSalvatore Benedetto 		if (tries++ >= max_tries)
18258771c1cSSalvatore Benedetto 			goto free_all;
18358771c1cSSalvatore Benedetto 
18458771c1cSSalvatore Benedetto 		get_random_bytes(private_key, 32);
18558771c1cSSalvatore Benedetto 
18658771c1cSSalvatore Benedetto 		/* Set private Key */
18758771c1cSSalvatore Benedetto 		p.key = (char *)private_key;
18858771c1cSSalvatore Benedetto 		crypto_ecdh_encode_key(buf, buf_len, &p);
18958771c1cSSalvatore Benedetto 		err = crypto_kpp_set_secret(tfm, buf, buf_len);
19058771c1cSSalvatore Benedetto 		if (err)
19158771c1cSSalvatore Benedetto 			goto free_all;
19258771c1cSSalvatore Benedetto 
19358771c1cSSalvatore Benedetto 		sg_init_one(&dst, tmp, 64);
194*f9583153SMarcel Holtmann 		kpp_request_set_input(req, NULL, 0);
19558771c1cSSalvatore Benedetto 		kpp_request_set_output(req, &dst, 64);
19658771c1cSSalvatore Benedetto 		kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
19758771c1cSSalvatore Benedetto 					 ecdh_complete, &result);
19858771c1cSSalvatore Benedetto 
19958771c1cSSalvatore Benedetto 		err = crypto_kpp_generate_public_key(req);
20058771c1cSSalvatore Benedetto 
20158771c1cSSalvatore Benedetto 		if (err == -EINPROGRESS) {
20258771c1cSSalvatore Benedetto 			wait_for_completion(&result.completion);
20358771c1cSSalvatore Benedetto 			err = result.err;
20458771c1cSSalvatore Benedetto 		}
20558771c1cSSalvatore Benedetto 
20658771c1cSSalvatore Benedetto 		/* Private key is not valid. Regenerate */
20758771c1cSSalvatore Benedetto 		if (err == -EINVAL)
20858771c1cSSalvatore Benedetto 			continue;
20958771c1cSSalvatore Benedetto 
21058771c1cSSalvatore Benedetto 		if (err < 0)
21158771c1cSSalvatore Benedetto 			goto free_all;
21258771c1cSSalvatore Benedetto 		else
21358771c1cSSalvatore Benedetto 			break;
21458771c1cSSalvatore Benedetto 
21558771c1cSSalvatore Benedetto 	} while (true);
21658771c1cSSalvatore Benedetto 
21758771c1cSSalvatore Benedetto 	/* Keys are handed back in little endian as expected by Security
21858771c1cSSalvatore Benedetto 	 * Manager Protocol
21958771c1cSSalvatore Benedetto 	 */
22058771c1cSSalvatore Benedetto 	swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */
22158771c1cSSalvatore Benedetto 	swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */
22258771c1cSSalvatore Benedetto 	swap_digits((u64 *)private_key, (u64 *)tmp, 4);
22358771c1cSSalvatore Benedetto 	memcpy(private_key, tmp, 32);
22458771c1cSSalvatore Benedetto 
22558771c1cSSalvatore Benedetto free_all:
22658771c1cSSalvatore Benedetto 	kzfree(buf);
22758771c1cSSalvatore Benedetto free_req:
22858771c1cSSalvatore Benedetto 	kpp_request_free(req);
22958771c1cSSalvatore Benedetto free_kpp:
23058771c1cSSalvatore Benedetto 	crypto_free_kpp(tfm);
231763d9a30SSalvatore Benedetto free_tmp:
232763d9a30SSalvatore Benedetto 	kfree(tmp);
23358771c1cSSalvatore Benedetto 	return (err == 0);
23458771c1cSSalvatore Benedetto }
235