dh.c revision 1.26
1/*	$OpenBSD: dh.c,v 1.26 2023/03/28 16:32:42 tb Exp $	*/
2
3/*
4 * Copyright (c) 2010-2014 Reyk Floeter <reyk@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <string.h>
20
21#include <openssl/obj_mac.h>
22#include <openssl/dh.h>
23#include <openssl/ec.h>
24#include <openssl/ecdh.h>
25#include <openssl/bn.h>
26
27#include "dh.h"
28
29#define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
30
31int	dh_init(struct group *);
32
33int	modp_init(struct group *);
34int	modp_getlen(struct group *);
35int	modp_create_exchange(struct group *, u_int8_t *);
36int	modp_create_shared(struct group *, u_int8_t *, u_int8_t *);
37
38int	ec_init(struct group *);
39int	ec_getlen(struct group *);
40int	ec_secretlen(struct group *);
41int	ec_create_exchange(struct group *, u_int8_t *);
42int	ec_create_shared(struct group *, u_int8_t *, u_int8_t *);
43
44#define EC_POINT2RAW_FULL	0
45#define EC_POINT2RAW_XONLY	1
46int	ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t, int);
47EC_POINT *
48	ec_raw2point(struct group *, u_int8_t *, size_t);
49
50struct group_id ike_groups[] = {
51	{ GROUP_MODP, 1, 768,
52	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
53	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
54	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
55	    "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
56	    "02"
57	},
58	{ GROUP_MODP, 2, 1024,
59	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
60	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
61	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
62	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
63	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
64	    "FFFFFFFFFFFFFFFF",
65	    "02"
66	},
67	{ GROUP_EC2N, 3, 155, NULL, NULL, NID_ipsec3 },
68	{ GROUP_EC2N, 4, 185, NULL, NULL, NID_ipsec4 },
69	{ GROUP_MODP, 5, 1536,
70	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
71	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
72	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
73	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
74	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
75	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
76	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
77	    "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
78	    "02"
79	},
80	{ GROUP_MODP, 14, 2048,
81	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
82	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
83	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
84	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
85	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
86	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
87	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
88	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
89	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
90	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
91	    "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
92	    "02"
93	},
94	{ GROUP_MODP, 15, 3072,
95	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
96	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
97	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
98	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
99	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
100	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
101	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
102	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
103	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
104	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
105	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
106	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
107	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
108	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
109	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
110	    "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF",
111	    "02"
112	},
113	{ GROUP_MODP, 16, 4096,
114	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
115	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
116	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
117	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
118	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
119	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
120	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
121	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
122	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
123	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
124	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
125	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
126	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
127	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
128	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
129	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
130	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
131	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
132	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
133	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
134	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
135	    "FFFFFFFFFFFFFFFF",
136	    "02"
137	},
138	{ GROUP_MODP, 17, 6144,
139	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
140	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
141	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
142	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
143	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
144	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
145	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
146	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
147	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
148	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
149	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
150	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
151	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
152	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
153	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
154	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
155	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
156	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
157	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
158	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
159	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
160	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
161	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
162	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
163	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
164	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
165	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
166	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
167	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
168	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
169	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
170	    "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF",
171	    "02"
172	},
173	{ GROUP_MODP, 18, 8192,
174	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
175	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
176	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
177	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
178	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
179	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
180	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
181	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
182	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
183	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
184	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
185	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
186	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
187	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
188	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
189	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
190	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
191	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
192	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
193	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
194	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
195	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
196	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
197	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
198	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
199	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
200	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
201	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
202	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
203	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
204	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
205	    "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
206	    "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
207	    "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
208	    "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
209	    "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
210	    "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
211	    "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
212	    "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
213	    "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
214	    "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
215	    "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
216	    "60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
217	    "02"
218	},
219	{ GROUP_ECP, 19, 256, NULL, NULL, NID_X9_62_prime256v1 },
220	{ GROUP_ECP, 20, 384, NULL, NULL, NID_secp384r1 },
221	{ GROUP_ECP, 21, 521, NULL, NULL, NID_secp521r1 },
222	{ GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 },
223	{ GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 },
224	{ GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 },
225	{ GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 },
226	{ GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 },
227	{ GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 }
228};
229
230void
231group_init(void)
232{
233	/* currently not used */
234	return;
235}
236
237void
238group_free(struct group *group)
239{
240	if (group == NULL)
241		return;
242	if (group->dh != NULL)
243		DH_free(group->dh);
244	if (group->ec != NULL)
245		EC_KEY_free(group->ec);
246	group->spec = NULL;
247	free(group);
248}
249
250struct group *
251group_get(u_int32_t id)
252{
253	struct group_id	*p = NULL;
254	struct group	*group;
255	u_int		 i, items;
256
257	items = sizeof(ike_groups) / sizeof(ike_groups[0]);
258	for (i = 0; i < items; i++) {
259		if (id == ike_groups[i].id) {
260			p = &ike_groups[i];
261			break;
262		}
263	}
264	if (p == NULL)
265		return (NULL);
266
267	if ((group = calloc(1, sizeof(*group))) == NULL)
268		return (NULL);
269
270	group->id = id;
271	group->spec = p;
272
273	switch (p->type) {
274	case GROUP_MODP:
275		group->init = modp_init;
276		group->getlen = modp_getlen;
277		group->exchange = modp_create_exchange;
278		group->shared = modp_create_shared;
279		break;
280	case GROUP_EC2N:
281	case GROUP_ECP:
282		group->init = ec_init;
283		group->getlen = ec_getlen;
284		group->secretlen = ec_secretlen;
285		group->exchange = ec_create_exchange;
286		group->shared = ec_create_shared;
287		break;
288	default:
289		group_free(group);
290		return (NULL);
291	}
292
293	if (dh_init(group) != 0) {
294		group_free(group);
295		return (NULL);
296	}
297
298	return (group);
299}
300
301int
302dh_init(struct group *group)
303{
304	return (group->init(group));
305}
306
307int
308dh_getlen(struct group *group)
309{
310	return (group->getlen(group));
311}
312
313int
314dh_secretlen(struct group *group)
315{
316	if (group->secretlen)
317		return (group->secretlen(group));
318	else
319		return (group->getlen(group));
320}
321
322int
323dh_create_exchange(struct group *group, u_int8_t *buf)
324{
325	return (group->exchange(group, buf));
326}
327
328int
329dh_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
330{
331	return (group->shared(group, secret, exchange));
332}
333
334int
335modp_init(struct group *group)
336{
337	DH	*dh;
338	BIGNUM	*p = NULL, *g = NULL;
339
340	if ((dh = DH_new()) == NULL)
341		return (-1);
342	group->dh = dh;
343
344	if (!BN_hex2bn(&p, group->spec->prime) ||
345	    !BN_hex2bn(&g, group->spec->generator)) {
346		BN_free(p);
347		BN_free(g);
348		return (-1);
349	}
350
351	if (!DH_set0_pqg(dh, p, NULL, g)) {
352		BN_free(p);
353		BN_free(g);
354		return (-1);
355	}
356
357	return (0);
358}
359
360int
361modp_getlen(struct group *group)
362{
363	if (group->spec == NULL)
364		return (0);
365	return (roundup(group->spec->bits, 8) / 8);
366}
367
368int
369modp_create_exchange(struct group *group, u_int8_t *buf)
370{
371	DH	*dh = group->dh;
372	int	 len, ret;
373
374	if (!DH_generate_key(dh))
375		return (-1);
376	ret = BN_bn2bin(DH_get0_pub_key(dh), buf);
377	if (!ret)
378		return (-1);
379
380	len = dh_getlen(group);
381
382	/* add zero padding */
383	if (ret < len) {
384		bcopy(buf, buf + (len - ret), ret);
385		bzero(buf, len - ret);
386	}
387
388	return (0);
389}
390
391int
392modp_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
393{
394	BIGNUM	*ex;
395	int	 len, ret;
396
397	len = dh_getlen(group);
398
399	if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL)
400		return (-1);
401
402	ret = DH_compute_key(secret, ex, group->dh);
403	BN_clear_free(ex);
404	if (ret <= 0)
405		return (-1);
406
407	/* add zero padding */
408	if (ret < len) {
409		bcopy(secret, secret + (len - ret), ret);
410		bzero(secret, len - ret);
411	}
412
413	return (0);
414}
415
416int
417ec_init(struct group *group)
418{
419	if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL)
420		return (-1);
421	if (!EC_KEY_generate_key(group->ec))
422		return (-1);
423	if (!EC_KEY_check_key(group->ec))
424		return (-1);
425	return (0);
426}
427
428int
429ec_getlen(struct group *group)
430{
431	if (group->spec == NULL)
432		return (0);
433	/* NB:  Return value will always be even */
434	return ((roundup(group->spec->bits, 8) * 2) / 8);
435}
436
437/*
438 * Note that the shared secret only includes the x value:
439 *
440 * See RFC 5903, 7. ECP Key Exchange Data Formats:
441 *   The Diffie-Hellman shared secret value consists of the x value of the
442 *   Diffie-Hellman common value.
443 * See also RFC 5903, 9. Changes from RFC 4753.
444 */
445int
446ec_secretlen(struct group *group)
447{
448	return (ec_getlen(group) / 2);
449}
450
451int
452ec_create_exchange(struct group *group, u_int8_t *buf)
453{
454	size_t	 len;
455
456	len = ec_getlen(group);
457	bzero(buf, len);
458
459	return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec),
460	    buf, len, EC_POINT2RAW_FULL));
461}
462
463int
464ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
465{
466	const EC_GROUP	*ecgroup = NULL;
467	const BIGNUM	*privkey;
468	EC_KEY		*exkey = NULL;
469	EC_POINT	*exchangep = NULL, *secretp = NULL;
470	int		 ret = -1;
471
472	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL ||
473	    (privkey = EC_KEY_get0_private_key(group->ec)) == NULL)
474		goto done;
475
476	if ((exchangep =
477	    ec_raw2point(group, exchange, ec_getlen(group))) == NULL)
478		goto done;
479
480	if ((exkey = EC_KEY_new()) == NULL)
481		goto done;
482	if (!EC_KEY_set_group(exkey, ecgroup))
483		goto done;
484	if (!EC_KEY_set_public_key(exkey, exchangep))
485		goto done;
486
487	/* validate exchangep */
488	if (!EC_KEY_check_key(exkey))
489		goto done;
490
491	if ((secretp = EC_POINT_new(ecgroup)) == NULL)
492		goto done;
493
494	if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL))
495		goto done;
496
497	ret = ec_point2raw(group, secretp, secret, ec_secretlen(group),
498	    EC_POINT2RAW_XONLY);
499
500 done:
501	if (exkey != NULL)
502		EC_KEY_free(exkey);
503	if (exchangep != NULL)
504		EC_POINT_clear_free(exchangep);
505	if (secretp != NULL)
506		EC_POINT_clear_free(secretp);
507
508	return (ret);
509}
510
511int
512ec_point2raw(struct group *group, const EC_POINT *point,
513    u_int8_t *buf, size_t len, int mode)
514{
515	const EC_GROUP	*ecgroup = NULL;
516	BN_CTX		*bnctx = NULL;
517	BIGNUM		*x = NULL, *y = NULL;
518	int		 ret = -1;
519	size_t		 eclen, xlen, ylen;
520	off_t		 xoff, yoff;
521
522	if ((bnctx = BN_CTX_new()) == NULL)
523		goto done;
524	BN_CTX_start(bnctx);
525	if ((x = BN_CTX_get(bnctx)) == NULL ||
526	    (y = BN_CTX_get(bnctx)) == NULL)
527		goto done;
528
529	eclen = ec_getlen(group);
530	switch (mode) {
531	case EC_POINT2RAW_XONLY:
532		xlen = eclen / 2;
533		ylen = 0;
534		break;
535	case EC_POINT2RAW_FULL:
536		xlen = ylen = eclen / 2;
537		break;
538	default:
539		goto done;
540	}
541	if (len < xlen + ylen)
542		goto done;
543
544	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
545		goto done;
546
547	if (!EC_POINT_get_affine_coordinates(ecgroup, point, x, y, bnctx))
548		goto done;
549
550	xoff = xlen - BN_num_bytes(x);
551	bzero(buf, xoff);
552	if (!BN_bn2bin(x, buf + xoff))
553		goto done;
554
555	if (ylen > 0) {
556		yoff = (ylen - BN_num_bytes(y)) + xlen;
557		bzero(buf + xlen, yoff - xlen);
558		if (!BN_bn2bin(y, buf + yoff))
559			goto done;
560	}
561
562	ret = 0;
563 done:
564	/* Make sure to erase sensitive data */
565	if (x != NULL)
566		BN_clear(x);
567	if (y != NULL)
568		BN_clear(y);
569	BN_CTX_end(bnctx);
570	BN_CTX_free(bnctx);
571
572	return (ret);
573}
574
575EC_POINT *
576ec_raw2point(struct group *group, u_int8_t *buf, size_t len)
577{
578	const EC_GROUP	*ecgroup = NULL;
579	EC_POINT	*point = NULL;
580	BN_CTX		*bnctx = NULL;
581	BIGNUM		*x = NULL, *y = NULL;
582	int		 ret = -1;
583	size_t		 eclen;
584	size_t		 xlen, ylen;
585
586	if ((bnctx = BN_CTX_new()) == NULL)
587		goto done;
588	BN_CTX_start(bnctx);
589	if ((x = BN_CTX_get(bnctx)) == NULL ||
590	    (y = BN_CTX_get(bnctx)) == NULL)
591		goto done;
592
593	eclen = ec_getlen(group);
594	if (len < eclen)
595		goto done;
596	xlen = ylen = eclen / 2;
597	if ((x = BN_bin2bn(buf, xlen, x)) == NULL ||
598	    (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL)
599		goto done;
600
601	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
602		goto done;
603
604	if ((point = EC_POINT_new(ecgroup)) == NULL)
605		goto done;
606
607	if (!EC_POINT_set_affine_coordinates(ecgroup, point, x, y, bnctx))
608		goto done;
609
610	ret = 0;
611 done:
612	if (ret != 0 && point != NULL)
613		EC_POINT_clear_free(point);
614	/* Make sure to erase sensitive data */
615	if (x != NULL)
616		BN_clear(x);
617	if (y != NULL)
618		BN_clear(y);
619	BN_CTX_end(bnctx);
620	BN_CTX_free(bnctx);
621
622	return (point);
623}
624