xref: /openbsd/lib/libssl/ssl_kex.c (revision 6fe5ec74)
1 /* $OpenBSD: ssl_kex.c,v 1.12 2023/07/28 16:02:34 tb Exp $ */
2 /*
3  * Copyright (c) 2020, 2021 Joel Sing <jsing@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <stdlib.h>
19 
20 #include <openssl/bn.h>
21 #include <openssl/dh.h>
22 #include <openssl/ec.h>
23 #include <openssl/evp.h>
24 #include <openssl/objects.h>
25 
26 #include "bytestring.h"
27 
28 #define DHE_MINIMUM_BITS	1024
29 
30 int
ssl_kex_generate_dhe(DH * dh,DH * dh_params)31 ssl_kex_generate_dhe(DH *dh, DH *dh_params)
32 {
33 	BIGNUM *p = NULL, *g = NULL;
34 	int ret = 0;
35 
36 	if ((p = BN_dup(DH_get0_p(dh_params))) == NULL)
37 		goto err;
38 	if ((g = BN_dup(DH_get0_g(dh_params))) == NULL)
39 		goto err;
40 
41 	if (!DH_set0_pqg(dh, p, NULL, g))
42 		goto err;
43 	p = NULL;
44 	g = NULL;
45 
46 	if (!DH_generate_key(dh))
47 		goto err;
48 
49 	ret = 1;
50 
51  err:
52 	BN_free(p);
53 	BN_free(g);
54 
55 	return ret;
56 }
57 
58 int
ssl_kex_generate_dhe_params_auto(DH * dh,size_t key_bits)59 ssl_kex_generate_dhe_params_auto(DH *dh, size_t key_bits)
60 {
61 	BIGNUM *p = NULL, *g = NULL;
62 	int ret = 0;
63 
64 	if (key_bits >= 8192)
65 		p = BN_get_rfc3526_prime_8192(NULL);
66 	else if (key_bits >= 4096)
67 		p = BN_get_rfc3526_prime_4096(NULL);
68 	else if (key_bits >= 3072)
69 		p = BN_get_rfc3526_prime_3072(NULL);
70 	else if (key_bits >= 2048)
71 		p = BN_get_rfc3526_prime_2048(NULL);
72 	else if (key_bits >= 1536)
73 		p = BN_get_rfc3526_prime_1536(NULL);
74 	else
75 		p = BN_get_rfc2409_prime_1024(NULL);
76 
77 	if (p == NULL)
78 		goto err;
79 
80 	if ((g = BN_new()) == NULL)
81 		goto err;
82 	if (!BN_set_word(g, 2))
83 		goto err;
84 
85 	if (!DH_set0_pqg(dh, p, NULL, g))
86 		goto err;
87 	p = NULL;
88 	g = NULL;
89 
90 	if (!DH_generate_key(dh))
91 		goto err;
92 
93 	ret = 1;
94 
95  err:
96 	BN_free(p);
97 	BN_free(g);
98 
99 	return ret;
100 }
101 
102 int
ssl_kex_params_dhe(DH * dh,CBB * cbb)103 ssl_kex_params_dhe(DH *dh, CBB *cbb)
104 {
105 	int dh_p_len, dh_g_len;
106 	CBB dh_p, dh_g;
107 	uint8_t *data;
108 
109 	if ((dh_p_len = BN_num_bytes(DH_get0_p(dh))) <= 0)
110 		return 0;
111 	if ((dh_g_len = BN_num_bytes(DH_get0_g(dh))) <= 0)
112 		return 0;
113 
114 	if (!CBB_add_u16_length_prefixed(cbb, &dh_p))
115 		return 0;
116 	if (!CBB_add_space(&dh_p, &data, dh_p_len))
117 		return 0;
118 	if (BN_bn2bin(DH_get0_p(dh), data) != dh_p_len)
119 		return 0;
120 
121 	if (!CBB_add_u16_length_prefixed(cbb, &dh_g))
122 		return 0;
123 	if (!CBB_add_space(&dh_g, &data, dh_g_len))
124 		return 0;
125 	if (BN_bn2bin(DH_get0_g(dh), data) != dh_g_len)
126 		return 0;
127 
128 	if (!CBB_flush(cbb))
129 		return 0;
130 
131 	return 1;
132 }
133 
134 int
ssl_kex_public_dhe(DH * dh,CBB * cbb)135 ssl_kex_public_dhe(DH *dh, CBB *cbb)
136 {
137 	uint8_t *data;
138 	int dh_y_len;
139 	CBB dh_y;
140 
141 	if ((dh_y_len = BN_num_bytes(DH_get0_pub_key(dh))) <= 0)
142 		return 0;
143 
144 	if (!CBB_add_u16_length_prefixed(cbb, &dh_y))
145 		return 0;
146 	if (!CBB_add_space(&dh_y, &data, dh_y_len))
147 		return 0;
148 	if (BN_bn2bin(DH_get0_pub_key(dh), data) != dh_y_len)
149 		return 0;
150 
151 	if (!CBB_flush(cbb))
152 		return 0;
153 
154 	return 1;
155 }
156 
157 int
ssl_kex_peer_params_dhe(DH * dh,CBS * cbs,int * decode_error,int * invalid_params)158 ssl_kex_peer_params_dhe(DH *dh, CBS *cbs, int *decode_error,
159     int *invalid_params)
160 {
161 	BIGNUM *p = NULL, *g = NULL;
162 	CBS dh_p, dh_g;
163 	int ret = 0;
164 
165 	*decode_error = 0;
166 	*invalid_params = 0;
167 
168 	if (!CBS_get_u16_length_prefixed(cbs, &dh_p)) {
169 		*decode_error = 1;
170 		goto err;
171 	}
172 	if (!CBS_get_u16_length_prefixed(cbs, &dh_g)) {
173 		*decode_error = 1;
174 		goto err;
175 	}
176 
177 	if ((p = BN_bin2bn(CBS_data(&dh_p), CBS_len(&dh_p), NULL)) == NULL)
178 		goto err;
179 	if ((g = BN_bin2bn(CBS_data(&dh_g), CBS_len(&dh_g), NULL)) == NULL)
180 		goto err;
181 
182 	if (!DH_set0_pqg(dh, p, NULL, g))
183 		goto err;
184 	p = NULL;
185 	g = NULL;
186 
187 	/* XXX - consider calling DH_check(). */
188 
189 	if (DH_bits(dh) < DHE_MINIMUM_BITS)
190 		*invalid_params = 1;
191 
192 	ret = 1;
193 
194  err:
195 	BN_free(p);
196 	BN_free(g);
197 
198 	return ret;
199 }
200 
201 int
ssl_kex_peer_public_dhe(DH * dh,CBS * cbs,int * decode_error,int * invalid_key)202 ssl_kex_peer_public_dhe(DH *dh, CBS *cbs, int *decode_error,
203     int *invalid_key)
204 {
205 	BIGNUM *pub_key = NULL;
206 	int check_flags;
207 	CBS dh_y;
208 	int ret = 0;
209 
210 	*decode_error = 0;
211 	*invalid_key = 0;
212 
213 	if (!CBS_get_u16_length_prefixed(cbs, &dh_y)) {
214 		*decode_error = 1;
215 		goto err;
216 	}
217 
218 	if ((pub_key = BN_bin2bn(CBS_data(&dh_y), CBS_len(&dh_y),
219 	    NULL)) == NULL)
220 		goto err;
221 
222 	if (!DH_set0_key(dh, pub_key, NULL))
223 		goto err;
224 	pub_key = NULL;
225 
226 	if (!DH_check_pub_key(dh, DH_get0_pub_key(dh), &check_flags))
227 		goto err;
228 	if (check_flags != 0)
229 		*invalid_key = 1;
230 
231 	ret = 1;
232 
233  err:
234 	BN_free(pub_key);
235 
236 	return ret;
237 }
238 
239 int
ssl_kex_derive_dhe(DH * dh,DH * dh_peer,uint8_t ** shared_key,size_t * shared_key_len)240 ssl_kex_derive_dhe(DH *dh, DH *dh_peer,
241     uint8_t **shared_key, size_t *shared_key_len)
242 {
243 	uint8_t *key = NULL;
244 	int key_len = 0;
245 	int ret = 0;
246 
247 	if ((key_len = DH_size(dh)) <= 0)
248 		goto err;
249 	if ((key = calloc(1, key_len)) == NULL)
250 		goto err;
251 
252 	if ((key_len = DH_compute_key(key, DH_get0_pub_key(dh_peer), dh)) <= 0)
253 		goto err;
254 
255 	*shared_key = key;
256 	*shared_key_len = key_len;
257 	key = NULL;
258 
259 	ret = 1;
260 
261  err:
262 	freezero(key, key_len);
263 
264 	return ret;
265 }
266 
267 int
ssl_kex_dummy_ecdhe_x25519(EVP_PKEY * pkey)268 ssl_kex_dummy_ecdhe_x25519(EVP_PKEY *pkey)
269 {
270 	EC_GROUP *group = NULL;
271 	EC_POINT *point = NULL;
272 	EC_KEY *ec_key = NULL;
273 	BIGNUM *order = NULL;
274 	int ret = 0;
275 
276 	/* Fudge up an EC_KEY that looks like X25519... */
277 	if ((group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) == NULL)
278 		goto err;
279 	if ((point = EC_POINT_new(group)) == NULL)
280 		goto err;
281 	if ((order = BN_new()) == NULL)
282 		goto err;
283 	if (!BN_set_bit(order, 252))
284 		goto err;
285 	if (!EC_GROUP_set_generator(group, point, order, NULL))
286 		goto err;
287 	EC_GROUP_set_curve_name(group, NID_X25519);
288 	if ((ec_key = EC_KEY_new()) == NULL)
289 		goto err;
290 	if (!EC_KEY_set_group(ec_key, group))
291 		goto err;
292 	if (!EVP_PKEY_set1_EC_KEY(pkey, ec_key))
293 		goto err;
294 
295 	ret = 1;
296 
297  err:
298 	EC_GROUP_free(group);
299 	EC_POINT_free(point);
300 	EC_KEY_free(ec_key);
301 	BN_free(order);
302 
303 	return ret;
304 }
305 
306 int
ssl_kex_generate_ecdhe_ecp(EC_KEY * ecdh,int nid)307 ssl_kex_generate_ecdhe_ecp(EC_KEY *ecdh, int nid)
308 {
309 	EC_GROUP *group;
310 	int ret = 0;
311 
312 	if ((group = EC_GROUP_new_by_curve_name(nid)) == NULL)
313 		goto err;
314 
315 	if (!EC_KEY_set_group(ecdh, group))
316 		goto err;
317 	if (!EC_KEY_generate_key(ecdh))
318 		goto err;
319 
320 	ret = 1;
321 
322  err:
323 	EC_GROUP_free(group);
324 
325 	return ret;
326 }
327 
328 int
ssl_kex_public_ecdhe_ecp(EC_KEY * ecdh,CBB * cbb)329 ssl_kex_public_ecdhe_ecp(EC_KEY *ecdh, CBB *cbb)
330 {
331 	const EC_GROUP *group;
332 	const EC_POINT *point;
333 	uint8_t *ecp;
334 	size_t ecp_len;
335 	int ret = 0;
336 
337 	if ((group = EC_KEY_get0_group(ecdh)) == NULL)
338 		goto err;
339 	if ((point = EC_KEY_get0_public_key(ecdh)) == NULL)
340 		goto err;
341 
342 	if ((ecp_len = EC_POINT_point2oct(group, point,
343 	    POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL)) == 0)
344 		goto err;
345 	if (!CBB_add_space(cbb, &ecp, ecp_len))
346 		goto err;
347 	if ((EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED,
348 	    ecp, ecp_len, NULL)) == 0)
349 		goto err;
350 
351 	ret = 1;
352 
353  err:
354 	return ret;
355 }
356 
357 int
ssl_kex_peer_public_ecdhe_ecp(EC_KEY * ecdh,int nid,CBS * cbs)358 ssl_kex_peer_public_ecdhe_ecp(EC_KEY *ecdh, int nid, CBS *cbs)
359 {
360 	EC_GROUP *group = NULL;
361 	EC_POINT *point = NULL;
362 	int ret = 0;
363 
364 	if ((group = EC_GROUP_new_by_curve_name(nid)) == NULL)
365 		goto err;
366 
367 	if (!EC_KEY_set_group(ecdh, group))
368 		goto err;
369 
370 	if ((point = EC_POINT_new(group)) == NULL)
371 		goto err;
372 	if (EC_POINT_oct2point(group, point, CBS_data(cbs), CBS_len(cbs),
373 	    NULL) == 0)
374 		goto err;
375 	if (!EC_KEY_set_public_key(ecdh, point))
376 		goto err;
377 
378 	ret = 1;
379 
380  err:
381 	EC_GROUP_free(group);
382 	EC_POINT_free(point);
383 
384 	return ret;
385 }
386 
387 int
ssl_kex_derive_ecdhe_ecp(EC_KEY * ecdh,EC_KEY * ecdh_peer,uint8_t ** shared_key,size_t * shared_key_len)388 ssl_kex_derive_ecdhe_ecp(EC_KEY *ecdh, EC_KEY *ecdh_peer,
389     uint8_t **shared_key, size_t *shared_key_len)
390 {
391 	const EC_POINT *point;
392 	uint8_t *key = NULL;
393 	int key_len = 0;
394 	int ret = 0;
395 
396 	if (!EC_GROUP_check(EC_KEY_get0_group(ecdh), NULL))
397 		goto err;
398 	if (!EC_GROUP_check(EC_KEY_get0_group(ecdh_peer), NULL))
399 		goto err;
400 
401 	if ((point = EC_KEY_get0_public_key(ecdh_peer)) == NULL)
402 		goto err;
403 
404 	if ((key_len = ECDH_size(ecdh)) <= 0)
405 		goto err;
406 	if ((key = calloc(1, key_len)) == NULL)
407 		goto err;
408 
409 	if (ECDH_compute_key(key, key_len, point, ecdh, NULL) <= 0)
410 		goto err;
411 
412 	*shared_key = key;
413 	*shared_key_len = key_len;
414 	key = NULL;
415 
416 	ret = 1;
417 
418  err:
419 	freezero(key, key_len);
420 
421 	return ret;
422 }
423