blob: e4857d534344f56c826d6dc4893efbaf932ee72e [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +01002/* ECDH key-agreement protocol
3 *
4 * Copyright (c) 2016, Intel Corporation
5 * Authors: Salvator Benedetto <salvatore.benedetto@intel.com>
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +01006 */
7
8#include <linux/module.h>
Daniele Alessandrellia745d3a2021-10-20 11:35:35 +01009#include <crypto/internal/ecc.h>
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010010#include <crypto/internal/kpp.h>
11#include <crypto/kpp.h>
12#include <crypto/ecdh.h>
13#include <linux/scatterlist.h>
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010014
15struct ecdh_ctx {
16 unsigned int curve_id;
17 unsigned int ndigits;
18 u64 private_key[ECC_MAX_DIGITS];
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010019};
20
21static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm)
22{
23 return kpp_tfm_ctx(tfm);
24}
25
Eric Biggers5527dfb2017-02-24 15:46:58 -080026static int ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
27 unsigned int len)
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010028{
29 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
30 struct ecdh params;
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010031
Ard Biesheuvel0aa171e2021-01-02 14:59:09 +010032 if (crypto_ecdh_decode_key(buf, len, &params) < 0 ||
Meng Yu6763f5e2021-03-04 14:35:46 +080033 params.key_size > sizeof(u64) * ctx->ndigits)
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010034 return -EINVAL;
35
Tudor-Dan Ambarus6755fd22017-05-30 17:52:48 +030036 if (!params.key || !params.key_size)
37 return ecc_gen_privkey(ctx->curve_id, ctx->ndigits,
38 ctx->private_key);
39
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010040 memcpy(ctx->private_key, params.key, params.key_size);
41
Ard Biesheuvel17858b12020-11-24 11:47:19 +010042 if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
43 ctx->private_key, params.key_size) < 0) {
44 memzero_explicit(ctx->private_key, params.key_size);
45 return -EINVAL;
46 }
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010047 return 0;
48}
49
50static int ecdh_compute_value(struct kpp_request *req)
51{
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010052 struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
53 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +030054 u64 *public_key;
55 u64 *shared_secret = NULL;
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010056 void *buf;
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +030057 size_t copied, nbytes, public_key_sz;
58 int ret = -ENOMEM;
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010059
60 nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +030061 /* Public part is a point thus it has both coordinates */
62 public_key_sz = 2 * nbytes;
63
64 public_key = kmalloc(public_key_sz, GFP_KERNEL);
65 if (!public_key)
66 return -ENOMEM;
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010067
68 if (req->src) {
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +030069 shared_secret = kmalloc(nbytes, GFP_KERNEL);
70 if (!shared_secret)
71 goto free_pubkey;
72
James Bottomley95ec01b2018-03-01 14:37:42 -080073 /* from here on it's invalid parameters */
74 ret = -EINVAL;
75
76 /* must have exactly two points to be on the curve */
77 if (public_key_sz != req->src_len)
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +030078 goto free_all;
James Bottomley95ec01b2018-03-01 14:37:42 -080079
80 copied = sg_copy_to_buffer(req->src,
81 sg_nents_for_len(req->src,
82 public_key_sz),
83 public_key, public_key_sz);
84 if (copied != public_key_sz)
85 goto free_all;
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010086
Stephen Rothwell8f44df12016-06-24 16:20:22 +100087 ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +030088 ctx->private_key, public_key,
89 shared_secret);
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010090
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +030091 buf = shared_secret;
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010092 } else {
Tudor-Dan Ambarus7380c562017-05-30 15:37:56 +030093 ret = ecc_make_pub_key(ctx->curve_id, ctx->ndigits,
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +030094 ctx->private_key, public_key);
95 buf = public_key;
96 nbytes = public_key_sz;
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +010097 }
98
99 if (ret < 0)
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +0300100 goto free_all;
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100101
James Bottomley95ec01b2018-03-01 14:37:42 -0800102 /* might want less than we've got */
103 nbytes = min_t(size_t, nbytes, req->dst_len);
104 copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
105 nbytes),
106 buf, nbytes);
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100107 if (copied != nbytes)
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +0300108 ret = -EINVAL;
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100109
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +0300110 /* fall through */
111free_all:
Waiman Long453431a2020-08-06 23:18:13 -0700112 kfree_sensitive(shared_secret);
Tudor-Dan Ambarus952035b2017-07-20 10:37:39 +0300113free_pubkey:
114 kfree(public_key);
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100115 return ret;
116}
117
Tudor-Dan Ambarusd0efb482017-05-25 10:18:10 +0300118static unsigned int ecdh_max_size(struct crypto_kpp *tfm)
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100119{
120 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100121
Tudor-Dan Ambarusd0efb482017-05-25 10:18:10 +0300122 /* Public key is made of two coordinates, add one to the left shift */
123 return ctx->ndigits << (ECC_DIGITS_TO_BYTES_SHIFT + 1);
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100124}
125
Meng Yu6763f5e2021-03-04 14:35:46 +0800126static int ecdh_nist_p192_init_tfm(struct crypto_kpp *tfm)
127{
128 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
129
130 ctx->curve_id = ECC_CURVE_NIST_P192;
131 ctx->ndigits = ECC_CURVE_NIST_P192_DIGITS;
132
133 return 0;
134}
135
136static struct kpp_alg ecdh_nist_p192 = {
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100137 .set_secret = ecdh_set_secret,
138 .generate_public_key = ecdh_compute_value,
139 .compute_shared_secret = ecdh_compute_value,
140 .max_size = ecdh_max_size,
Meng Yu6763f5e2021-03-04 14:35:46 +0800141 .init = ecdh_nist_p192_init_tfm,
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100142 .base = {
Meng Yu6763f5e2021-03-04 14:35:46 +0800143 .cra_name = "ecdh-nist-p192",
Hui Tangc5ae16f2021-05-10 16:59:47 +0800144 .cra_driver_name = "ecdh-nist-p192-generic",
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100145 .cra_priority = 100,
146 .cra_module = THIS_MODULE,
147 .cra_ctxsize = sizeof(struct ecdh_ctx),
148 },
149};
150
Meng Yu6763f5e2021-03-04 14:35:46 +0800151static int ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm)
152{
153 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
154
155 ctx->curve_id = ECC_CURVE_NIST_P256;
156 ctx->ndigits = ECC_CURVE_NIST_P256_DIGITS;
157
158 return 0;
159}
160
161static struct kpp_alg ecdh_nist_p256 = {
162 .set_secret = ecdh_set_secret,
163 .generate_public_key = ecdh_compute_value,
164 .compute_shared_secret = ecdh_compute_value,
165 .max_size = ecdh_max_size,
166 .init = ecdh_nist_p256_init_tfm,
167 .base = {
168 .cra_name = "ecdh-nist-p256",
Hui Tangc5ae16f2021-05-10 16:59:47 +0800169 .cra_driver_name = "ecdh-nist-p256-generic",
Meng Yu6763f5e2021-03-04 14:35:46 +0800170 .cra_priority = 100,
171 .cra_module = THIS_MODULE,
172 .cra_ctxsize = sizeof(struct ecdh_ctx),
173 },
174};
175
Hui Tang81541322021-05-22 10:44:30 +0800176static int ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm)
177{
178 struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
179
180 ctx->curve_id = ECC_CURVE_NIST_P384;
181 ctx->ndigits = ECC_CURVE_NIST_P384_DIGITS;
182
183 return 0;
184}
185
186static struct kpp_alg ecdh_nist_p384 = {
187 .set_secret = ecdh_set_secret,
188 .generate_public_key = ecdh_compute_value,
189 .compute_shared_secret = ecdh_compute_value,
190 .max_size = ecdh_max_size,
191 .init = ecdh_nist_p384_init_tfm,
192 .base = {
193 .cra_name = "ecdh-nist-p384",
194 .cra_driver_name = "ecdh-nist-p384-generic",
195 .cra_priority = 100,
196 .cra_module = THIS_MODULE,
197 .cra_ctxsize = sizeof(struct ecdh_ctx),
198 },
199};
200
Meng Yu6763f5e2021-03-04 14:35:46 +0800201static bool ecdh_nist_p192_registered;
202
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100203static int ecdh_init(void)
204{
Meng Yu6763f5e2021-03-04 14:35:46 +0800205 int ret;
206
Hui Tang6889fc22021-05-22 10:44:28 +0800207 /* NIST p192 will fail to register in FIPS mode */
Meng Yu6763f5e2021-03-04 14:35:46 +0800208 ret = crypto_register_kpp(&ecdh_nist_p192);
209 ecdh_nist_p192_registered = ret == 0;
210
Hui Tang8fd28fa2021-05-22 10:44:29 +0800211 ret = crypto_register_kpp(&ecdh_nist_p256);
212 if (ret)
213 goto nist_p256_error;
214
Hui Tang81541322021-05-22 10:44:30 +0800215 ret = crypto_register_kpp(&ecdh_nist_p384);
216 if (ret)
217 goto nist_p384_error;
218
Hui Tang8fd28fa2021-05-22 10:44:29 +0800219 return 0;
220
Hui Tang81541322021-05-22 10:44:30 +0800221nist_p384_error:
222 crypto_unregister_kpp(&ecdh_nist_p256);
223
Hui Tang8fd28fa2021-05-22 10:44:29 +0800224nist_p256_error:
225 if (ecdh_nist_p192_registered)
226 crypto_unregister_kpp(&ecdh_nist_p192);
227 return ret;
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100228}
229
230static void ecdh_exit(void)
231{
Meng Yu6763f5e2021-03-04 14:35:46 +0800232 if (ecdh_nist_p192_registered)
233 crypto_unregister_kpp(&ecdh_nist_p192);
234 crypto_unregister_kpp(&ecdh_nist_p256);
Hui Tang81541322021-05-22 10:44:30 +0800235 crypto_unregister_kpp(&ecdh_nist_p384);
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100236}
237
Eric Biggersc4741b22019-04-11 21:57:42 -0700238subsys_initcall(ecdh_init);
Salvatore Benedetto3c4b2392016-06-22 17:49:15 +0100239module_exit(ecdh_exit);
240MODULE_ALIAS_CRYPTO("ecdh");
241MODULE_LICENSE("GPL");
242MODULE_DESCRIPTION("ECDH generic algorithm");