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*a2976416STudor Ambarus int compute_ecdh_secret(struct crypto_kpp *tfm, const u8 public_key[64], 5347eb2ac8STudor 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; 61*a2976416STudor Ambarus int err; 6258771c1cSSalvatore Benedetto 63763d9a30SSalvatore Benedetto tmp = kmalloc(64, GFP_KERNEL); 64763d9a30SSalvatore Benedetto if (!tmp) 65*a2976416STudor Ambarus return -ENOMEM; 66763d9a30SSalvatore Benedetto 6758771c1cSSalvatore Benedetto req = kpp_request_alloc(tfm, GFP_KERNEL); 68*a2976416STudor Ambarus if (!req) { 69*a2976416STudor Ambarus err = -ENOMEM; 7047eb2ac8STudor Ambarus goto free_tmp; 71*a2976416STudor Ambarus } 7258771c1cSSalvatore Benedetto 7358771c1cSSalvatore Benedetto init_completion(&result.completion); 7458771c1cSSalvatore Benedetto 7558771c1cSSalvatore Benedetto /* Security Manager Protocol holds digits in litte-endian order 7658771c1cSSalvatore Benedetto * while ECC API expect big-endian data 7758771c1cSSalvatore Benedetto */ 7858771c1cSSalvatore Benedetto swap_digits((u64 *)private_key, (u64 *)tmp, 4); 7958771c1cSSalvatore Benedetto p.key = (char *)tmp; 8058771c1cSSalvatore Benedetto p.key_size = 32; 8158771c1cSSalvatore Benedetto /* Set curve_id */ 8258771c1cSSalvatore Benedetto p.curve_id = ECC_CURVE_NIST_P256; 8358771c1cSSalvatore Benedetto buf_len = crypto_ecdh_key_len(&p); 8458771c1cSSalvatore Benedetto buf = kmalloc(buf_len, GFP_KERNEL); 85*a2976416STudor Ambarus if (!buf) { 86*a2976416STudor Ambarus err = -ENOMEM; 8758771c1cSSalvatore Benedetto goto free_req; 88*a2976416STudor Ambarus } 895d4acfc1SMarkus Elfring 9058771c1cSSalvatore Benedetto crypto_ecdh_encode_key(buf, buf_len, &p); 9158771c1cSSalvatore Benedetto 9258771c1cSSalvatore Benedetto /* Set A private Key */ 9358771c1cSSalvatore Benedetto err = crypto_kpp_set_secret(tfm, (void *)buf, buf_len); 9458771c1cSSalvatore Benedetto if (err) 9558771c1cSSalvatore Benedetto goto free_all; 9658771c1cSSalvatore Benedetto 9758771c1cSSalvatore Benedetto swap_digits((u64 *)public_key, (u64 *)tmp, 4); /* x */ 9858771c1cSSalvatore Benedetto swap_digits((u64 *)&public_key[32], (u64 *)&tmp[32], 4); /* y */ 9958771c1cSSalvatore Benedetto 10058771c1cSSalvatore Benedetto sg_init_one(&src, tmp, 64); 10158771c1cSSalvatore Benedetto sg_init_one(&dst, secret, 32); 10258771c1cSSalvatore Benedetto kpp_request_set_input(req, &src, 64); 10358771c1cSSalvatore Benedetto kpp_request_set_output(req, &dst, 32); 10458771c1cSSalvatore Benedetto kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 10558771c1cSSalvatore Benedetto ecdh_complete, &result); 10658771c1cSSalvatore Benedetto err = crypto_kpp_compute_shared_secret(req); 10758771c1cSSalvatore Benedetto if (err == -EINPROGRESS) { 10858771c1cSSalvatore Benedetto wait_for_completion(&result.completion); 10958771c1cSSalvatore Benedetto err = result.err; 11058771c1cSSalvatore Benedetto } 11158771c1cSSalvatore Benedetto if (err < 0) { 11258771c1cSSalvatore Benedetto pr_err("alg: ecdh: compute shared secret failed. err %d\n", 11358771c1cSSalvatore Benedetto err); 11458771c1cSSalvatore Benedetto goto free_all; 11558771c1cSSalvatore Benedetto } 11658771c1cSSalvatore Benedetto 11758771c1cSSalvatore Benedetto swap_digits((u64 *)secret, (u64 *)tmp, 4); 11858771c1cSSalvatore Benedetto memcpy(secret, tmp, 32); 11958771c1cSSalvatore Benedetto 12058771c1cSSalvatore Benedetto free_all: 12158771c1cSSalvatore Benedetto kzfree(buf); 12258771c1cSSalvatore Benedetto free_req: 12358771c1cSSalvatore Benedetto kpp_request_free(req); 124763d9a30SSalvatore Benedetto free_tmp: 125763d9a30SSalvatore Benedetto kfree(tmp); 126*a2976416STudor Ambarus return err; 12758771c1cSSalvatore Benedetto } 12858771c1cSSalvatore Benedetto 129*a2976416STudor Ambarus int generate_ecdh_keys(struct crypto_kpp *tfm, u8 public_key[64], 13047eb2ac8STudor Ambarus u8 private_key[32]) 13158771c1cSSalvatore Benedetto { 13258771c1cSSalvatore Benedetto struct kpp_request *req; 13358771c1cSSalvatore Benedetto struct ecdh p; 13458771c1cSSalvatore Benedetto struct ecdh_completion result; 13558771c1cSSalvatore Benedetto struct scatterlist dst; 136763d9a30SSalvatore Benedetto u8 *tmp, *buf; 13758771c1cSSalvatore Benedetto unsigned int buf_len; 138*a2976416STudor Ambarus int err; 13958771c1cSSalvatore Benedetto const unsigned short max_tries = 16; 14058771c1cSSalvatore Benedetto unsigned short tries = 0; 14158771c1cSSalvatore Benedetto 142763d9a30SSalvatore Benedetto tmp = kmalloc(64, GFP_KERNEL); 143763d9a30SSalvatore Benedetto if (!tmp) 144*a2976416STudor Ambarus return -ENOMEM; 145763d9a30SSalvatore Benedetto 14658771c1cSSalvatore Benedetto req = kpp_request_alloc(tfm, GFP_KERNEL); 147*a2976416STudor Ambarus if (!req) { 148*a2976416STudor Ambarus err = -ENOMEM; 14947eb2ac8STudor Ambarus goto free_tmp; 150*a2976416STudor Ambarus } 15158771c1cSSalvatore Benedetto 15258771c1cSSalvatore Benedetto init_completion(&result.completion); 15358771c1cSSalvatore Benedetto 15458771c1cSSalvatore Benedetto /* Set curve_id */ 15558771c1cSSalvatore Benedetto p.curve_id = ECC_CURVE_NIST_P256; 15658771c1cSSalvatore Benedetto p.key_size = 32; 15758771c1cSSalvatore Benedetto buf_len = crypto_ecdh_key_len(&p); 15858771c1cSSalvatore Benedetto buf = kmalloc(buf_len, GFP_KERNEL); 1595d4acfc1SMarkus Elfring if (!buf) 16058771c1cSSalvatore Benedetto goto free_req; 16158771c1cSSalvatore Benedetto 16258771c1cSSalvatore Benedetto do { 16358771c1cSSalvatore Benedetto if (tries++ >= max_tries) 16458771c1cSSalvatore Benedetto goto free_all; 16558771c1cSSalvatore Benedetto 16658771c1cSSalvatore Benedetto /* Set private Key */ 16758771c1cSSalvatore Benedetto p.key = (char *)private_key; 16858771c1cSSalvatore Benedetto crypto_ecdh_encode_key(buf, buf_len, &p); 16958771c1cSSalvatore Benedetto err = crypto_kpp_set_secret(tfm, buf, buf_len); 17058771c1cSSalvatore Benedetto if (err) 17158771c1cSSalvatore Benedetto goto free_all; 17258771c1cSSalvatore Benedetto 17358771c1cSSalvatore Benedetto sg_init_one(&dst, tmp, 64); 174f9583153SMarcel Holtmann kpp_request_set_input(req, NULL, 0); 17558771c1cSSalvatore Benedetto kpp_request_set_output(req, &dst, 64); 17658771c1cSSalvatore Benedetto kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 17758771c1cSSalvatore Benedetto ecdh_complete, &result); 17858771c1cSSalvatore Benedetto 17958771c1cSSalvatore Benedetto err = crypto_kpp_generate_public_key(req); 18058771c1cSSalvatore Benedetto 18158771c1cSSalvatore Benedetto if (err == -EINPROGRESS) { 18258771c1cSSalvatore Benedetto wait_for_completion(&result.completion); 18358771c1cSSalvatore Benedetto err = result.err; 18458771c1cSSalvatore Benedetto } 18558771c1cSSalvatore Benedetto 18658771c1cSSalvatore Benedetto /* Private key is not valid. Regenerate */ 18758771c1cSSalvatore Benedetto if (err == -EINVAL) 18858771c1cSSalvatore Benedetto continue; 18958771c1cSSalvatore Benedetto 19058771c1cSSalvatore Benedetto if (err < 0) 19158771c1cSSalvatore Benedetto goto free_all; 19258771c1cSSalvatore Benedetto else 19358771c1cSSalvatore Benedetto break; 19458771c1cSSalvatore Benedetto 19558771c1cSSalvatore Benedetto } while (true); 19658771c1cSSalvatore Benedetto 19758771c1cSSalvatore Benedetto /* Keys are handed back in little endian as expected by Security 19858771c1cSSalvatore Benedetto * Manager Protocol 19958771c1cSSalvatore Benedetto */ 20058771c1cSSalvatore Benedetto swap_digits((u64 *)tmp, (u64 *)public_key, 4); /* x */ 20158771c1cSSalvatore Benedetto swap_digits((u64 *)&tmp[32], (u64 *)&public_key[32], 4); /* y */ 20258771c1cSSalvatore Benedetto swap_digits((u64 *)private_key, (u64 *)tmp, 4); 20358771c1cSSalvatore Benedetto memcpy(private_key, tmp, 32); 20458771c1cSSalvatore Benedetto 20558771c1cSSalvatore Benedetto free_all: 20658771c1cSSalvatore Benedetto kzfree(buf); 20758771c1cSSalvatore Benedetto free_req: 20858771c1cSSalvatore Benedetto kpp_request_free(req); 209763d9a30SSalvatore Benedetto free_tmp: 210763d9a30SSalvatore Benedetto kfree(tmp); 211*a2976416STudor Ambarus return err; 21258771c1cSSalvatore Benedetto } 213