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