1
2
3
4
5
6
7
8
9
10
11
12#include <linux/module.h>
13#include <crypto/internal/kpp.h>
14#include <crypto/kpp.h>
15#include <crypto/dh.h>
16#include <linux/fips.h>
17#include <linux/mpi.h>
18
19struct dh_ctx {
20 MPI p;
21 MPI q;
22 MPI g;
23 MPI xa;
24};
25
26static void dh_clear_ctx(struct dh_ctx *ctx)
27{
28 mpi_free(ctx->p);
29 mpi_free(ctx->q);
30 mpi_free(ctx->g);
31 mpi_free(ctx->xa);
32 memset(ctx, 0, sizeof(*ctx));
33}
34
35
36
37
38
39
40
41static int _compute_val(const struct dh_ctx *ctx, MPI base, MPI val)
42{
43
44 return mpi_powm(val, base, ctx->xa, ctx->p);
45}
46
47static inline struct dh_ctx *dh_get_ctx(struct crypto_kpp *tfm)
48{
49 return kpp_tfm_ctx(tfm);
50}
51
52static int dh_check_params_length(unsigned int p_len)
53{
54 return (p_len < 1536) ? -EINVAL : 0;
55}
56
57static int dh_set_params(struct dh_ctx *ctx, struct dh *params)
58{
59 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
66 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
72 ctx->g = mpi_read_raw_data(params->g, params->g_size);
73 if (!ctx->g)
74 return -EINVAL;
75
76 return 0;
77}
78
79static int dh_set_secret(struct crypto_kpp *tfm, const void *buf,
80 unsigned int len)
81{
82 struct dh_ctx *ctx = dh_get_ctx(tfm);
83 struct dh params;
84
85
86 dh_clear_ctx(ctx);
87
88 if (crypto_dh_decode_key(buf, len, ¶ms) < 0)
89 goto err_clear_ctx;
90
91 if (dh_set_params(ctx, ¶ms) < 0)
92 goto err_clear_ctx;
93
94 ctx->xa = mpi_read_raw_data(params.key, params.key_size);
95 if (!ctx->xa)
96 goto err_clear_ctx;
97
98 return 0;
99
100err_clear_ctx:
101 dh_clear_ctx(ctx);
102 return -EINVAL;
103}
104
105
106
107
108
109
110
111
112
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
121
122
123
124
125 if (mpi_cmp_ui(y, 1) < 1 || mpi_cmp(y, ctx->p) >= 0)
126 return -EINVAL;
127
128
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
154static 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) {
173 ret = -EINVAL;
174 goto err_free_val;
175 }
176 ret = dh_is_pubkey_valid(ctx, base);
177 if (ret)
178 goto err_free_base;
179 } else {
180 base = ctx->g;
181 }
182
183 ret = _compute_val(ctx, base, val);
184 if (ret)
185 goto err_free_base;
186
187 if (fips_enabled) {
188
189 if (req->src) {
190 MPI pone;
191
192
193 if (mpi_cmp_ui(val, 1) < 1) {
194 ret = -EBADMSG;
195 goto err_free_base;
196 }
197
198
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
216 } else {
217 if (dh_is_pubkey_valid(ctx, val)) {
218 ret = -EAGAIN;
219 goto err_free_val;
220 }
221 }
222 }
223
224 ret = mpi_write_to_sgl(val, req->dst, req->dst_len, &sign);
225 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
238static unsigned int dh_max_size(struct crypto_kpp *tfm)
239{
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
249 dh_clear_ctx(ctx);
250}
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
277module_init(dh_init);
278module_exit(dh_exit);
279MODULE_ALIAS_CRYPTO("dh");
280MODULE_LICENSE("GPL");
281MODULE_DESCRIPTION("DH generic algorithm");
282