xref: /openbsd/sbin/iked/dh.c (revision 0e1bb3dc)
1*0e1bb3dcStobhe /*	$OpenBSD: dh.c,v 1.27 2021/02/04 20:38:26 tobhe Exp $	*/
245ae9d61Sreyk 
345ae9d61Sreyk /*
4547eb84dSreyk  * Copyright (c) 2010-2014 Reyk Floeter <reyk@openbsd.org>
545ae9d61Sreyk  *
645ae9d61Sreyk  * Permission to use, copy, modify, and distribute this software for any
745ae9d61Sreyk  * purpose with or without fee is hereby granted, provided that the above
845ae9d61Sreyk  * copyright notice and this permission notice appear in all copies.
945ae9d61Sreyk  *
1045ae9d61Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1145ae9d61Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1245ae9d61Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1345ae9d61Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1445ae9d61Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1545ae9d61Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1645ae9d61Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1745ae9d61Sreyk  */
1845ae9d61Sreyk 
19b9fc9a72Sderaadt #include <sys/param.h>	/* roundup */
2045ae9d61Sreyk #include <string.h>
2145ae9d61Sreyk 
22710c50d7Stobhe #include <sys/queue.h>
23710c50d7Stobhe #include <sys/socket.h>
24710c50d7Stobhe #include <sys/uio.h>
25710c50d7Stobhe #include <event.h>
26710c50d7Stobhe #include <imsg.h>
27710c50d7Stobhe 
28710c50d7Stobhe #include <openssl/evp.h>
29710c50d7Stobhe #include <openssl/sha.h>
3045ae9d61Sreyk #include <openssl/obj_mac.h>
3145ae9d61Sreyk #include <openssl/dh.h>
3245ae9d61Sreyk #include <openssl/ec.h>
3345ae9d61Sreyk #include <openssl/ecdh.h>
34a4194998Sjsg #include <openssl/bn.h>
3545ae9d61Sreyk 
3645ae9d61Sreyk #include "dh.h"
37710c50d7Stobhe #include "iked.h"
380d5bf58dSreyk 
39*0e1bb3dcStobhe int	dh_init(struct dh_group *);
40*0e1bb3dcStobhe int	dh_getlen(struct dh_group *);
41*0e1bb3dcStobhe int	dh_secretlen(struct dh_group *);
4245ae9d61Sreyk 
4345135ebcSreyk /* MODP */
44*0e1bb3dcStobhe int	modp_init(struct dh_group *);
45*0e1bb3dcStobhe int	modp_getlen(struct dh_group *);
46*0e1bb3dcStobhe int	modp_create_exchange(struct dh_group *, uint8_t *);
47*0e1bb3dcStobhe int	modp_create_shared(struct dh_group *, uint8_t *, uint8_t *);
4845ae9d61Sreyk 
49bc77414bStobhe /* ECP */
50*0e1bb3dcStobhe int	ec_init(struct dh_group *);
51*0e1bb3dcStobhe int	ec_getlen(struct dh_group *);
52*0e1bb3dcStobhe int	ec_secretlen(struct dh_group *);
53*0e1bb3dcStobhe int	ec_create_exchange(struct dh_group *, uint8_t *);
54*0e1bb3dcStobhe int	ec_create_shared(struct dh_group *, uint8_t *, uint8_t *);
5545ae9d61Sreyk 
56a6321d0fSpatrick #define EC_POINT2RAW_FULL	0
57a6321d0fSpatrick #define EC_POINT2RAW_XONLY	1
58*0e1bb3dcStobhe int	ec_point2raw(struct dh_group *, const EC_POINT *, uint8_t *, size_t, int);
5945ae9d61Sreyk EC_POINT *
60*0e1bb3dcStobhe 	ec_raw2point(struct dh_group *, uint8_t *, size_t);
6145ae9d61Sreyk 
6245135ebcSreyk /* curve25519 */
63*0e1bb3dcStobhe int	ec25519_init(struct dh_group *);
64*0e1bb3dcStobhe int	ec25519_getlen(struct dh_group *);
65*0e1bb3dcStobhe int	ec25519_create_exchange(struct dh_group *, uint8_t *);
66*0e1bb3dcStobhe int	ec25519_create_shared(struct dh_group *, uint8_t *, uint8_t *);
6745135ebcSreyk 
6845135ebcSreyk #define CURVE25519_SIZE 32	/* 256 bits */
6945135ebcSreyk struct curve25519_key {
70d09d3a7dSreyk 	uint8_t		 secret[CURVE25519_SIZE];
71d09d3a7dSreyk 	uint8_t		 public[CURVE25519_SIZE];
7245135ebcSreyk };
73d09d3a7dSreyk extern int crypto_scalarmult_curve25519(unsigned char a[CURVE25519_SIZE],
74d09d3a7dSreyk     const unsigned char b[CURVE25519_SIZE],
75d09d3a7dSreyk     const unsigned char c[CURVE25519_SIZE])
7645135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
7745135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)))
7845135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE)));
7945135ebcSreyk 
80e254d6eaSmikeb const struct group_id ike_groups[] = {
8145ae9d61Sreyk 	{ GROUP_MODP, 1, 768,
8245ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
8345ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
8445ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
8545ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
8645ae9d61Sreyk 	    "02"
8745ae9d61Sreyk 	},
8845ae9d61Sreyk 	{ GROUP_MODP, 2, 1024,
8945ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
9045ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
9145ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
9245ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
9345ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
9445ae9d61Sreyk 	    "FFFFFFFFFFFFFFFF",
9545ae9d61Sreyk 	    "02"
9645ae9d61Sreyk 	},
9745ae9d61Sreyk 	{ GROUP_MODP, 5, 1536,
9845ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
9945ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
10045ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
10145ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
10245ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
10345ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
10445ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
10545ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
10645ae9d61Sreyk 	    "02"
10745ae9d61Sreyk 	},
10845ae9d61Sreyk 	{ GROUP_MODP, 14, 2048,
10945ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
11045ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
11145ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
11245ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
11345ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
11445ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
11545ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
11645ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
11745ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
11845ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
11945ae9d61Sreyk 	    "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
12045ae9d61Sreyk 	    "02"
12145ae9d61Sreyk 	},
12245ae9d61Sreyk 	{ GROUP_MODP, 15, 3072,
12345ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
12445ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
12545ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
12645ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
12745ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
12845ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
12945ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
13045ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
13145ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
13245ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
13345ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
13445ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
13545ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
13645ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
13745ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
13845ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF",
13945ae9d61Sreyk 	    "02"
14045ae9d61Sreyk 	},
14145ae9d61Sreyk 	{ GROUP_MODP, 16, 4096,
14245ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
14345ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
14445ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
14545ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
14645ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
14745ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
14845ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
14945ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
15045ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
15145ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
15245ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
15345ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
15445ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
15545ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
15645ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
15745ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
15845ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
15945ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
16045ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
16145ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
16245ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
16345ae9d61Sreyk 	    "FFFFFFFFFFFFFFFF",
16445ae9d61Sreyk 	    "02"
16545ae9d61Sreyk 	},
16645ae9d61Sreyk 	{ GROUP_MODP, 17, 6144,
16745ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
16845ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
16945ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
17045ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
17145ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
17245ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
17345ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
17445ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
17545ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
17645ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
17745ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
17845ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
17945ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
18045ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
18145ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
18245ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
18345ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
18445ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
18545ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
18645ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
18745ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
18845ae9d61Sreyk 	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
18945ae9d61Sreyk 	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
19045ae9d61Sreyk 	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
19145ae9d61Sreyk 	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
19245ae9d61Sreyk 	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
19345ae9d61Sreyk 	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
19445ae9d61Sreyk 	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
19545ae9d61Sreyk 	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
19645ae9d61Sreyk 	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
19745ae9d61Sreyk 	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
19845ae9d61Sreyk 	    "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF",
19945ae9d61Sreyk 	    "02"
20045ae9d61Sreyk 	},
20145ae9d61Sreyk 	{ GROUP_MODP, 18, 8192,
20245ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
20345ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
20445ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
20545ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
20645ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
20745ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
20845ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
20945ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
21045ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
21145ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
21245ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
21345ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
21445ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
21545ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
21645ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
21745ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
21845ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
21945ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
22045ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
22145ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
22245ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
22345ae9d61Sreyk 	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
22445ae9d61Sreyk 	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
22545ae9d61Sreyk 	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
22645ae9d61Sreyk 	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
22745ae9d61Sreyk 	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
22845ae9d61Sreyk 	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
22945ae9d61Sreyk 	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
23045ae9d61Sreyk 	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
23145ae9d61Sreyk 	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
23245ae9d61Sreyk 	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
23345ae9d61Sreyk 	    "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
23445ae9d61Sreyk 	    "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
23545ae9d61Sreyk 	    "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
23645ae9d61Sreyk 	    "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
23745ae9d61Sreyk 	    "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
23845ae9d61Sreyk 	    "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
23945ae9d61Sreyk 	    "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
24045ae9d61Sreyk 	    "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
24145ae9d61Sreyk 	    "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
24245ae9d61Sreyk 	    "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
24345ae9d61Sreyk 	    "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
24445ae9d61Sreyk 	    "60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
24545ae9d61Sreyk 	    "02"
24645ae9d61Sreyk 	},
247369beec1Sreyk 	{ GROUP_ECP, 19, 256, NULL, NULL, NID_X9_62_prime256v1 },
248369beec1Sreyk 	{ GROUP_ECP, 20, 384, NULL, NULL, NID_secp384r1 },
249369beec1Sreyk 	{ GROUP_ECP, 21, 521, NULL, NULL, NID_secp521r1 },
250369beec1Sreyk 	{ GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 },
251547eb84dSreyk 	{ GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 },
252547eb84dSreyk 	{ GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 },
253547eb84dSreyk 	{ GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 },
254547eb84dSreyk 	{ GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 },
25545135ebcSreyk 	{ GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 },
256337280ecSsthen 	{ GROUP_CURVE25519, 31, CURVE25519_SIZE * 8 }
25745ae9d61Sreyk };
25845ae9d61Sreyk 
25945ae9d61Sreyk void
26045ae9d61Sreyk group_init(void)
26145ae9d61Sreyk {
2620d5bf58dSreyk 	/* currently not used */
26345ae9d61Sreyk 	return;
26445ae9d61Sreyk }
26545ae9d61Sreyk 
26645ae9d61Sreyk void
267*0e1bb3dcStobhe group_free(struct dh_group *group)
26845ae9d61Sreyk {
26945ae9d61Sreyk 	if (group == NULL)
27045ae9d61Sreyk 		return;
27145ae9d61Sreyk 	if (group->dh != NULL)
27245ae9d61Sreyk 		DH_free(group->dh);
27345ae9d61Sreyk 	if (group->ec != NULL)
27445ae9d61Sreyk 		EC_KEY_free(group->ec);
27529b4e2eaSderaadt 	freezero(group->curve25519, sizeof(struct curve25519_key));
27645ae9d61Sreyk 	group->spec = NULL;
27764449014Sreyk 	free(group);
27845ae9d61Sreyk }
27945ae9d61Sreyk 
280*0e1bb3dcStobhe struct dh_group *
281d09d3a7dSreyk group_get(uint32_t id)
28245ae9d61Sreyk {
283e254d6eaSmikeb 	const struct group_id	*p;
284*0e1bb3dcStobhe 	struct dh_group		*group;
28545ae9d61Sreyk 
286e254d6eaSmikeb 	if ((p = group_getid(id)) == NULL)
28745ae9d61Sreyk 		return (NULL);
28845ae9d61Sreyk 
28945ae9d61Sreyk 	if ((group = calloc(1, sizeof(*group))) == NULL)
29045ae9d61Sreyk 		return (NULL);
29145ae9d61Sreyk 
29245ae9d61Sreyk 	group->id = id;
29345ae9d61Sreyk 	group->spec = p;
29445ae9d61Sreyk 
29545ae9d61Sreyk 	switch (p->type) {
29645ae9d61Sreyk 	case GROUP_MODP:
29745ae9d61Sreyk 		group->init = modp_init;
29845ae9d61Sreyk 		group->getlen = modp_getlen;
29945ae9d61Sreyk 		group->exchange = modp_create_exchange;
30045ae9d61Sreyk 		group->shared = modp_create_shared;
30145ae9d61Sreyk 		break;
302369beec1Sreyk 	case GROUP_ECP:
30345ae9d61Sreyk 		group->init = ec_init;
30445ae9d61Sreyk 		group->getlen = ec_getlen;
305a6321d0fSpatrick 		group->secretlen = ec_secretlen;
30645ae9d61Sreyk 		group->exchange = ec_create_exchange;
30745ae9d61Sreyk 		group->shared = ec_create_shared;
30845ae9d61Sreyk 		break;
30945135ebcSreyk 	case GROUP_CURVE25519:
31045135ebcSreyk 		group->init = ec25519_init;
31145135ebcSreyk 		group->getlen = ec25519_getlen;
31245135ebcSreyk 		group->exchange = ec25519_create_exchange;
31345135ebcSreyk 		group->shared = ec25519_create_shared;
31445135ebcSreyk 		break;
31545ae9d61Sreyk 	default:
31645ae9d61Sreyk 		group_free(group);
31745ae9d61Sreyk 		return (NULL);
31845ae9d61Sreyk 	}
31945ae9d61Sreyk 
32045ae9d61Sreyk 	if (dh_init(group) != 0) {
32145ae9d61Sreyk 		group_free(group);
32245ae9d61Sreyk 		return (NULL);
32345ae9d61Sreyk 	}
32445ae9d61Sreyk 
32545ae9d61Sreyk 	return (group);
32645ae9d61Sreyk }
32745ae9d61Sreyk 
328e254d6eaSmikeb const struct group_id *
329e254d6eaSmikeb group_getid(uint32_t id)
330e254d6eaSmikeb {
331e254d6eaSmikeb 	const struct group_id	*p = NULL;
332e254d6eaSmikeb 	unsigned int		 i, items;
333e254d6eaSmikeb 
334e254d6eaSmikeb 	items = sizeof(ike_groups) / sizeof(ike_groups[0]);
335e254d6eaSmikeb 	for (i = 0; i < items; i++) {
336e254d6eaSmikeb 		if (id == ike_groups[i].id) {
337e254d6eaSmikeb 			p = &ike_groups[i];
338e254d6eaSmikeb 			break;
339e254d6eaSmikeb 		}
340e254d6eaSmikeb 	}
341e254d6eaSmikeb 	return (p);
342e254d6eaSmikeb }
343e254d6eaSmikeb 
34445ae9d61Sreyk int
345*0e1bb3dcStobhe dh_init(struct dh_group *group)
34645ae9d61Sreyk {
34745ae9d61Sreyk 	return (group->init(group));
34845ae9d61Sreyk }
34945ae9d61Sreyk 
35045ae9d61Sreyk int
351*0e1bb3dcStobhe dh_getlen(struct dh_group *group)
35245ae9d61Sreyk {
35345ae9d61Sreyk 	return (group->getlen(group));
35445ae9d61Sreyk }
35545ae9d61Sreyk 
35645ae9d61Sreyk int
357*0e1bb3dcStobhe dh_secretlen(struct dh_group *group)
358a6321d0fSpatrick {
359a6321d0fSpatrick 	if (group->secretlen)
360a6321d0fSpatrick 		return (group->secretlen(group));
361a6321d0fSpatrick 	else
362a6321d0fSpatrick 		return (group->getlen(group));
363a6321d0fSpatrick }
364a6321d0fSpatrick 
365a6321d0fSpatrick int
366*0e1bb3dcStobhe dh_create_exchange(struct dh_group *group, struct ibuf **bufp, struct ibuf *iexchange)
36745ae9d61Sreyk {
368710c50d7Stobhe 	struct ibuf *buf;
369710c50d7Stobhe 
370710c50d7Stobhe 	*bufp = NULL;
371710c50d7Stobhe 	buf = ibuf_new(NULL, dh_getlen(group));
372710c50d7Stobhe 	if (buf == NULL)
373710c50d7Stobhe 		return -1;
374710c50d7Stobhe 	*bufp = buf;
375710c50d7Stobhe 	return (group->exchange(group, buf->buf));
37645ae9d61Sreyk }
37745ae9d61Sreyk 
37845ae9d61Sreyk int
379*0e1bb3dcStobhe dh_create_shared(struct dh_group *group, struct ibuf **secretp, struct ibuf *exchange)
38045ae9d61Sreyk {
381710c50d7Stobhe 	struct ibuf *buf;
382710c50d7Stobhe 
383710c50d7Stobhe 	*secretp = NULL;
384710c50d7Stobhe 	if (exchange == NULL ||
385710c50d7Stobhe 	    (ssize_t)ibuf_size(exchange) != dh_getlen(group))
386710c50d7Stobhe 		return -1;
387710c50d7Stobhe 	buf = ibuf_new(NULL, dh_secretlen(group));
388710c50d7Stobhe 	if (buf == NULL)
389710c50d7Stobhe 		return -1;
390710c50d7Stobhe 	*secretp = buf;
391710c50d7Stobhe 	return (group->shared(group, buf->buf, exchange->buf));
39245ae9d61Sreyk }
39345ae9d61Sreyk 
39445ae9d61Sreyk int
395*0e1bb3dcStobhe modp_init(struct dh_group *group)
39645ae9d61Sreyk {
39708c24fddStobhe 	BIGNUM	*g = NULL, *p = NULL;
39845ae9d61Sreyk 	DH	*dh;
39908c24fddStobhe 	int	 ret = -1;
40045ae9d61Sreyk 
40145ae9d61Sreyk 	if ((dh = DH_new()) == NULL)
40245ae9d61Sreyk 		return (-1);
40308c24fddStobhe 
40408c24fddStobhe 	if (!BN_hex2bn(&p, group->spec->prime) ||
40508c24fddStobhe 	    !BN_hex2bn(&g, group->spec->generator) ||
40608c24fddStobhe 	    DH_set0_pqg(dh, p, NULL, g) == 0)
40708c24fddStobhe 		goto done;
40808c24fddStobhe 
40908c24fddStobhe 	p = g = NULL;
4107d7b0856Sreyk 	group->dh = dh;
41145ae9d61Sreyk 
41208c24fddStobhe 	ret = 0;
41308c24fddStobhe  done:
41408c24fddStobhe 	BN_clear_free(g);
41508c24fddStobhe 	BN_clear_free(p);
41645ae9d61Sreyk 
41708c24fddStobhe 	return (ret);
41845ae9d61Sreyk }
41945ae9d61Sreyk 
42045ae9d61Sreyk int
421*0e1bb3dcStobhe modp_getlen(struct dh_group *group)
42245ae9d61Sreyk {
42345ae9d61Sreyk 	if (group->spec == NULL)
42445ae9d61Sreyk 		return (0);
42545ae9d61Sreyk 	return (roundup(group->spec->bits, 8) / 8);
42645ae9d61Sreyk }
42745ae9d61Sreyk 
42845ae9d61Sreyk int
429*0e1bb3dcStobhe modp_create_exchange(struct dh_group *group, uint8_t *buf)
43045ae9d61Sreyk {
43108c24fddStobhe 	const BIGNUM	*pub;
43245ae9d61Sreyk 	DH		*dh = group->dh;
43312abf43bSmikeb 	int		 len, ret;
43445ae9d61Sreyk 
43545ae9d61Sreyk 	if (!DH_generate_key(dh))
43645ae9d61Sreyk 		return (-1);
43708c24fddStobhe 	DH_get0_key(group->dh, &pub, NULL);
43808c24fddStobhe 	ret = BN_bn2bin(pub, buf);
43912abf43bSmikeb 	if (!ret)
44045ae9d61Sreyk 		return (-1);
44145ae9d61Sreyk 
44212abf43bSmikeb 	len = dh_getlen(group);
44312abf43bSmikeb 
44412abf43bSmikeb 	/* add zero padding */
44512abf43bSmikeb 	if (ret < len) {
44612abf43bSmikeb 		bcopy(buf, buf + (len - ret), ret);
44712abf43bSmikeb 		bzero(buf, len - ret);
44812abf43bSmikeb 	}
44912abf43bSmikeb 
4507d7b0856Sreyk 	return (0);
45145ae9d61Sreyk }
45245ae9d61Sreyk 
45345ae9d61Sreyk int
454*0e1bb3dcStobhe modp_create_shared(struct dh_group *group, uint8_t *secret, uint8_t *exchange)
45545ae9d61Sreyk {
45645ae9d61Sreyk 	BIGNUM	*ex;
45712abf43bSmikeb 	int	 len, ret;
45845ae9d61Sreyk 
45912abf43bSmikeb 	len = dh_getlen(group);
46012abf43bSmikeb 
46112abf43bSmikeb 	if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL)
46245ae9d61Sreyk 		return (-1);
4637d7b0856Sreyk 
4647d7b0856Sreyk 	ret = DH_compute_key(secret, ex, group->dh);
4657d7b0856Sreyk 	BN_clear_free(ex);
4662ffa77eaSjsg 	if (ret <= 0)
46745ae9d61Sreyk 		return (-1);
46845ae9d61Sreyk 
46912abf43bSmikeb 	/* add zero padding */
47012abf43bSmikeb 	if (ret < len) {
47112abf43bSmikeb 		bcopy(secret, secret + (len - ret), ret);
47212abf43bSmikeb 		bzero(secret, len - ret);
47312abf43bSmikeb 	}
47412abf43bSmikeb 
4757d7b0856Sreyk 	return (0);
47645ae9d61Sreyk }
47745ae9d61Sreyk 
47845ae9d61Sreyk int
479*0e1bb3dcStobhe ec_init(struct dh_group *group)
48045ae9d61Sreyk {
48145ae9d61Sreyk 	if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL)
48245ae9d61Sreyk 		return (-1);
48345ae9d61Sreyk 	if (!EC_KEY_generate_key(group->ec))
48445ae9d61Sreyk 		return (-1);
485c900656bSmarkus 	if (!EC_KEY_check_key(group->ec)) {
486c900656bSmarkus 		EC_KEY_free(group->ec);
487c900656bSmarkus 		return (-1);
488c900656bSmarkus 	}
48945ae9d61Sreyk 	return (0);
49045ae9d61Sreyk }
49145ae9d61Sreyk 
49245ae9d61Sreyk int
493*0e1bb3dcStobhe ec_getlen(struct dh_group *group)
49445ae9d61Sreyk {
49545ae9d61Sreyk 	if (group->spec == NULL)
49645ae9d61Sreyk 		return (0);
49745b72fd1Smikeb 	/* NB:  Return value will always be even */
49845ae9d61Sreyk 	return ((roundup(group->spec->bits, 8) * 2) / 8);
49945ae9d61Sreyk }
50045ae9d61Sreyk 
501a6321d0fSpatrick /*
502a6321d0fSpatrick  * Note that the shared secret only includes the x value:
503a6321d0fSpatrick  *
504a6321d0fSpatrick  * See RFC 5903, 7. ECP Key Exchange Data Formats:
505a6321d0fSpatrick  *   The Diffie-Hellman shared secret value consists of the x value of the
506a6321d0fSpatrick  *   Diffie-Hellman common value.
507a6321d0fSpatrick  * See also RFC 5903, 9. Changes from RFC 4753.
508a6321d0fSpatrick  */
509a6321d0fSpatrick int
510*0e1bb3dcStobhe ec_secretlen(struct dh_group *group)
511a6321d0fSpatrick {
512a6321d0fSpatrick 	return (ec_getlen(group) / 2);
513a6321d0fSpatrick }
514a6321d0fSpatrick 
51545ae9d61Sreyk int
516*0e1bb3dcStobhe ec_create_exchange(struct dh_group *group, uint8_t *buf)
51745ae9d61Sreyk {
5180d5bf58dSreyk 	size_t	 len;
5190d5bf58dSreyk 
5200d5bf58dSreyk 	len = ec_getlen(group);
5210d5bf58dSreyk 	bzero(buf, len);
5220d5bf58dSreyk 
52345ae9d61Sreyk 	return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec),
524a6321d0fSpatrick 	    buf, len, EC_POINT2RAW_FULL));
52545ae9d61Sreyk }
52645ae9d61Sreyk 
52745ae9d61Sreyk int
528*0e1bb3dcStobhe ec_create_shared(struct dh_group *group, uint8_t *secret, uint8_t *exchange)
52945ae9d61Sreyk {
53045ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
53145ae9d61Sreyk 	const BIGNUM	*privkey;
532c900656bSmarkus 	EC_KEY		*exkey = NULL;
53345ae9d61Sreyk 	EC_POINT	*exchangep = NULL, *secretp = NULL;
53445ae9d61Sreyk 	int		 ret = -1;
53545ae9d61Sreyk 
53645ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL ||
53745ae9d61Sreyk 	    (privkey = EC_KEY_get0_private_key(group->ec)) == NULL)
53845ae9d61Sreyk 		goto done;
53945ae9d61Sreyk 
54045ae9d61Sreyk 	if ((exchangep =
54145ae9d61Sreyk 	    ec_raw2point(group, exchange, ec_getlen(group))) == NULL)
54245ae9d61Sreyk 		goto done;
54345ae9d61Sreyk 
544c900656bSmarkus 	if ((exkey = EC_KEY_new()) == NULL)
545c900656bSmarkus 		goto done;
546c900656bSmarkus 	if (!EC_KEY_set_group(exkey, ecgroup))
547c900656bSmarkus 		goto done;
548c900656bSmarkus 	if (!EC_KEY_set_public_key(exkey, exchangep))
549c900656bSmarkus 		goto done;
550c900656bSmarkus 
551c900656bSmarkus 	/* validate exchangep */
552c900656bSmarkus 	if (!EC_KEY_check_key(exkey))
553c900656bSmarkus 		goto done;
554c900656bSmarkus 
55545ae9d61Sreyk 	if ((secretp = EC_POINT_new(ecgroup)) == NULL)
55645ae9d61Sreyk 		goto done;
55745ae9d61Sreyk 
55845ae9d61Sreyk 	if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL))
55945ae9d61Sreyk 		goto done;
56045ae9d61Sreyk 
561a6321d0fSpatrick 	ret = ec_point2raw(group, secretp, secret, ec_secretlen(group),
562a6321d0fSpatrick 	    EC_POINT2RAW_XONLY);
56345ae9d61Sreyk 
56445ae9d61Sreyk  done:
565c900656bSmarkus 	if (exkey != NULL)
566c900656bSmarkus 		EC_KEY_free(exkey);
56745ae9d61Sreyk 	if (exchangep != NULL)
56845ae9d61Sreyk 		EC_POINT_clear_free(exchangep);
56945ae9d61Sreyk 	if (secretp != NULL)
57045ae9d61Sreyk 		EC_POINT_clear_free(secretp);
57145ae9d61Sreyk 
57245ae9d61Sreyk 	return (ret);
57345ae9d61Sreyk }
57445ae9d61Sreyk 
57545ae9d61Sreyk int
576*0e1bb3dcStobhe ec_point2raw(struct dh_group *group, const EC_POINT *point,
577a6321d0fSpatrick     uint8_t *buf, size_t len, int mode)
57845ae9d61Sreyk {
57945ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
58045ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
58145ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
58245ae9d61Sreyk 	int		 ret = -1;
58345b72fd1Smikeb 	size_t		 eclen, xlen, ylen;
58445ae9d61Sreyk 	off_t		 xoff, yoff;
58545ae9d61Sreyk 
58645ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
58745ae9d61Sreyk 		goto done;
58845ae9d61Sreyk 	BN_CTX_start(bnctx);
58945ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
59045ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
59145ae9d61Sreyk 		goto done;
59245ae9d61Sreyk 
59345b72fd1Smikeb 	eclen = ec_getlen(group);
594a6321d0fSpatrick 	switch (mode) {
595a6321d0fSpatrick 	case EC_POINT2RAW_XONLY:
596a6321d0fSpatrick 		xlen = eclen / 2;
597a6321d0fSpatrick 		ylen = 0;
598a6321d0fSpatrick 		break;
599a6321d0fSpatrick 	case EC_POINT2RAW_FULL:
60045b72fd1Smikeb 		xlen = ylen = eclen / 2;
601a6321d0fSpatrick 		break;
602a6321d0fSpatrick 	default:
603a6321d0fSpatrick 		goto done;
604a6321d0fSpatrick 	}
605a6321d0fSpatrick 	if (len < xlen + ylen)
606a6321d0fSpatrick 		goto done;
60745b72fd1Smikeb 
60845ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
60945ae9d61Sreyk 		goto done;
61045ae9d61Sreyk 
61145ae9d61Sreyk 	if (!EC_POINT_get_affine_coordinates_GFp(ecgroup,
61245ae9d61Sreyk 	    point, x, y, bnctx))
61345ae9d61Sreyk 		goto done;
61445ae9d61Sreyk 
61545ae9d61Sreyk 	xoff = xlen - BN_num_bytes(x);
61645b72fd1Smikeb 	bzero(buf, xoff);
61745ae9d61Sreyk 	if (!BN_bn2bin(x, buf + xoff))
61845ae9d61Sreyk 		goto done;
61945ae9d61Sreyk 
620a6321d0fSpatrick 	if (ylen > 0) {
62145ae9d61Sreyk 		yoff = (ylen - BN_num_bytes(y)) + xlen;
62245b72fd1Smikeb 		bzero(buf + xlen, yoff - xlen);
62345ae9d61Sreyk 		if (!BN_bn2bin(y, buf + yoff))
62445ae9d61Sreyk 			goto done;
625a6321d0fSpatrick 	}
62645ae9d61Sreyk 
62745ae9d61Sreyk 	ret = 0;
62845ae9d61Sreyk  done:
629c900656bSmarkus 	/* Make sure to erase sensitive data */
630c900656bSmarkus 	if (x != NULL)
631c900656bSmarkus 		BN_clear(x);
632c900656bSmarkus 	if (y != NULL)
633c900656bSmarkus 		BN_clear(y);
63445ae9d61Sreyk 	BN_CTX_end(bnctx);
63545ae9d61Sreyk 	BN_CTX_free(bnctx);
63645ae9d61Sreyk 
63745ae9d61Sreyk 	return (ret);
63845ae9d61Sreyk }
63945ae9d61Sreyk 
64045ae9d61Sreyk EC_POINT *
641*0e1bb3dcStobhe ec_raw2point(struct dh_group *group, uint8_t *buf, size_t len)
64245ae9d61Sreyk {
64345ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
64445ae9d61Sreyk 	EC_POINT	*point = NULL;
64545ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
64645ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
64745ae9d61Sreyk 	int		 ret = -1;
64845ae9d61Sreyk 	size_t		 eclen;
64945ae9d61Sreyk 	size_t		 xlen, ylen;
65045ae9d61Sreyk 
65145ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
65245ae9d61Sreyk 		goto done;
65345ae9d61Sreyk 	BN_CTX_start(bnctx);
65445ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
65545ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
65645ae9d61Sreyk 		goto done;
65745ae9d61Sreyk 
65845ae9d61Sreyk 	eclen = ec_getlen(group);
65945ae9d61Sreyk 	if (len < eclen)
66045ae9d61Sreyk 		goto done;
66145ae9d61Sreyk 	xlen = ylen = eclen / 2;
66245ae9d61Sreyk 	if ((x = BN_bin2bn(buf, xlen, x)) == NULL ||
66345ae9d61Sreyk 	    (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL)
66445ae9d61Sreyk 		goto done;
66545ae9d61Sreyk 
66645ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
66745ae9d61Sreyk 		goto done;
66845ae9d61Sreyk 
66945ae9d61Sreyk 	if ((point = EC_POINT_new(ecgroup)) == NULL)
67045ae9d61Sreyk 		goto done;
67145ae9d61Sreyk 
67245ae9d61Sreyk 	if (!EC_POINT_set_affine_coordinates_GFp(ecgroup,
67345ae9d61Sreyk 	    point, x, y, bnctx))
67445ae9d61Sreyk 		goto done;
67545ae9d61Sreyk 
67645ae9d61Sreyk 	ret = 0;
67745ae9d61Sreyk  done:
67845ae9d61Sreyk 	if (ret != 0 && point != NULL)
67945ae9d61Sreyk 		EC_POINT_clear_free(point);
680c900656bSmarkus 	/* Make sure to erase sensitive data */
681c900656bSmarkus 	if (x != NULL)
682c900656bSmarkus 		BN_clear(x);
683c900656bSmarkus 	if (y != NULL)
684c900656bSmarkus 		BN_clear(y);
68545ae9d61Sreyk 	BN_CTX_end(bnctx);
68645ae9d61Sreyk 	BN_CTX_free(bnctx);
68745ae9d61Sreyk 
68845ae9d61Sreyk 	return (point);
68945ae9d61Sreyk }
69045135ebcSreyk 
69145135ebcSreyk int
692*0e1bb3dcStobhe ec25519_init(struct dh_group *group)
69345135ebcSreyk {
694d09d3a7dSreyk 	static const uint8_t	 basepoint[CURVE25519_SIZE] = { 9 };
69545135ebcSreyk 	struct curve25519_key	*curve25519;
69645135ebcSreyk 
69745135ebcSreyk 	if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL)
69845135ebcSreyk 		return (-1);
69945135ebcSreyk 
70045135ebcSreyk 	group->curve25519 = curve25519;
70145135ebcSreyk 
70245135ebcSreyk 	arc4random_buf(curve25519->secret, CURVE25519_SIZE);
70345135ebcSreyk 	crypto_scalarmult_curve25519(curve25519->public,
70445135ebcSreyk 	    curve25519->secret, basepoint);
70545135ebcSreyk 
70645135ebcSreyk 	return (0);
70745135ebcSreyk }
70845135ebcSreyk 
70945135ebcSreyk int
710*0e1bb3dcStobhe ec25519_getlen(struct dh_group *group)
71145135ebcSreyk {
71245135ebcSreyk 	if (group->spec == NULL)
71345135ebcSreyk 		return (0);
71445135ebcSreyk 	return (CURVE25519_SIZE);
71545135ebcSreyk }
71645135ebcSreyk 
71745135ebcSreyk int
718*0e1bb3dcStobhe ec25519_create_exchange(struct dh_group *group, uint8_t *buf)
71945135ebcSreyk {
72045135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
72145135ebcSreyk 
72245135ebcSreyk 	memcpy(buf, curve25519->public, ec25519_getlen(group));
72345135ebcSreyk 	return (0);
72445135ebcSreyk }
72545135ebcSreyk 
72645135ebcSreyk int
727*0e1bb3dcStobhe ec25519_create_shared(struct dh_group *group, uint8_t *shared, uint8_t *public)
72845135ebcSreyk {
72945135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
73045135ebcSreyk 
73145135ebcSreyk 	crypto_scalarmult_curve25519(shared, curve25519->secret, public);
73245135ebcSreyk 	return (0);
73345135ebcSreyk }
734