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