dh.c revision 1.23
1/*	$OpenBSD: dh.c,v 1.23 2021/11/29 06:42:13 deraadt 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
339	if ((dh = DH_new()) == NULL)
340		return (-1);
341	group->dh = dh;
342
343	if (!BN_hex2bn(&dh->p, group->spec->prime) ||
344	    !BN_hex2bn(&dh->g, group->spec->generator))
345		return (-1);
346
347	return (0);
348}
349
350int
351modp_getlen(struct group *group)
352{
353	if (group->spec == NULL)
354		return (0);
355	return (roundup(group->spec->bits, 8) / 8);
356}
357
358int
359modp_create_exchange(struct group *group, u_int8_t *buf)
360{
361	DH	*dh = group->dh;
362	int	 len, ret;
363
364	if (!DH_generate_key(dh))
365		return (-1);
366	ret = BN_bn2bin(dh->pub_key, buf);
367	if (!ret)
368		return (-1);
369
370	len = dh_getlen(group);
371
372	/* add zero padding */
373	if (ret < len) {
374		bcopy(buf, buf + (len - ret), ret);
375		bzero(buf, len - ret);
376	}
377
378	return (0);
379}
380
381int
382modp_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
383{
384	BIGNUM	*ex;
385	int	 len, ret;
386
387	len = dh_getlen(group);
388
389	if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL)
390		return (-1);
391
392	ret = DH_compute_key(secret, ex, group->dh);
393	BN_clear_free(ex);
394	if (ret <= 0)
395		return (-1);
396
397	/* add zero padding */
398	if (ret < len) {
399		bcopy(secret, secret + (len - ret), ret);
400		bzero(secret, len - ret);
401	}
402
403	return (0);
404}
405
406int
407ec_init(struct group *group)
408{
409	if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL)
410		return (-1);
411	if (!EC_KEY_generate_key(group->ec))
412		return (-1);
413	if (!EC_KEY_check_key(group->ec)) {
414		EC_KEY_free(group->ec);
415		return (-1);
416	}
417	return (0);
418}
419
420int
421ec_getlen(struct group *group)
422{
423	if (group->spec == NULL)
424		return (0);
425	/* NB:  Return value will always be even */
426	return ((roundup(group->spec->bits, 8) * 2) / 8);
427}
428
429/*
430 * Note that the shared secret only includes the x value:
431 *
432 * See RFC 5903, 7. ECP Key Exchange Data Formats:
433 *   The Diffie-Hellman shared secret value consists of the x value of the
434 *   Diffie-Hellman common value.
435 * See also RFC 5903, 9. Changes from RFC 4753.
436 */
437int
438ec_secretlen(struct group *group)
439{
440	return (ec_getlen(group) / 2);
441}
442
443int
444ec_create_exchange(struct group *group, u_int8_t *buf)
445{
446	size_t	 len;
447
448	len = ec_getlen(group);
449	bzero(buf, len);
450
451	return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec),
452	    buf, len, EC_POINT2RAW_FULL));
453}
454
455int
456ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
457{
458	const EC_GROUP	*ecgroup = NULL;
459	const BIGNUM	*privkey;
460	EC_KEY		*exkey = NULL;
461	EC_POINT	*exchangep = NULL, *secretp = NULL;
462	int		 ret = -1;
463
464	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL ||
465	    (privkey = EC_KEY_get0_private_key(group->ec)) == NULL)
466		goto done;
467
468	if ((exchangep =
469	    ec_raw2point(group, exchange, ec_getlen(group))) == NULL)
470		goto done;
471
472	if ((exkey = EC_KEY_new()) == NULL)
473		goto done;
474	if (!EC_KEY_set_group(exkey, ecgroup))
475		goto done;
476	if (!EC_KEY_set_public_key(exkey, exchangep))
477		goto done;
478
479	/* validate exchangep */
480	if (!EC_KEY_check_key(exkey))
481		goto done;
482
483	if ((secretp = EC_POINT_new(ecgroup)) == NULL)
484		goto done;
485
486	if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL))
487		goto done;
488
489	ret = ec_point2raw(group, secretp, secret, ec_secretlen(group),
490	    EC_POINT2RAW_XONLY);
491
492 done:
493	if (exkey != NULL)
494		EC_KEY_free(exkey);
495	if (exchangep != NULL)
496		EC_POINT_clear_free(exchangep);
497	if (secretp != NULL)
498		EC_POINT_clear_free(secretp);
499
500	return (ret);
501}
502
503int
504ec_point2raw(struct group *group, const EC_POINT *point,
505    u_int8_t *buf, size_t len, int mode)
506{
507	const EC_GROUP	*ecgroup = NULL;
508	BN_CTX		*bnctx = NULL;
509	BIGNUM		*x = NULL, *y = NULL;
510	int		 ret = -1;
511	size_t		 eclen, xlen, ylen;
512	off_t		 xoff, yoff;
513
514	if ((bnctx = BN_CTX_new()) == NULL)
515		goto done;
516	BN_CTX_start(bnctx);
517	if ((x = BN_CTX_get(bnctx)) == NULL ||
518	    (y = BN_CTX_get(bnctx)) == NULL)
519		goto done;
520
521	eclen = ec_getlen(group);
522	switch (mode) {
523	case EC_POINT2RAW_XONLY:
524		xlen = eclen / 2;
525		ylen = 0;
526		break;
527	case EC_POINT2RAW_FULL:
528		xlen = ylen = eclen / 2;
529		break;
530	default:
531		goto done;
532	}
533	if (len < xlen + ylen)
534		goto done;
535
536	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
537		goto done;
538
539	if (!EC_POINT_get_affine_coordinates(ecgroup, point, x, y, bnctx))
540		goto done;
541
542	xoff = xlen - BN_num_bytes(x);
543	bzero(buf, xoff);
544	if (!BN_bn2bin(x, buf + xoff))
545		goto done;
546
547	if (ylen > 0) {
548		yoff = (ylen - BN_num_bytes(y)) + xlen;
549		bzero(buf + xlen, yoff - xlen);
550		if (!BN_bn2bin(y, buf + yoff))
551			goto done;
552	}
553
554	ret = 0;
555 done:
556	/* Make sure to erase sensitive data */
557	if (x != NULL)
558		BN_clear(x);
559	if (y != NULL)
560		BN_clear(y);
561	BN_CTX_end(bnctx);
562	BN_CTX_free(bnctx);
563
564	return (ret);
565}
566
567EC_POINT *
568ec_raw2point(struct group *group, u_int8_t *buf, size_t len)
569{
570	const EC_GROUP	*ecgroup = NULL;
571	EC_POINT	*point = NULL;
572	BN_CTX		*bnctx = NULL;
573	BIGNUM		*x = NULL, *y = NULL;
574	int		 ret = -1;
575	size_t		 eclen;
576	size_t		 xlen, ylen;
577
578	if ((bnctx = BN_CTX_new()) == NULL)
579		goto done;
580	BN_CTX_start(bnctx);
581	if ((x = BN_CTX_get(bnctx)) == NULL ||
582	    (y = BN_CTX_get(bnctx)) == NULL)
583		goto done;
584
585	eclen = ec_getlen(group);
586	if (len < eclen)
587		goto done;
588	xlen = ylen = eclen / 2;
589	if ((x = BN_bin2bn(buf, xlen, x)) == NULL ||
590	    (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL)
591		goto done;
592
593	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
594		goto done;
595
596	if ((point = EC_POINT_new(ecgroup)) == NULL)
597		goto done;
598
599	if (!EC_POINT_set_affine_coordinates(ecgroup, point, x, y, bnctx))
600		goto done;
601
602	ret = 0;
603 done:
604	if (ret != 0 && point != NULL)
605		EC_POINT_clear_free(point);
606	/* Make sure to erase sensitive data */
607	if (x != NULL)
608		BN_clear(x);
609	if (y != NULL)
610		BN_clear(y);
611	BN_CTX_end(bnctx);
612	BN_CTX_free(bnctx);
613
614	return (point);
615}
616