blob: 38557e64b4b31597b54e32dc89c9c204b58437e7 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Salvatore Benedetto802c7f12016-06-22 17:49:14 +01002/* Diffie-Hellman Key Agreement Method [RFC2631]
3 *
4 * Copyright (c) 2016, Intel Corporation
5 * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
Salvatore Benedetto802c7f12016-06-22 17:49:14 +01006 */
7
Stephan Müller1e146c32021-11-21 15:51:44 +01008#include <linux/fips.h>
Salvatore Benedetto802c7f12016-06-22 17:49:14 +01009#include <linux/module.h>
10#include <crypto/internal/kpp.h>
11#include <crypto/kpp.h>
12#include <crypto/dh.h>
Stephan Müller90fa9ae2020-07-20 19:08:32 +020013#include <linux/fips.h>
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010014#include <linux/mpi.h>
15
16struct dh_ctx {
Stephan Muellere3fe0ae2018-06-27 08:15:31 +020017 MPI p; /* Value is guaranteed to be set. */
18 MPI q; /* Value is optional. */
19 MPI g; /* Value is guaranteed to be set. */
20 MPI xa; /* Value is guaranteed to be set. */
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010021};
22
Eric Biggers12d41a02017-11-05 18:30:44 -080023static void dh_clear_ctx(struct dh_ctx *ctx)
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010024{
25 mpi_free(ctx->p);
Stephan Muellere3fe0ae2018-06-27 08:15:31 +020026 mpi_free(ctx->q);
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010027 mpi_free(ctx->g);
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010028 mpi_free(ctx->xa);
Eric Biggers12d41a02017-11-05 18:30:44 -080029 memset(ctx, 0, sizeof(*ctx));
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010030}
31
32/*
33 * If base is g we compute the public key
34 * ya = g^xa mod p; [RFC2631 sec 2.1.1]
35 * else if base if the counterpart public key we compute the shared secret
36 * ZZ = yb^xa mod p; [RFC2631 sec 2.1.1]
37 */
38static int _compute_val(const struct dh_ctx *ctx, MPI base, MPI val)
39{
40 /* val = base^xa mod p */
41 return mpi_powm(val, base, ctx->xa, ctx->p);
42}
43
44static inline struct dh_ctx *dh_get_ctx(struct crypto_kpp *tfm)
45{
46 return kpp_tfm_ctx(tfm);
47}
48
49static int dh_check_params_length(unsigned int p_len)
50{
Stephan Müller1e146c32021-11-21 15:51:44 +010051 if (fips_enabled)
52 return (p_len < 2048) ? -EINVAL : 0;
53
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010054 return (p_len < 1536) ? -EINVAL : 0;
55}
56
57static int dh_set_params(struct dh_ctx *ctx, struct dh *params)
58{
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010059 if (dh_check_params_length(params->p_size << 3))
60 return -EINVAL;
61
62 ctx->p = mpi_read_raw_data(params->p, params->p_size);
63 if (!ctx->p)
64 return -EINVAL;
65
Stephan Muellere3fe0ae2018-06-27 08:15:31 +020066 if (params->q && params->q_size) {
67 ctx->q = mpi_read_raw_data(params->q, params->q_size);
68 if (!ctx->q)
69 return -EINVAL;
70 }
71
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010072 ctx->g = mpi_read_raw_data(params->g, params->g_size);
Eric Biggers12d41a02017-11-05 18:30:44 -080073 if (!ctx->g)
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010074 return -EINVAL;
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010075
76 return 0;
77}
78
Eric Biggers5527dfb2017-02-24 15:46:58 -080079static int dh_set_secret(struct crypto_kpp *tfm, const void *buf,
80 unsigned int len)
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010081{
82 struct dh_ctx *ctx = dh_get_ctx(tfm);
83 struct dh params;
84
Tudor-Dan Ambarusee34e262017-05-25 10:18:07 +030085 /* Free the old MPI key if any */
Eric Biggers12d41a02017-11-05 18:30:44 -080086 dh_clear_ctx(ctx);
Tudor-Dan Ambarusee34e262017-05-25 10:18:07 +030087
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010088 if (crypto_dh_decode_key(buf, len, &params) < 0)
Eric Biggers12d41a02017-11-05 18:30:44 -080089 goto err_clear_ctx;
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010090
91 if (dh_set_params(ctx, &params) < 0)
Eric Biggers12d41a02017-11-05 18:30:44 -080092 goto err_clear_ctx;
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010093
94 ctx->xa = mpi_read_raw_data(params.key, params.key_size);
Eric Biggers12d41a02017-11-05 18:30:44 -080095 if (!ctx->xa)
96 goto err_clear_ctx;
Salvatore Benedetto802c7f12016-06-22 17:49:14 +010097
98 return 0;
Eric Biggers12d41a02017-11-05 18:30:44 -080099
100err_clear_ctx:
101 dh_clear_ctx(ctx);
102 return -EINVAL;
Salvatore Benedetto802c7f12016-06-22 17:49:14 +0100103}
104
Stephan Muellere3fe0ae2018-06-27 08:15:31 +0200105/*
106 * SP800-56A public key verification:
107 *
108 * * If Q is provided as part of the domain paramenters, a full validation
109 * according to SP800-56A section 5.6.2.3.1 is performed.
110 *
111 * * If Q is not provided, a partial validation according to SP800-56A section
112 * 5.6.2.3.2 is performed.
113 */
114static int dh_is_pubkey_valid(struct dh_ctx *ctx, MPI y)
115{
116 if (unlikely(!ctx->p))
117 return -EINVAL;
118
119 /*
120 * Step 1: Verify that 2 <= y <= p - 2.
121 *
122 * The upper limit check is actually y < p instead of y < p - 1
123 * as the mpi_sub_ui function is yet missing.
124 */
125 if (mpi_cmp_ui(y, 1) < 1 || mpi_cmp(y, ctx->p) >= 0)
126 return -EINVAL;
127
128 /* Step 2: Verify that 1 = y^q mod p */
129 if (ctx->q) {
130 MPI val = mpi_alloc(0);
131 int ret;
132
133 if (!val)
134 return -ENOMEM;
135
136 ret = mpi_powm(val, y, ctx->q, ctx->p);
137
138 if (ret) {
139 mpi_free(val);
140 return ret;
141 }
142
143 ret = mpi_cmp_ui(val, 1);
144
145 mpi_free(val);
146
147 if (ret != 0)
148 return -EINVAL;
149 }
150
151 return 0;
152}
153
Salvatore Benedetto802c7f12016-06-22 17:49:14 +0100154static int dh_compute_value(struct kpp_request *req)
155{
156 struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
157 struct dh_ctx *ctx = dh_get_ctx(tfm);
158 MPI base, val = mpi_alloc(0);
159 int ret = 0;
160 int sign;
161
162 if (!val)
163 return -ENOMEM;
164
165 if (unlikely(!ctx->xa)) {
166 ret = -EINVAL;
167 goto err_free_val;
168 }
169
170 if (req->src) {
171 base = mpi_read_raw_from_sgl(req->src, req->src_len);
172 if (!base) {
Mat Martineau8edda7d2016-11-08 15:48:22 -0800173 ret = -EINVAL;
Salvatore Benedetto802c7f12016-06-22 17:49:14 +0100174 goto err_free_val;
175 }
Stephan Muellere3fe0ae2018-06-27 08:15:31 +0200176 ret = dh_is_pubkey_valid(ctx, base);
177 if (ret)
Gustavo A. R. Silva3fd80932018-07-10 09:22:52 -0500178 goto err_free_base;
Salvatore Benedetto802c7f12016-06-22 17:49:14 +0100179 } else {
180 base = ctx->g;
181 }
182
183 ret = _compute_val(ctx, base, val);
184 if (ret)
185 goto err_free_base;
186
Stephan Müller2ed5ba62020-07-20 19:08:52 +0200187 if (fips_enabled) {
188 /* SP800-56A rev3 5.7.1.1 check: Validation of shared secret */
189 if (req->src) {
190 MPI pone;
Stephan Müller90fa9ae2020-07-20 19:08:32 +0200191
Stephan Müller2ed5ba62020-07-20 19:08:52 +0200192 /* z <= 1 */
193 if (mpi_cmp_ui(val, 1) < 1) {
194 ret = -EBADMSG;
195 goto err_free_base;
196 }
197
198 /* z == p - 1 */
199 pone = mpi_alloc(0);
200
201 if (!pone) {
202 ret = -ENOMEM;
203 goto err_free_base;
204 }
205
206 ret = mpi_sub_ui(pone, ctx->p, 1);
207 if (!ret && !mpi_cmp(pone, val))
208 ret = -EBADMSG;
209
210 mpi_free(pone);
211
212 if (ret)
213 goto err_free_base;
214
215 /* SP800-56A rev 3 5.6.2.1.3 key check */
216 } else {
217 if (dh_is_pubkey_valid(ctx, val)) {
218 ret = -EAGAIN;
219 goto err_free_val;
220 }
Stephan Müller90fa9ae2020-07-20 19:08:32 +0200221 }
Stephan Müller90fa9ae2020-07-20 19:08:32 +0200222 }
223
Herbert Xu9b45b7b2016-06-29 19:32:21 +0800224 ret = mpi_write_to_sgl(val, req->dst, req->dst_len, &sign);
Salvatore Benedetto802c7f12016-06-22 17:49:14 +0100225 if (ret)
226 goto err_free_base;
227
228 if (sign < 0)
229 ret = -EBADMSG;
230err_free_base:
231 if (req->src)
232 mpi_free(base);
233err_free_val:
234 mpi_free(val);
235 return ret;
236}
237
Tudor-Dan Ambarus7f691052017-05-25 10:18:09 +0300238static unsigned int dh_max_size(struct crypto_kpp *tfm)
Salvatore Benedetto802c7f12016-06-22 17:49:14 +0100239{
240 struct dh_ctx *ctx = dh_get_ctx(tfm);
241
242 return mpi_get_size(ctx->p);
243}
244
245static void dh_exit_tfm(struct crypto_kpp *tfm)
246{
247 struct dh_ctx *ctx = dh_get_ctx(tfm);
248
Eric Biggers12d41a02017-11-05 18:30:44 -0800249 dh_clear_ctx(ctx);
Salvatore Benedetto802c7f12016-06-22 17:49:14 +0100250}
251
252static struct kpp_alg dh = {
253 .set_secret = dh_set_secret,
254 .generate_public_key = dh_compute_value,
255 .compute_shared_secret = dh_compute_value,
256 .max_size = dh_max_size,
257 .exit = dh_exit_tfm,
258 .base = {
259 .cra_name = "dh",
260 .cra_driver_name = "dh-generic",
261 .cra_priority = 100,
262 .cra_module = THIS_MODULE,
263 .cra_ctxsize = sizeof(struct dh_ctx),
264 },
265};
266
267static int dh_init(void)
268{
269 return crypto_register_kpp(&dh);
270}
271
272static void dh_exit(void)
273{
274 crypto_unregister_kpp(&dh);
275}
276
Eric Biggersc4741b22019-04-11 21:57:42 -0700277subsys_initcall(dh_init);
Salvatore Benedetto802c7f12016-06-22 17:49:14 +0100278module_exit(dh_exit);
279MODULE_ALIAS_CRYPTO("dh");
280MODULE_LICENSE("GPL");
281MODULE_DESCRIPTION("DH generic algorithm");