xref: /openbsd/sbin/isakmpd/dh.c (revision 771fbea0)
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 
30 int	dh_init(struct group *);
31 
32 int	modp_init(struct group *);
33 int	modp_getlen(struct group *);
34 int	modp_create_exchange(struct group *, u_int8_t *);
35 int	modp_create_shared(struct group *, u_int8_t *, u_int8_t *);
36 
37 int	ec_init(struct group *);
38 int	ec_getlen(struct group *);
39 int	ec_secretlen(struct group *);
40 int	ec_create_exchange(struct group *, u_int8_t *);
41 int	ec_create_shared(struct group *, u_int8_t *, u_int8_t *);
42 
43 #define EC_POINT2RAW_FULL	0
44 #define EC_POINT2RAW_XONLY	1
45 int	ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t, int);
46 EC_POINT *
47 	ec_raw2point(struct group *, u_int8_t *, size_t);
48 
49 struct 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 
229 void
230 group_init(void)
231 {
232 	/* currently not used */
233 	return;
234 }
235 
236 void
237 group_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 
249 struct group *
250 group_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 
300 int
301 dh_init(struct group *group)
302 {
303 	return (group->init(group));
304 }
305 
306 int
307 dh_getlen(struct group *group)
308 {
309 	return (group->getlen(group));
310 }
311 
312 int
313 dh_secretlen(struct group *group)
314 {
315 	if (group->secretlen)
316 		return (group->secretlen(group));
317 	else
318 		return (group->getlen(group));
319 }
320 
321 int
322 dh_create_exchange(struct group *group, u_int8_t *buf)
323 {
324 	return (group->exchange(group, buf));
325 }
326 
327 int
328 dh_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
329 {
330 	return (group->shared(group, secret, exchange));
331 }
332 
333 int
334 modp_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 
349 int
350 modp_getlen(struct group *group)
351 {
352 	if (group->spec == NULL)
353 		return (0);
354 	return (roundup(group->spec->bits, 8) / 8);
355 }
356 
357 int
358 modp_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 
380 int
381 modp_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 
405 int
406 ec_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 
419 int
420 ec_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  */
436 int
437 ec_secretlen(struct group *group)
438 {
439 	return (ec_getlen(group) / 2);
440 }
441 
442 int
443 ec_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 
454 int
455 ec_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 
502 int
503 ec_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 
566 EC_POINT *
567 ec_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