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