18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * ECDH helper functions - KPP wrappings
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2017 Intel Corporation
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as
88c2ecf20Sopenharmony_ci * published by the Free Software Foundation;
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
118c2ecf20Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
128c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
138c2ecf20Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
148c2ecf20Sopenharmony_ci * CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
158c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
168c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
178c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
208c2ecf20Sopenharmony_ci * COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
218c2ecf20Sopenharmony_ci * SOFTWARE IS DISCLAIMED.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci#include "ecdh_helper.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
268c2ecf20Sopenharmony_ci#include <crypto/ecdh.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct ecdh_completion {
298c2ecf20Sopenharmony_ci	struct completion completion;
308c2ecf20Sopenharmony_ci	int err;
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic void ecdh_complete(struct crypto_async_request *req, int err)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	struct ecdh_completion *res = req->data;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (err == -EINPROGRESS)
388c2ecf20Sopenharmony_ci		return;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	res->err = err;
418c2ecf20Sopenharmony_ci	complete(&res->completion);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline void swap_digits(u64 *in, u64 *out, unsigned int ndigits)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	int i;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	for (i = 0; i < ndigits; i++)
498c2ecf20Sopenharmony_ci		out[i] = __swab64(in[ndigits - 1 - i]);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* compute_ecdh_secret() - function assumes that the private key was
538c2ecf20Sopenharmony_ci *                         already set.
548c2ecf20Sopenharmony_ci * @tfm:          KPP tfm handle allocated with crypto_alloc_kpp().
558c2ecf20Sopenharmony_ci * @public_key:   pair's ecc public key.
568c2ecf20Sopenharmony_ci * secret:        memory where the ecdh computed shared secret will be saved.
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci * Return: zero on success; error code in case of error.
598c2ecf20Sopenharmony_ci */
608c2ecf20Sopenharmony_ciint compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64],
618c2ecf20Sopenharmony_ci			u8 secret[32])
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct kpp_request *req;
648c2ecf20Sopenharmony_ci	u8 *tmp;
658c2ecf20Sopenharmony_ci	struct ecdh_completion result;
668c2ecf20Sopenharmony_ci	struct scatterlist src, dst;
678c2ecf20Sopenharmony_ci	int err;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	tmp = kmalloc(64, GFP_KERNEL);
708c2ecf20Sopenharmony_ci	if (!tmp)
718c2ecf20Sopenharmony_ci		return -ENOMEM;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	req = kpp_request_alloc(tfm, GFP_KERNEL);
748c2ecf20Sopenharmony_ci	if (!req) {
758c2ecf20Sopenharmony_ci		err = -ENOMEM;
768c2ecf20Sopenharmony_ci		goto free_tmp;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	init_completion(&result.completion);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */
828c2ecf20Sopenharmony_ci	swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	sg_init_one(&src, tmp, 64);
858c2ecf20Sopenharmony_ci	sg_init_one(&dst, secret, 32);
868c2ecf20Sopenharmony_ci	kpp_request_set_input(req, &src, 64);
878c2ecf20Sopenharmony_ci	kpp_request_set_output(req, &dst, 32);
888c2ecf20Sopenharmony_ci	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
898c2ecf20Sopenharmony_ci				 ecdh_complete, &result);
908c2ecf20Sopenharmony_ci	err = crypto_kpp_compute_shared_secret(req);
918c2ecf20Sopenharmony_ci	if (err == -EINPROGRESS) {
928c2ecf20Sopenharmony_ci		wait_for_completion(&result.completion);
938c2ecf20Sopenharmony_ci		err = result.err;
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci	if (err < 0) {
968c2ecf20Sopenharmony_ci		pr_err("alg: ecdh: compute shared secret failed. err %d\n",
978c2ecf20Sopenharmony_ci		       err);
988c2ecf20Sopenharmony_ci		goto free_all;
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	swap_digits((u64 *)secret, (u64 *)tmp, 4);
1028c2ecf20Sopenharmony_ci	memcpy(secret, tmp, 32);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cifree_all:
1058c2ecf20Sopenharmony_ci	kpp_request_free(req);
1068c2ecf20Sopenharmony_cifree_tmp:
1078c2ecf20Sopenharmony_ci	kfree_sensitive(tmp);
1088c2ecf20Sopenharmony_ci	return err;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/* set_ecdh_privkey() - set or generate ecc private key.
1128c2ecf20Sopenharmony_ci *
1138c2ecf20Sopenharmony_ci * Function generates an ecc private key in the crypto subsystem when receiving
1148c2ecf20Sopenharmony_ci * a NULL private key or sets the received key when not NULL.
1158c2ecf20Sopenharmony_ci *
1168c2ecf20Sopenharmony_ci * @tfm:           KPP tfm handle allocated with crypto_alloc_kpp().
1178c2ecf20Sopenharmony_ci * @private_key:   user's ecc private key. When not NULL, the key is expected
1188c2ecf20Sopenharmony_ci *                 in little endian format.
1198c2ecf20Sopenharmony_ci *
1208c2ecf20Sopenharmony_ci * Return: zero on success; error code in case of error.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_ciint set_ecdh_privkey(struct crypto_kpp *tfm, const u8 private_key[32])
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	u8 *buf, *tmp = NULL;
1258c2ecf20Sopenharmony_ci	unsigned int buf_len;
1268c2ecf20Sopenharmony_ci	int err;
1278c2ecf20Sopenharmony_ci	struct ecdh p = {0};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	p.curve_id = ECC_CURVE_NIST_P256;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (private_key) {
1328c2ecf20Sopenharmony_ci		tmp = kmalloc(32, GFP_KERNEL);
1338c2ecf20Sopenharmony_ci		if (!tmp)
1348c2ecf20Sopenharmony_ci			return -ENOMEM;
1358c2ecf20Sopenharmony_ci		swap_digits((u64 *)private_key, (u64 *)tmp, 4);
1368c2ecf20Sopenharmony_ci		p.key = tmp;
1378c2ecf20Sopenharmony_ci		p.key_size = 32;
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	buf_len = crypto_ecdh_key_len(&p);
1418c2ecf20Sopenharmony_ci	buf = kmalloc(buf_len, GFP_KERNEL);
1428c2ecf20Sopenharmony_ci	if (!buf) {
1438c2ecf20Sopenharmony_ci		err = -ENOMEM;
1448c2ecf20Sopenharmony_ci		goto free_tmp;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	err = crypto_ecdh_encode_key(buf, buf_len, &p);
1488c2ecf20Sopenharmony_ci	if (err)
1498c2ecf20Sopenharmony_ci		goto free_all;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	err = crypto_kpp_set_secret(tfm, buf, buf_len);
1528c2ecf20Sopenharmony_ci	/* fall through */
1538c2ecf20Sopenharmony_cifree_all:
1548c2ecf20Sopenharmony_ci	kfree_sensitive(buf);
1558c2ecf20Sopenharmony_cifree_tmp:
1568c2ecf20Sopenharmony_ci	kfree_sensitive(tmp);
1578c2ecf20Sopenharmony_ci	return err;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/* generate_ecdh_public_key() - function assumes that the private key was
1618c2ecf20Sopenharmony_ci *                              already set.
1628c2ecf20Sopenharmony_ci *
1638c2ecf20Sopenharmony_ci * @tfm:          KPP tfm handle allocated with crypto_alloc_kpp().
1648c2ecf20Sopenharmony_ci * @public_key:   memory where the computed ecc public key will be saved.
1658c2ecf20Sopenharmony_ci *
1668c2ecf20Sopenharmony_ci * Return: zero on success; error code in case of error.
1678c2ecf20Sopenharmony_ci */
1688c2ecf20Sopenharmony_ciint generate_ecdh_public_key(struct crypto_kpp *tfm, u8 public_key[64])
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	struct kpp_request *req;
1718c2ecf20Sopenharmony_ci	u8 *tmp;
1728c2ecf20Sopenharmony_ci	struct ecdh_completion result;
1738c2ecf20Sopenharmony_ci	struct scatterlist dst;
1748c2ecf20Sopenharmony_ci	int err;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	tmp = kmalloc(64, GFP_KERNEL);
1778c2ecf20Sopenharmony_ci	if (!tmp)
1788c2ecf20Sopenharmony_ci		return -ENOMEM;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	req = kpp_request_alloc(tfm, GFP_KERNEL);
1818c2ecf20Sopenharmony_ci	if (!req) {
1828c2ecf20Sopenharmony_ci		err = -ENOMEM;
1838c2ecf20Sopenharmony_ci		goto free_tmp;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	init_completion(&result.completion);
1878c2ecf20Sopenharmony_ci	sg_init_one(&dst, tmp, 64);
1888c2ecf20Sopenharmony_ci	kpp_request_set_input(req, NULL, 0);
1898c2ecf20Sopenharmony_ci	kpp_request_set_output(req, &dst, 64);
1908c2ecf20Sopenharmony_ci	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
1918c2ecf20Sopenharmony_ci				 ecdh_complete, &result);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	err = crypto_kpp_generate_public_key(req);
1948c2ecf20Sopenharmony_ci	if (err == -EINPROGRESS) {
1958c2ecf20Sopenharmony_ci		wait_for_completion(&result.completion);
1968c2ecf20Sopenharmony_ci		err = result.err;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci	if (err < 0)
1998c2ecf20Sopenharmony_ci		goto free_all;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/* The public key is handed back in little endian as expected by
2028c2ecf20Sopenharmony_ci	 * the Security Manager Protocol.
2038c2ecf20Sopenharmony_ci	 */
2048c2ecf20Sopenharmony_ci	swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */
2058c2ecf20Sopenharmony_ci	swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cifree_all:
2088c2ecf20Sopenharmony_ci	kpp_request_free(req);
2098c2ecf20Sopenharmony_cifree_tmp:
2108c2ecf20Sopenharmony_ci	kfree(tmp);
2118c2ecf20Sopenharmony_ci	return err;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/* generate_ecdh_keys() - generate ecc key pair.
2158c2ecf20Sopenharmony_ci *
2168c2ecf20Sopenharmony_ci * @tfm:          KPP tfm handle allocated with crypto_alloc_kpp().
2178c2ecf20Sopenharmony_ci * @public_key:   memory where the computed ecc public key will be saved.
2188c2ecf20Sopenharmony_ci *
2198c2ecf20Sopenharmony_ci * Return: zero on success; error code in case of error.
2208c2ecf20Sopenharmony_ci */
2218c2ecf20Sopenharmony_ciint generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64])
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	int err;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	err = set_ecdh_privkey(tfm, NULL);
2268c2ecf20Sopenharmony_ci	if (err)
2278c2ecf20Sopenharmony_ci		return err;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	return generate_ecdh_public_key(tfm, public_key);
2308c2ecf20Sopenharmony_ci}
231