xref: /openbmc/linux/net/bluetooth/ecdh_helper.c (revision c0153b0b901a16663ff91504fea25fb51d57cc29)
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*c0153b0bSTudor Ambarus /* compute_ecdh_secret() - function assumes that the private key was
53*c0153b0bSTudor Ambarus  *                         already set.
54*c0153b0bSTudor Ambarus  * @tfm:          KPP tfm handle allocated with crypto_alloc_kpp().
55*c0153b0bSTudor Ambarus  * @public_key:   pair's ecc public key.
56*c0153b0bSTudor Ambarus  * secret:        memory where the ecdh computed shared secret will be saved.
57*c0153b0bSTudor Ambarus  *
58*c0153b0bSTudor Ambarus  * Return: zero on success; error code in case of error.
59*c0153b0bSTudor Ambarus  */
60a2976416STudor Ambarus int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64],
61*c0153b0bSTudor Ambarus 			u8 secret[32])
6258771c1cSSalvatore Benedetto {
6358771c1cSSalvatore Benedetto 	struct kpp_request *req;
64*c0153b0bSTudor Ambarus 	u8 *tmp;
6558771c1cSSalvatore Benedetto 	struct ecdh_completion result;
6658771c1cSSalvatore Benedetto 	struct scatterlist src, dst;
67a2976416STudor Ambarus 	int err;
6858771c1cSSalvatore Benedetto 
69763d9a30SSalvatore Benedetto 	tmp = kmalloc(64, GFP_KERNEL);
70763d9a30SSalvatore Benedetto 	if (!tmp)
71a2976416STudor Ambarus 		return -ENOMEM;
72763d9a30SSalvatore Benedetto 
7358771c1cSSalvatore Benedetto 	req = kpp_request_alloc(tfm, GFP_KERNEL);
74a2976416STudor Ambarus 	if (!req) {
75a2976416STudor Ambarus 		err = -ENOMEM;
7647eb2ac8STudor Ambarus 		goto free_tmp;
77a2976416STudor Ambarus 	}
7858771c1cSSalvatore Benedetto 
7958771c1cSSalvatore Benedetto 	init_completion(&result.completion);
8058771c1cSSalvatore Benedetto 
8158771c1cSSalvatore Benedetto 	swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */
8258771c1cSSalvatore Benedetto 	swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */
8358771c1cSSalvatore Benedetto 
8458771c1cSSalvatore Benedetto 	sg_init_one(&src, tmp, 64);
8558771c1cSSalvatore Benedetto 	sg_init_one(&dst, secret, 32);
8658771c1cSSalvatore Benedetto 	kpp_request_set_input(req, &src, 64);
8758771c1cSSalvatore Benedetto 	kpp_request_set_output(req, &dst, 32);
8858771c1cSSalvatore Benedetto 	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
8958771c1cSSalvatore Benedetto 				 ecdh_complete, &result);
9058771c1cSSalvatore Benedetto 	err = crypto_kpp_compute_shared_secret(req);
9158771c1cSSalvatore Benedetto 	if (err == -EINPROGRESS) {
9258771c1cSSalvatore Benedetto 		wait_for_completion(&result.completion);
9358771c1cSSalvatore Benedetto 		err = result.err;
9458771c1cSSalvatore Benedetto 	}
9558771c1cSSalvatore Benedetto 	if (err < 0) {
9658771c1cSSalvatore Benedetto 		pr_err("alg: ecdh: compute shared secret failed. err %d\n",
9758771c1cSSalvatore Benedetto 		       err);
9858771c1cSSalvatore Benedetto 		goto free_all;
9958771c1cSSalvatore Benedetto 	}
10058771c1cSSalvatore Benedetto 
10158771c1cSSalvatore Benedetto 	swap_digits((u64 *)secret, (u64 *)tmp, 4);
10258771c1cSSalvatore Benedetto 	memcpy(secret, tmp, 32);
10358771c1cSSalvatore Benedetto 
10458771c1cSSalvatore Benedetto free_all:
10558771c1cSSalvatore Benedetto 	kpp_request_free(req);
106763d9a30SSalvatore Benedetto free_tmp:
107168ed654STudor Ambarus 	kzfree(tmp);
108a2976416STudor Ambarus 	return err;
10958771c1cSSalvatore Benedetto }
11058771c1cSSalvatore Benedetto 
111*c0153b0bSTudor Ambarus /* set_ecdh_privkey() - set or generate ecc private key.
112*c0153b0bSTudor Ambarus  *
113*c0153b0bSTudor Ambarus  * Function generates an ecc private key in the crypto subsystem when receiving
114*c0153b0bSTudor Ambarus  * a NULL private key or sets the received key when not NULL.
115*c0153b0bSTudor Ambarus  *
116*c0153b0bSTudor Ambarus  * @tfm:           KPP tfm handle allocated with crypto_alloc_kpp().
117*c0153b0bSTudor Ambarus  * @private_key:   user's ecc private key. When not NULL, the key is expected
118*c0153b0bSTudor Ambarus  *                 in little endian format.
119*c0153b0bSTudor Ambarus  *
120*c0153b0bSTudor Ambarus  * Return: zero on success; error code in case of error.
121*c0153b0bSTudor Ambarus  */
122*c0153b0bSTudor Ambarus int set_ecdh_privkey(struct crypto_kpp *tfm, const u8 private_key[32])
12358771c1cSSalvatore Benedetto {
124*c0153b0bSTudor Ambarus 	u8 *buf, *tmp = NULL;
12558771c1cSSalvatore Benedetto 	unsigned int buf_len;
126a2976416STudor Ambarus 	int err;
127*c0153b0bSTudor Ambarus 	struct ecdh p = {0};
128*c0153b0bSTudor Ambarus 
129*c0153b0bSTudor Ambarus 	p.curve_id = ECC_CURVE_NIST_P256;
130*c0153b0bSTudor Ambarus 
131*c0153b0bSTudor Ambarus 	if (private_key) {
132*c0153b0bSTudor Ambarus 		tmp = kmalloc(32, GFP_KERNEL);
133*c0153b0bSTudor Ambarus 		if (!tmp)
134*c0153b0bSTudor Ambarus 			return -ENOMEM;
135*c0153b0bSTudor Ambarus 		swap_digits((u64 *)private_key, (u64 *)tmp, 4);
136*c0153b0bSTudor Ambarus 		p.key = tmp;
137*c0153b0bSTudor Ambarus 		p.key_size = 32;
138*c0153b0bSTudor Ambarus 	}
139*c0153b0bSTudor Ambarus 
140*c0153b0bSTudor Ambarus 	buf_len = crypto_ecdh_key_len(&p);
141*c0153b0bSTudor Ambarus 	buf = kmalloc(buf_len, GFP_KERNEL);
142*c0153b0bSTudor Ambarus 	if (!buf) {
143*c0153b0bSTudor Ambarus 		err = -ENOMEM;
144*c0153b0bSTudor Ambarus 		goto free_tmp;
145*c0153b0bSTudor Ambarus 	}
146*c0153b0bSTudor Ambarus 
147*c0153b0bSTudor Ambarus 	err = crypto_ecdh_encode_key(buf, buf_len, &p);
148*c0153b0bSTudor Ambarus 	if (err)
149*c0153b0bSTudor Ambarus 		goto free_all;
150*c0153b0bSTudor Ambarus 
151*c0153b0bSTudor Ambarus 	err = crypto_kpp_set_secret(tfm, buf, buf_len);
152*c0153b0bSTudor Ambarus 	/* fall through */
153*c0153b0bSTudor Ambarus free_all:
154*c0153b0bSTudor Ambarus 	kzfree(buf);
155*c0153b0bSTudor Ambarus free_tmp:
156*c0153b0bSTudor Ambarus 	kzfree(tmp);
157*c0153b0bSTudor Ambarus 	return err;
158*c0153b0bSTudor Ambarus }
159*c0153b0bSTudor Ambarus 
160*c0153b0bSTudor Ambarus /* generate_ecdh_public_key() - function assumes that the private key was
161*c0153b0bSTudor Ambarus  *                              already set.
162*c0153b0bSTudor Ambarus  *
163*c0153b0bSTudor Ambarus  * @tfm:          KPP tfm handle allocated with crypto_alloc_kpp().
164*c0153b0bSTudor Ambarus  * @public_key:   memory where the computed ecc public key will be saved.
165*c0153b0bSTudor Ambarus  *
166*c0153b0bSTudor Ambarus  * Return: zero on success; error code in case of error.
167*c0153b0bSTudor Ambarus  */
168*c0153b0bSTudor Ambarus int generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64])
169*c0153b0bSTudor Ambarus {
170*c0153b0bSTudor Ambarus 	struct kpp_request *req;
171*c0153b0bSTudor Ambarus 	u8 *tmp;
172*c0153b0bSTudor Ambarus 	struct ecdh_completion result;
173*c0153b0bSTudor Ambarus 	struct scatterlist dst;
174*c0153b0bSTudor Ambarus 	int err;
17558771c1cSSalvatore Benedetto 
176763d9a30SSalvatore Benedetto 	tmp = kmalloc(64, GFP_KERNEL);
177763d9a30SSalvatore Benedetto 	if (!tmp)
178a2976416STudor Ambarus 		return -ENOMEM;
179763d9a30SSalvatore Benedetto 
18058771c1cSSalvatore Benedetto 	req = kpp_request_alloc(tfm, GFP_KERNEL);
181a2976416STudor Ambarus 	if (!req) {
182a2976416STudor Ambarus 		err = -ENOMEM;
18347eb2ac8STudor Ambarus 		goto free_tmp;
184a2976416STudor Ambarus 	}
18558771c1cSSalvatore Benedetto 
18658771c1cSSalvatore Benedetto 	init_completion(&result.completion);
18758771c1cSSalvatore Benedetto 	sg_init_one(&dst, tmp, 64);
188f9583153SMarcel Holtmann 	kpp_request_set_input(req, NULL, 0);
18958771c1cSSalvatore Benedetto 	kpp_request_set_output(req, &dst, 64);
19058771c1cSSalvatore Benedetto 	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
19158771c1cSSalvatore Benedetto 				 ecdh_complete, &result);
19258771c1cSSalvatore Benedetto 
19358771c1cSSalvatore Benedetto 	err = crypto_kpp_generate_public_key(req);
19458771c1cSSalvatore Benedetto 	if (err == -EINPROGRESS) {
19558771c1cSSalvatore Benedetto 		wait_for_completion(&result.completion);
19658771c1cSSalvatore Benedetto 		err = result.err;
19758771c1cSSalvatore Benedetto 	}
19858771c1cSSalvatore Benedetto 	if (err < 0)
19958771c1cSSalvatore Benedetto 		goto free_all;
20058771c1cSSalvatore Benedetto 
201*c0153b0bSTudor Ambarus 	/* The public key is handed back in little endian as expected by
202*c0153b0bSTudor Ambarus 	 * the Security Manager Protocol.
20358771c1cSSalvatore Benedetto 	 */
20458771c1cSSalvatore Benedetto 	swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */
20558771c1cSSalvatore Benedetto 	swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */
20658771c1cSSalvatore Benedetto 
20758771c1cSSalvatore Benedetto free_all:
20858771c1cSSalvatore Benedetto 	kpp_request_free(req);
209763d9a30SSalvatore Benedetto free_tmp:
210763d9a30SSalvatore Benedetto 	kfree(tmp);
211a2976416STudor Ambarus 	return err;
21258771c1cSSalvatore Benedetto }
213*c0153b0bSTudor Ambarus 
214*c0153b0bSTudor Ambarus /* generate_ecdh_keys() - generate ecc key pair.
215*c0153b0bSTudor Ambarus  *
216*c0153b0bSTudor Ambarus  * @tfm:          KPP tfm handle allocated with crypto_alloc_kpp().
217*c0153b0bSTudor Ambarus  * @public_key:   memory where the computed ecc public key will be saved.
218*c0153b0bSTudor Ambarus  *
219*c0153b0bSTudor Ambarus  * Return: zero on success; error code in case of error.
220*c0153b0bSTudor Ambarus  */
221*c0153b0bSTudor Ambarus int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64])
222*c0153b0bSTudor Ambarus {
223*c0153b0bSTudor Ambarus 	int err;
224*c0153b0bSTudor Ambarus 
225*c0153b0bSTudor Ambarus 	err = set_ecdh_privkey(tfm, NULL);
226*c0153b0bSTudor Ambarus 	if (err)
227*c0153b0bSTudor Ambarus 		return err;
228*c0153b0bSTudor Ambarus 
229*c0153b0bSTudor Ambarus 	return generate_ecdh_public_key(tfm, public_key);
230*c0153b0bSTudor Ambarus }
231