xref: /openbmc/linux/net/bluetooth/ecdh_helper.c (revision 47eb2ac809189e0a60ad78eec6db9e84004e11be)
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/scatterlist.h>
2658771c1cSSalvatore Benedetto #include <crypto/ecdh.h>
2758771c1cSSalvatore Benedetto 
2858771c1cSSalvatore Benedetto struct ecdh_completion {
2958771c1cSSalvatore Benedetto 	struct completion completion;
3058771c1cSSalvatore Benedetto 	int err;
3158771c1cSSalvatore Benedetto };
3258771c1cSSalvatore Benedetto 
3358771c1cSSalvatore Benedetto static void ecdh_complete(struct crypto_async_request *req, int err)
3458771c1cSSalvatore Benedetto {
3558771c1cSSalvatore Benedetto 	struct ecdh_completion *res = req->data;
3658771c1cSSalvatore Benedetto 
3758771c1cSSalvatore Benedetto 	if (err == -EINPROGRESS)
3858771c1cSSalvatore Benedetto 		return;
3958771c1cSSalvatore Benedetto 
4058771c1cSSalvatore Benedetto 	res->err = err;
4158771c1cSSalvatore Benedetto 	complete(&res->completion);
4258771c1cSSalvatore Benedetto }
4358771c1cSSalvatore Benedetto 
4458771c1cSSalvatore Benedetto static inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits)
4558771c1cSSalvatore Benedetto {
4658771c1cSSalvatore Benedetto 	int i;
4758771c1cSSalvatore Benedetto 
4858771c1cSSalvatore Benedetto 	for (i = 0; i < ndigits; i++)
4958771c1cSSalvatore Benedetto 		out[i] = __swab64(in[ndigits - 1 - i]);
5058771c1cSSalvatore Benedetto }
5158771c1cSSalvatore Benedetto 
52*47eb2ac8STudor Ambarus bool compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64],
53*47eb2ac8STudor Ambarus 			 const u8 private_key[32], u8 secret[32])
5458771c1cSSalvatore Benedetto {
5558771c1cSSalvatore Benedetto 	struct kpp_request *req;
5658771c1cSSalvatore Benedetto 	struct ecdh p;
5758771c1cSSalvatore Benedetto 	struct ecdh_completion result;
5858771c1cSSalvatore Benedetto 	struct scatterlist src, dst;
59763d9a30SSalvatore Benedetto 	u8 *tmp, *buf;
6058771c1cSSalvatore Benedetto 	unsigned int buf_len;
6158771c1cSSalvatore Benedetto 	int err = -ENOMEM;
6258771c1cSSalvatore Benedetto 
63763d9a30SSalvatore Benedetto 	tmp = kmalloc(64, GFP_KERNEL);
64763d9a30SSalvatore Benedetto 	if (!tmp)
65763d9a30SSalvatore Benedetto 		return false;
66763d9a30SSalvatore Benedetto 
6758771c1cSSalvatore Benedetto 	req = kpp_request_alloc(tfm, GFP_KERNEL);
6858771c1cSSalvatore Benedetto 	if (!req)
69*47eb2ac8STudor Ambarus 		goto free_tmp;
7058771c1cSSalvatore Benedetto 
7158771c1cSSalvatore Benedetto 	init_completion(&result.completion);
7258771c1cSSalvatore Benedetto 
7358771c1cSSalvatore Benedetto 	/* Security Manager Protocol holds digits in litte-endian order
7458771c1cSSalvatore Benedetto 	 * while ECC API expect big-endian data
7558771c1cSSalvatore Benedetto 	 */
7658771c1cSSalvatore Benedetto 	swap_digits((u64 *)private_key, (u64 *)tmp, 4);
7758771c1cSSalvatore Benedetto 	p.key = (char *)tmp;
7858771c1cSSalvatore Benedetto 	p.key_size = 32;
7958771c1cSSalvatore Benedetto 	/* Set curve_id */
8058771c1cSSalvatore Benedetto 	p.curve_id = ECC_CURVE_NIST_P256;
8158771c1cSSalvatore Benedetto 	buf_len = crypto_ecdh_key_len(&p);
8258771c1cSSalvatore Benedetto 	buf = kmalloc(buf_len, GFP_KERNEL);
835d4acfc1SMarkus Elfring 	if (!buf)
8458771c1cSSalvatore Benedetto 		goto free_req;
855d4acfc1SMarkus Elfring 
8658771c1cSSalvatore Benedetto 	crypto_ecdh_encode_key(buf, buf_len, &p);
8758771c1cSSalvatore Benedetto 
8858771c1cSSalvatore Benedetto 	/* Set A private Key */
8958771c1cSSalvatore Benedetto 	err = crypto_kpp_set_secret(tfm, (void *)buf, buf_len);
9058771c1cSSalvatore Benedetto 	if (err)
9158771c1cSSalvatore Benedetto 		goto free_all;
9258771c1cSSalvatore Benedetto 
9358771c1cSSalvatore Benedetto 	swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */
9458771c1cSSalvatore Benedetto 	swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */
9558771c1cSSalvatore Benedetto 
9658771c1cSSalvatore Benedetto 	sg_init_one(&src, tmp, 64);
9758771c1cSSalvatore Benedetto 	sg_init_one(&dst, secret, 32);
9858771c1cSSalvatore Benedetto 	kpp_request_set_input(req, &src, 64);
9958771c1cSSalvatore Benedetto 	kpp_request_set_output(req, &dst, 32);
10058771c1cSSalvatore Benedetto 	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
10158771c1cSSalvatore Benedetto 				 ecdh_complete, &result);
10258771c1cSSalvatore Benedetto 	err = crypto_kpp_compute_shared_secret(req);
10358771c1cSSalvatore Benedetto 	if (err == -EINPROGRESS) {
10458771c1cSSalvatore Benedetto 		wait_for_completion(&result.completion);
10558771c1cSSalvatore Benedetto 		err = result.err;
10658771c1cSSalvatore Benedetto 	}
10758771c1cSSalvatore Benedetto 	if (err < 0) {
10858771c1cSSalvatore Benedetto 		pr_err("alg: ecdh: compute shared secret failed. err %d\n",
10958771c1cSSalvatore Benedetto 		       err);
11058771c1cSSalvatore Benedetto 		goto free_all;
11158771c1cSSalvatore Benedetto 	}
11258771c1cSSalvatore Benedetto 
11358771c1cSSalvatore Benedetto 	swap_digits((u64 *)secret, (u64 *)tmp, 4);
11458771c1cSSalvatore Benedetto 	memcpy(secret, tmp, 32);
11558771c1cSSalvatore Benedetto 
11658771c1cSSalvatore Benedetto free_all:
11758771c1cSSalvatore Benedetto 	kzfree(buf);
11858771c1cSSalvatore Benedetto free_req:
11958771c1cSSalvatore Benedetto 	kpp_request_free(req);
120763d9a30SSalvatore Benedetto free_tmp:
121763d9a30SSalvatore Benedetto 	kfree(tmp);
12258771c1cSSalvatore Benedetto 	return (err == 0);
12358771c1cSSalvatore Benedetto }
12458771c1cSSalvatore Benedetto 
125*47eb2ac8STudor Ambarus bool generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64],
126*47eb2ac8STudor Ambarus 			u8 private_key[32])
12758771c1cSSalvatore Benedetto {
12858771c1cSSalvatore Benedetto 	struct kpp_request *req;
12958771c1cSSalvatore Benedetto 	struct ecdh p;
13058771c1cSSalvatore Benedetto 	struct ecdh_completion result;
13158771c1cSSalvatore Benedetto 	struct scatterlist dst;
132763d9a30SSalvatore Benedetto 	u8 *tmp, *buf;
13358771c1cSSalvatore Benedetto 	unsigned int buf_len;
13458771c1cSSalvatore Benedetto 	int err = -ENOMEM;
13558771c1cSSalvatore Benedetto 	const unsigned short max_tries = 16;
13658771c1cSSalvatore Benedetto 	unsigned short tries = 0;
13758771c1cSSalvatore Benedetto 
138763d9a30SSalvatore Benedetto 	tmp = kmalloc(64, GFP_KERNEL);
139763d9a30SSalvatore Benedetto 	if (!tmp)
140763d9a30SSalvatore Benedetto 		return false;
141763d9a30SSalvatore Benedetto 
14258771c1cSSalvatore Benedetto 	req = kpp_request_alloc(tfm, GFP_KERNEL);
14358771c1cSSalvatore Benedetto 	if (!req)
144*47eb2ac8STudor Ambarus 		goto free_tmp;
14558771c1cSSalvatore Benedetto 
14658771c1cSSalvatore Benedetto 	init_completion(&result.completion);
14758771c1cSSalvatore Benedetto 
14858771c1cSSalvatore Benedetto 	/* Set curve_id */
14958771c1cSSalvatore Benedetto 	p.curve_id = ECC_CURVE_NIST_P256;
15058771c1cSSalvatore Benedetto 	p.key_size = 32;
15158771c1cSSalvatore Benedetto 	buf_len = crypto_ecdh_key_len(&p);
15258771c1cSSalvatore Benedetto 	buf = kmalloc(buf_len, GFP_KERNEL);
1535d4acfc1SMarkus Elfring 	if (!buf)
15458771c1cSSalvatore Benedetto 		goto free_req;
15558771c1cSSalvatore Benedetto 
15658771c1cSSalvatore Benedetto 	do {
15758771c1cSSalvatore Benedetto 		if (tries++ >= max_tries)
15858771c1cSSalvatore Benedetto 			goto free_all;
15958771c1cSSalvatore Benedetto 
16058771c1cSSalvatore Benedetto 		/* Set private Key */
16158771c1cSSalvatore Benedetto 		p.key = (char *)private_key;
16258771c1cSSalvatore Benedetto 		crypto_ecdh_encode_key(buf, buf_len, &p);
16358771c1cSSalvatore Benedetto 		err = crypto_kpp_set_secret(tfm, buf, buf_len);
16458771c1cSSalvatore Benedetto 		if (err)
16558771c1cSSalvatore Benedetto 			goto free_all;
16658771c1cSSalvatore Benedetto 
16758771c1cSSalvatore Benedetto 		sg_init_one(&dst, tmp, 64);
168f9583153SMarcel Holtmann 		kpp_request_set_input(req, NULL, 0);
16958771c1cSSalvatore Benedetto 		kpp_request_set_output(req, &dst, 64);
17058771c1cSSalvatore Benedetto 		kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
17158771c1cSSalvatore Benedetto 					 ecdh_complete, &result);
17258771c1cSSalvatore Benedetto 
17358771c1cSSalvatore Benedetto 		err = crypto_kpp_generate_public_key(req);
17458771c1cSSalvatore Benedetto 
17558771c1cSSalvatore Benedetto 		if (err == -EINPROGRESS) {
17658771c1cSSalvatore Benedetto 			wait_for_completion(&result.completion);
17758771c1cSSalvatore Benedetto 			err = result.err;
17858771c1cSSalvatore Benedetto 		}
17958771c1cSSalvatore Benedetto 
18058771c1cSSalvatore Benedetto 		/* Private key is not valid. Regenerate */
18158771c1cSSalvatore Benedetto 		if (err == -EINVAL)
18258771c1cSSalvatore Benedetto 			continue;
18358771c1cSSalvatore Benedetto 
18458771c1cSSalvatore Benedetto 		if (err < 0)
18558771c1cSSalvatore Benedetto 			goto free_all;
18658771c1cSSalvatore Benedetto 		else
18758771c1cSSalvatore Benedetto 			break;
18858771c1cSSalvatore Benedetto 
18958771c1cSSalvatore Benedetto 	} while (true);
19058771c1cSSalvatore Benedetto 
19158771c1cSSalvatore Benedetto 	/* Keys are handed back in little endian as expected by Security
19258771c1cSSalvatore Benedetto 	 * Manager Protocol
19358771c1cSSalvatore Benedetto 	 */
19458771c1cSSalvatore Benedetto 	swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */
19558771c1cSSalvatore Benedetto 	swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */
19658771c1cSSalvatore Benedetto 	swap_digits((u64 *)private_key, (u64 *)tmp, 4);
19758771c1cSSalvatore Benedetto 	memcpy(private_key, tmp, 32);
19858771c1cSSalvatore Benedetto 
19958771c1cSSalvatore Benedetto free_all:
20058771c1cSSalvatore Benedetto 	kzfree(buf);
20158771c1cSSalvatore Benedetto free_req:
20258771c1cSSalvatore Benedetto 	kpp_request_free(req);
203763d9a30SSalvatore Benedetto free_tmp:
204763d9a30SSalvatore Benedetto 	kfree(tmp);
20558771c1cSSalvatore Benedetto 	return (err == 0);
20658771c1cSSalvatore Benedetto }
207