xref: /openbsd/sbin/iked/dh.c (revision 2ffa77ea)
1*2ffa77eaSjsg /*	$OpenBSD: dh.c,v 1.15 2014/10/12 15:57:00 jsg 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 
1945ae9d61Sreyk #include <sys/param.h>
2045ae9d61Sreyk #include <string.h>
2145ae9d61Sreyk 
2245ae9d61Sreyk #include <openssl/obj_mac.h>
2345ae9d61Sreyk #include <openssl/dh.h>
2445ae9d61Sreyk #include <openssl/ec.h>
2545ae9d61Sreyk #include <openssl/ecdh.h>
26a4194998Sjsg #include <openssl/bn.h>
2745ae9d61Sreyk 
2845ae9d61Sreyk #include "dh.h"
290d5bf58dSreyk 
300d5bf58dSreyk int	dh_init(struct group *);
3145ae9d61Sreyk 
3245135ebcSreyk /* MODP */
3345ae9d61Sreyk int	modp_init(struct group *);
3445ae9d61Sreyk int	modp_getlen(struct group *);
3545ae9d61Sreyk int	modp_create_exchange(struct group *, u_int8_t *);
3645ae9d61Sreyk int	modp_create_shared(struct group *, u_int8_t *, u_int8_t *);
3745ae9d61Sreyk 
3845135ebcSreyk /* EC2N/ECP */
3945ae9d61Sreyk int	ec_init(struct group *);
4045ae9d61Sreyk int	ec_getlen(struct group *);
4145ae9d61Sreyk int	ec_create_exchange(struct group *, u_int8_t *);
4245ae9d61Sreyk int	ec_create_shared(struct group *, u_int8_t *, u_int8_t *);
4345ae9d61Sreyk 
4445ae9d61Sreyk int	ec_point2raw(struct group *, const EC_POINT *, u_int8_t *, size_t);
4545ae9d61Sreyk EC_POINT *
4645ae9d61Sreyk 	ec_raw2point(struct group *, u_int8_t *, size_t);
4745ae9d61Sreyk 
4845135ebcSreyk /* curve25519 */
4945135ebcSreyk int	ec25519_init(struct group *);
5045135ebcSreyk int	ec25519_getlen(struct group *);
5145135ebcSreyk int	ec25519_create_exchange(struct group *, u_int8_t *);
5245135ebcSreyk int	ec25519_create_shared(struct group *, u_int8_t *, u_int8_t *);
5345135ebcSreyk 
5445135ebcSreyk #define CURVE25519_SIZE 32	/* 256 bits */
5545135ebcSreyk struct curve25519_key {
5645135ebcSreyk 	u_int8_t	 secret[CURVE25519_SIZE];
5745135ebcSreyk 	u_int8_t	 public[CURVE25519_SIZE];
5845135ebcSreyk };
5945135ebcSreyk extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE],
6045135ebcSreyk     const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE])
6145135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
6245135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)))
6345135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE)));
6445135ebcSreyk 
6545ae9d61Sreyk struct group_id ike_groups[] = {
6645ae9d61Sreyk 	{ GROUP_MODP, 1, 768,
6745ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
6845ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
6945ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
7045ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
7145ae9d61Sreyk 	    "02"
7245ae9d61Sreyk 	},
7345ae9d61Sreyk 	{ GROUP_MODP, 2, 1024,
7445ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
7545ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
7645ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
7745ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
7845ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
7945ae9d61Sreyk 	    "FFFFFFFFFFFFFFFF",
8045ae9d61Sreyk 	    "02"
8145ae9d61Sreyk 	},
82369beec1Sreyk 	{ GROUP_EC2N, 3, 155, NULL, NULL, NID_ipsec3 },
83369beec1Sreyk 	{ GROUP_EC2N, 4, 185, NULL, NULL, NID_ipsec4 },
8445ae9d61Sreyk 	{ GROUP_MODP, 5, 1536,
8545ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
8645ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
8745ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
8845ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
8945ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
9045ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
9145ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
9245ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
9345ae9d61Sreyk 	    "02"
9445ae9d61Sreyk 	},
9545ae9d61Sreyk 	{ GROUP_MODP, 14, 2048,
9645ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
9745ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
9845ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
9945ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
10045ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
10145ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
10245ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
10345ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
10445ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
10545ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
10645ae9d61Sreyk 	    "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
10745ae9d61Sreyk 	    "02"
10845ae9d61Sreyk 	},
10945ae9d61Sreyk 	{ GROUP_MODP, 15, 3072,
11045ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
11145ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
11245ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
11345ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
11445ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
11545ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
11645ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
11745ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
11845ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
11945ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
12045ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
12145ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
12245ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
12345ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
12445ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
12545ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF",
12645ae9d61Sreyk 	    "02"
12745ae9d61Sreyk 	},
12845ae9d61Sreyk 	{ GROUP_MODP, 16, 4096,
12945ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
13045ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
13145ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
13245ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
13345ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
13445ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
13545ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
13645ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
13745ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
13845ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
13945ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
14045ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
14145ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
14245ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
14345ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
14445ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
14545ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
14645ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
14745ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
14845ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
14945ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
15045ae9d61Sreyk 	    "FFFFFFFFFFFFFFFF",
15145ae9d61Sreyk 	    "02"
15245ae9d61Sreyk 	},
15345ae9d61Sreyk 	{ GROUP_MODP, 17, 6144,
15445ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
15545ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
15645ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
15745ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
15845ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
15945ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
16045ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
16145ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
16245ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
16345ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
16445ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
16545ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
16645ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
16745ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
16845ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
16945ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
17045ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
17145ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
17245ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
17345ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
17445ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
17545ae9d61Sreyk 	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
17645ae9d61Sreyk 	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
17745ae9d61Sreyk 	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
17845ae9d61Sreyk 	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
17945ae9d61Sreyk 	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
18045ae9d61Sreyk 	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
18145ae9d61Sreyk 	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
18245ae9d61Sreyk 	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
18345ae9d61Sreyk 	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
18445ae9d61Sreyk 	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
18545ae9d61Sreyk 	    "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF",
18645ae9d61Sreyk 	    "02"
18745ae9d61Sreyk 	},
18845ae9d61Sreyk 	{ GROUP_MODP, 18, 8192,
18945ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
19045ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
19145ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
19245ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
19345ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
19445ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
19545ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
19645ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
19745ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
19845ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
19945ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
20045ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
20145ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
20245ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
20345ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
20445ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
20545ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
20645ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
20745ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
20845ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
20945ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
21045ae9d61Sreyk 	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
21145ae9d61Sreyk 	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
21245ae9d61Sreyk 	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
21345ae9d61Sreyk 	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
21445ae9d61Sreyk 	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
21545ae9d61Sreyk 	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
21645ae9d61Sreyk 	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
21745ae9d61Sreyk 	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
21845ae9d61Sreyk 	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
21945ae9d61Sreyk 	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
22045ae9d61Sreyk 	    "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
22145ae9d61Sreyk 	    "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
22245ae9d61Sreyk 	    "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
22345ae9d61Sreyk 	    "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
22445ae9d61Sreyk 	    "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
22545ae9d61Sreyk 	    "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
22645ae9d61Sreyk 	    "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
22745ae9d61Sreyk 	    "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
22845ae9d61Sreyk 	    "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
22945ae9d61Sreyk 	    "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
23045ae9d61Sreyk 	    "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
23145ae9d61Sreyk 	    "60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
23245ae9d61Sreyk 	    "02"
23345ae9d61Sreyk 	},
234369beec1Sreyk 	{ GROUP_ECP, 19, 256, NULL, NULL, NID_X9_62_prime256v1 },
235369beec1Sreyk 	{ GROUP_ECP, 20, 384, NULL, NULL, NID_secp384r1 },
236369beec1Sreyk 	{ GROUP_ECP, 21, 521, NULL, NULL, NID_secp521r1 },
23745ae9d61Sreyk 	{ GROUP_MODP, 22, 1024,
23845ae9d61Sreyk 	    "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C6"
23945ae9d61Sreyk 	    "9A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C0"
24045ae9d61Sreyk 	    "13ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD70"
24145ae9d61Sreyk 	    "98488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0"
24245ae9d61Sreyk 	    "A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708"
24345ae9d61Sreyk 	    "DF1FB2BC2E4A4371",
24445ae9d61Sreyk 	    "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507F"
24545ae9d61Sreyk 	    "D6406CFF14266D31266FEA1E5C41564B777E690F5504F213"
24645ae9d61Sreyk 	    "160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1"
24745ae9d61Sreyk 	    "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A"
24845ae9d61Sreyk 	    "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24"
24945ae9d61Sreyk 	    "855E6EEB22B3B2E5"
25045ae9d61Sreyk 	},
25145ae9d61Sreyk 	{ GROUP_MODP, 23, 2048,
25245ae9d61Sreyk 	    "AD107E1E9123A9D0D660FAA79559C51FA20D64E5683B9FD1"
25345ae9d61Sreyk 	    "B54B1597B61D0A75E6FA141DF95A56DBAF9A3C407BA1DF15"
25445ae9d61Sreyk 	    "EB3D688A309C180E1DE6B85A1274A0A66D3F8152AD6AC212"
25545ae9d61Sreyk 	    "9037C9EDEFDA4DF8D91E8FEF55B7394B7AD5B7D0B6C12207"
25645ae9d61Sreyk 	    "C9F98D11ED34DBF6C6BA0B2C8BBC27BE6A00E0A0B9C49708"
25745ae9d61Sreyk 	    "B3BF8A317091883681286130BC8985DB1602E714415D9330"
25845ae9d61Sreyk 	    "278273C7DE31EFDC7310F7121FD5A07415987D9ADC0A486D"
25945ae9d61Sreyk 	    "CDF93ACC44328387315D75E198C641A480CD86A1B9E587E8"
26045ae9d61Sreyk 	    "BE60E69CC928B2B9C52172E413042E9B23F10B0E16E79763"
26145ae9d61Sreyk 	    "C9B53DCF4BA80A29E3FB73C16B8E75B97EF363E2FFA31F71"
26245ae9d61Sreyk 	    "CF9DE5384E71B81C0AC4DFFE0C10E64F",
26345ae9d61Sreyk 	    "AC4032EF4F2D9AE39DF30B5C8FFDAC506CDEBE7B89998CAF"
26445ae9d61Sreyk 	    "74866A08CFE4FFE3A6824A4E10B9A6F0DD921F01A70C4AFA"
26545ae9d61Sreyk 	    "AB739D7700C29F52C57DB17C620A8652BE5E9001A8D66AD7"
26645ae9d61Sreyk 	    "C17669101999024AF4D027275AC1348BB8A762D0521BC98A"
26745ae9d61Sreyk 	    "E247150422EA1ED409939D54DA7460CDB5F6C6B250717CBE"
26845ae9d61Sreyk 	    "F180EB34118E98D119529A45D6F834566E3025E316A330EF"
26945ae9d61Sreyk 	    "BB77A86F0C1AB15B051AE3D428C8F8ACB70A8137150B8EEB"
27045ae9d61Sreyk 	    "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381"
27145ae9d61Sreyk 	    "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269"
27245ae9d61Sreyk 	    "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179"
27345ae9d61Sreyk 	    "81BC087F2A7065B384B890D3191F2BFA"
27445ae9d61Sreyk 	},
27545ae9d61Sreyk 	{ GROUP_MODP, 24, 2048,
27645ae9d61Sreyk 	    "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F2"
27745ae9d61Sreyk 	    "5D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA30"
27845ae9d61Sreyk 	    "16C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD"
27945ae9d61Sreyk 	    "5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B"
28045ae9d61Sreyk 	    "6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C"
28145ae9d61Sreyk 	    "4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0E"
28245ae9d61Sreyk 	    "F13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D9"
28345ae9d61Sreyk 	    "67E144E5140564251CCACB83E6B486F6B3CA3F7971506026"
28445ae9d61Sreyk 	    "C0B857F689962856DED4010ABD0BE621C3A3960A54E710C3"
28545ae9d61Sreyk 	    "75F26375D7014103A4B54330C198AF126116D2276E11715F"
28645ae9d61Sreyk 	    "693877FAD7EF09CADB094AE91E1A1597",
28745ae9d61Sreyk 	    "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF2054"
28845ae9d61Sreyk 	    "07F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555"
28945ae9d61Sreyk 	    "BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18"
29045ae9d61Sreyk 	    "A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B"
29145ae9d61Sreyk 	    "777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC83"
29245ae9d61Sreyk 	    "1D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55"
29345ae9d61Sreyk 	    "A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14"
29445ae9d61Sreyk 	    "C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915"
29545ae9d61Sreyk 	    "B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6"
29645ae9d61Sreyk 	    "184B523D1DB246C32F63078490F00EF8D647D148D4795451"
29745ae9d61Sreyk 	    "5E2327CFEF98C582664B4C0F6CC41659"
29845ae9d61Sreyk 	},
299369beec1Sreyk 	{ GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 },
300547eb84dSreyk 	{ GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 },
301547eb84dSreyk 	{ GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 },
302547eb84dSreyk 	{ GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 },
303547eb84dSreyk 	{ GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 },
30445135ebcSreyk 	{ GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 },
30545135ebcSreyk 
30645135ebcSreyk 	/* "Private use" extensions */
30745135ebcSreyk 	{ GROUP_CURVE25519, 1034, CURVE25519_SIZE * 8 }
30845ae9d61Sreyk };
30945ae9d61Sreyk 
31045ae9d61Sreyk void
31145ae9d61Sreyk group_init(void)
31245ae9d61Sreyk {
3130d5bf58dSreyk 	/* currently not used */
31445ae9d61Sreyk 	return;
31545ae9d61Sreyk }
31645ae9d61Sreyk 
31745ae9d61Sreyk void
31845ae9d61Sreyk group_free(struct group *group)
31945ae9d61Sreyk {
32045ae9d61Sreyk 	if (group == NULL)
32145ae9d61Sreyk 		return;
32245ae9d61Sreyk 	if (group->dh != NULL)
32345ae9d61Sreyk 		DH_free(group->dh);
32445ae9d61Sreyk 	if (group->ec != NULL)
32545ae9d61Sreyk 		EC_KEY_free(group->ec);
32645135ebcSreyk 	if (group->curve25519 != NULL) {
32745135ebcSreyk 		explicit_bzero(group->curve25519,
32845135ebcSreyk 		    sizeof(struct curve25519_key));
32945135ebcSreyk 		free(group->curve25519);
33045135ebcSreyk 	}
33145ae9d61Sreyk 	group->spec = NULL;
33264449014Sreyk 	free(group);
33345ae9d61Sreyk }
33445ae9d61Sreyk 
33545ae9d61Sreyk struct group *
33645ae9d61Sreyk group_get(u_int32_t id)
33745ae9d61Sreyk {
33845ae9d61Sreyk 	struct group_id	*p = NULL;
33945ae9d61Sreyk 	struct group	*group;
34045ae9d61Sreyk 	u_int		 i, items;
34145ae9d61Sreyk 
34245ae9d61Sreyk 	items = sizeof(ike_groups) / sizeof(ike_groups[0]);
34345ae9d61Sreyk 	for (i = 0; i < items; i++) {
34445ae9d61Sreyk 		if (id == ike_groups[i].id) {
34545ae9d61Sreyk 			p = &ike_groups[i];
34645ae9d61Sreyk 			break;
34745ae9d61Sreyk 		}
34845ae9d61Sreyk 	}
34945ae9d61Sreyk 	if (p == NULL)
35045ae9d61Sreyk 		return (NULL);
35145ae9d61Sreyk 
35245ae9d61Sreyk 	if ((group = calloc(1, sizeof(*group))) == NULL)
35345ae9d61Sreyk 		return (NULL);
35445ae9d61Sreyk 
35545ae9d61Sreyk 	group->id = id;
35645ae9d61Sreyk 	group->spec = p;
35745ae9d61Sreyk 
35845ae9d61Sreyk 	switch (p->type) {
35945ae9d61Sreyk 	case GROUP_MODP:
36045ae9d61Sreyk 		group->init = modp_init;
36145ae9d61Sreyk 		group->getlen = modp_getlen;
36245ae9d61Sreyk 		group->exchange = modp_create_exchange;
36345ae9d61Sreyk 		group->shared = modp_create_shared;
36445ae9d61Sreyk 		break;
365369beec1Sreyk 	case GROUP_EC2N:
366369beec1Sreyk 	case GROUP_ECP:
36745ae9d61Sreyk 		group->init = ec_init;
36845ae9d61Sreyk 		group->getlen = ec_getlen;
36945ae9d61Sreyk 		group->exchange = ec_create_exchange;
37045ae9d61Sreyk 		group->shared = ec_create_shared;
37145ae9d61Sreyk 		break;
37245135ebcSreyk 	case GROUP_CURVE25519:
37345135ebcSreyk 		group->init = ec25519_init;
37445135ebcSreyk 		group->getlen = ec25519_getlen;
37545135ebcSreyk 		group->exchange = ec25519_create_exchange;
37645135ebcSreyk 		group->shared = ec25519_create_shared;
37745135ebcSreyk 		break;
37845ae9d61Sreyk 	default:
37945ae9d61Sreyk 		group_free(group);
38045ae9d61Sreyk 		return (NULL);
38145ae9d61Sreyk 	}
38245ae9d61Sreyk 
38345ae9d61Sreyk 	if (dh_init(group) != 0) {
38445ae9d61Sreyk 		group_free(group);
38545ae9d61Sreyk 		return (NULL);
38645ae9d61Sreyk 	}
38745ae9d61Sreyk 
38845ae9d61Sreyk 	return (group);
38945ae9d61Sreyk }
39045ae9d61Sreyk 
39145ae9d61Sreyk int
39245ae9d61Sreyk dh_init(struct group *group)
39345ae9d61Sreyk {
39445ae9d61Sreyk 	return (group->init(group));
39545ae9d61Sreyk }
39645ae9d61Sreyk 
39745ae9d61Sreyk int
39845ae9d61Sreyk dh_getlen(struct group *group)
39945ae9d61Sreyk {
40045ae9d61Sreyk 	return (group->getlen(group));
40145ae9d61Sreyk }
40245ae9d61Sreyk 
40345ae9d61Sreyk int
40445ae9d61Sreyk dh_create_exchange(struct group *group, u_int8_t *buf)
40545ae9d61Sreyk {
40645ae9d61Sreyk 	return (group->exchange(group, buf));
40745ae9d61Sreyk }
40845ae9d61Sreyk 
40945ae9d61Sreyk int
41045ae9d61Sreyk dh_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
41145ae9d61Sreyk {
41245ae9d61Sreyk 	return (group->shared(group, secret, exchange));
41345ae9d61Sreyk }
41445ae9d61Sreyk 
41545ae9d61Sreyk int
41645ae9d61Sreyk modp_init(struct group *group)
41745ae9d61Sreyk {
41845ae9d61Sreyk 	DH	*dh;
41945ae9d61Sreyk 
42045ae9d61Sreyk 	if ((dh = DH_new()) == NULL)
42145ae9d61Sreyk 		return (-1);
4227d7b0856Sreyk 	group->dh = dh;
42345ae9d61Sreyk 
42445ae9d61Sreyk 	if (!BN_hex2bn(&dh->p, group->spec->prime) ||
42545ae9d61Sreyk 	    !BN_hex2bn(&dh->g, group->spec->generator))
42645ae9d61Sreyk 		return (-1);
42745ae9d61Sreyk 
42845ae9d61Sreyk 	return (0);
42945ae9d61Sreyk }
43045ae9d61Sreyk 
43145ae9d61Sreyk int
43245ae9d61Sreyk modp_getlen(struct group *group)
43345ae9d61Sreyk {
43445ae9d61Sreyk 	if (group->spec == NULL)
43545ae9d61Sreyk 		return (0);
43645ae9d61Sreyk 	return (roundup(group->spec->bits, 8) / 8);
43745ae9d61Sreyk }
43845ae9d61Sreyk 
43945ae9d61Sreyk int
44045ae9d61Sreyk modp_create_exchange(struct group *group, u_int8_t *buf)
44145ae9d61Sreyk {
44245ae9d61Sreyk 	DH	*dh = group->dh;
44312abf43bSmikeb 	int	 len, ret;
44445ae9d61Sreyk 
44545ae9d61Sreyk 	if (!DH_generate_key(dh))
44645ae9d61Sreyk 		return (-1);
44712abf43bSmikeb 	ret = BN_bn2bin(dh->pub_key, buf);
44812abf43bSmikeb 	if (!ret)
44945ae9d61Sreyk 		return (-1);
45045ae9d61Sreyk 
45112abf43bSmikeb 	len = dh_getlen(group);
45212abf43bSmikeb 
45312abf43bSmikeb 	/* add zero padding */
45412abf43bSmikeb 	if (ret < len) {
45512abf43bSmikeb 		bcopy(buf, buf + (len - ret), ret);
45612abf43bSmikeb 		bzero(buf, len - ret);
45712abf43bSmikeb 	}
45812abf43bSmikeb 
4597d7b0856Sreyk 	return (0);
46045ae9d61Sreyk }
46145ae9d61Sreyk 
46245ae9d61Sreyk int
46345ae9d61Sreyk modp_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
46445ae9d61Sreyk {
46545ae9d61Sreyk 	BIGNUM	*ex;
46612abf43bSmikeb 	int	 len, ret;
46745ae9d61Sreyk 
46812abf43bSmikeb 	len = dh_getlen(group);
46912abf43bSmikeb 
47012abf43bSmikeb 	if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL)
47145ae9d61Sreyk 		return (-1);
4727d7b0856Sreyk 
4737d7b0856Sreyk 	ret = DH_compute_key(secret, ex, group->dh);
4747d7b0856Sreyk 	BN_clear_free(ex);
475*2ffa77eaSjsg 	if (ret <= 0)
47645ae9d61Sreyk 		return (-1);
47745ae9d61Sreyk 
47812abf43bSmikeb 	/* add zero padding */
47912abf43bSmikeb 	if (ret < len) {
48012abf43bSmikeb 		bcopy(secret, secret + (len - ret), ret);
48112abf43bSmikeb 		bzero(secret, len - ret);
48212abf43bSmikeb 	}
48312abf43bSmikeb 
4847d7b0856Sreyk 	return (0);
48545ae9d61Sreyk }
48645ae9d61Sreyk 
48745ae9d61Sreyk int
48845ae9d61Sreyk ec_init(struct group *group)
48945ae9d61Sreyk {
49045ae9d61Sreyk 	if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL)
49145ae9d61Sreyk 		return (-1);
49245ae9d61Sreyk 	if (!EC_KEY_generate_key(group->ec))
49345ae9d61Sreyk 		return (-1);
494c900656bSmarkus 	if (!EC_KEY_check_key(group->ec)) {
495c900656bSmarkus 		EC_KEY_free(group->ec);
496c900656bSmarkus 		return (-1);
497c900656bSmarkus 	}
49845ae9d61Sreyk 	return (0);
49945ae9d61Sreyk }
50045ae9d61Sreyk 
50145ae9d61Sreyk int
50245ae9d61Sreyk ec_getlen(struct group *group)
50345ae9d61Sreyk {
50445ae9d61Sreyk 	if (group->spec == NULL)
50545ae9d61Sreyk 		return (0);
50645b72fd1Smikeb 	/* NB:  Return value will always be even */
50745ae9d61Sreyk 	return ((roundup(group->spec->bits, 8) * 2) / 8);
50845ae9d61Sreyk }
50945ae9d61Sreyk 
51045ae9d61Sreyk int
51145ae9d61Sreyk ec_create_exchange(struct group *group, u_int8_t *buf)
51245ae9d61Sreyk {
5130d5bf58dSreyk 	size_t	 len;
5140d5bf58dSreyk 
5150d5bf58dSreyk 	len = ec_getlen(group);
5160d5bf58dSreyk 	bzero(buf, len);
5170d5bf58dSreyk 
51845ae9d61Sreyk 	return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec),
5190d5bf58dSreyk 	    buf, len));
52045ae9d61Sreyk }
52145ae9d61Sreyk 
52245ae9d61Sreyk int
52345ae9d61Sreyk ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
52445ae9d61Sreyk {
52545ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
52645ae9d61Sreyk 	const BIGNUM	*privkey;
527c900656bSmarkus 	EC_KEY		*exkey = NULL;
52845ae9d61Sreyk 	EC_POINT	*exchangep = NULL, *secretp = NULL;
52945ae9d61Sreyk 	int		 ret = -1;
53045ae9d61Sreyk 
53145ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL ||
53245ae9d61Sreyk 	    (privkey = EC_KEY_get0_private_key(group->ec)) == NULL)
53345ae9d61Sreyk 		goto done;
53445ae9d61Sreyk 
53545ae9d61Sreyk 	if ((exchangep =
53645ae9d61Sreyk 	    ec_raw2point(group, exchange, ec_getlen(group))) == NULL)
53745ae9d61Sreyk 		goto done;
53845ae9d61Sreyk 
539c900656bSmarkus 	if ((exkey = EC_KEY_new()) == NULL)
540c900656bSmarkus 		goto done;
541c900656bSmarkus 	if (!EC_KEY_set_group(exkey, ecgroup))
542c900656bSmarkus 		goto done;
543c900656bSmarkus 	if (!EC_KEY_set_public_key(exkey, exchangep))
544c900656bSmarkus 		goto done;
545c900656bSmarkus 
546c900656bSmarkus 	/* validate exchangep */
547c900656bSmarkus 	if (!EC_KEY_check_key(exkey))
548c900656bSmarkus 		goto done;
549c900656bSmarkus 
55045ae9d61Sreyk 	if ((secretp = EC_POINT_new(ecgroup)) == NULL)
55145ae9d61Sreyk 		goto done;
55245ae9d61Sreyk 
55345ae9d61Sreyk 	if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL))
55445ae9d61Sreyk 		goto done;
55545ae9d61Sreyk 
55645ae9d61Sreyk 	ret = ec_point2raw(group, secretp, secret, ec_getlen(group));
55745ae9d61Sreyk 
55845ae9d61Sreyk  done:
559c900656bSmarkus 	if (exkey != NULL)
560c900656bSmarkus 		EC_KEY_free(exkey);
56145ae9d61Sreyk 	if (exchangep != NULL)
56245ae9d61Sreyk 		EC_POINT_clear_free(exchangep);
56345ae9d61Sreyk 	if (secretp != NULL)
56445ae9d61Sreyk 		EC_POINT_clear_free(secretp);
56545ae9d61Sreyk 
56645ae9d61Sreyk 	return (ret);
56745ae9d61Sreyk }
56845ae9d61Sreyk 
56945ae9d61Sreyk int
57045ae9d61Sreyk ec_point2raw(struct group *group, const EC_POINT *point,
57145ae9d61Sreyk     u_int8_t *buf, size_t len)
57245ae9d61Sreyk {
57345ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
57445ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
57545ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
57645ae9d61Sreyk 	int		 ret = -1;
57745b72fd1Smikeb 	size_t		 eclen, xlen, ylen;
57845ae9d61Sreyk 	off_t		 xoff, yoff;
57945ae9d61Sreyk 
58045ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
58145ae9d61Sreyk 		goto done;
58245ae9d61Sreyk 	BN_CTX_start(bnctx);
58345ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
58445ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
58545ae9d61Sreyk 		goto done;
58645ae9d61Sreyk 
58745b72fd1Smikeb 	eclen = ec_getlen(group);
58845b72fd1Smikeb 	if (len < eclen)
58945b72fd1Smikeb 		goto done;
59045b72fd1Smikeb 	xlen = ylen = eclen / 2;
59145b72fd1Smikeb 
59245ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
59345ae9d61Sreyk 		goto done;
59445ae9d61Sreyk 
59545ae9d61Sreyk 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) ==
59645ae9d61Sreyk 	    NID_X9_62_prime_field) {
59745ae9d61Sreyk 		if (!EC_POINT_get_affine_coordinates_GFp(ecgroup,
59845ae9d61Sreyk 		    point, x, y, bnctx))
59945ae9d61Sreyk 			goto done;
60045ae9d61Sreyk 	} else {
60145ae9d61Sreyk 		if (!EC_POINT_get_affine_coordinates_GF2m(ecgroup,
60245ae9d61Sreyk 		    point, x, y, bnctx))
60345ae9d61Sreyk 			goto done;
60445ae9d61Sreyk 	}
60545ae9d61Sreyk 
60645ae9d61Sreyk 	xoff = xlen - BN_num_bytes(x);
60745b72fd1Smikeb 	bzero(buf, xoff);
60845ae9d61Sreyk 	if (!BN_bn2bin(x, buf + xoff))
60945ae9d61Sreyk 		goto done;
61045ae9d61Sreyk 
61145ae9d61Sreyk 	yoff = (ylen - BN_num_bytes(y)) + xlen;
61245b72fd1Smikeb 	bzero(buf + xlen, yoff - xlen);
61345ae9d61Sreyk 	if (!BN_bn2bin(y, buf + yoff))
61445ae9d61Sreyk 		goto done;
61545ae9d61Sreyk 
61645ae9d61Sreyk 	ret = 0;
61745ae9d61Sreyk  done:
618c900656bSmarkus 	/* Make sure to erase sensitive data */
619c900656bSmarkus 	if (x != NULL)
620c900656bSmarkus 		BN_clear(x);
621c900656bSmarkus 	if (y != NULL)
622c900656bSmarkus 		BN_clear(y);
62345ae9d61Sreyk 	BN_CTX_end(bnctx);
62445ae9d61Sreyk 	BN_CTX_free(bnctx);
62545ae9d61Sreyk 
62645ae9d61Sreyk 	return (ret);
62745ae9d61Sreyk }
62845ae9d61Sreyk 
62945ae9d61Sreyk EC_POINT *
63045ae9d61Sreyk ec_raw2point(struct group *group, u_int8_t *buf, size_t len)
63145ae9d61Sreyk {
63245ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
63345ae9d61Sreyk 	EC_POINT	*point = NULL;
63445ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
63545ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
63645ae9d61Sreyk 	int		 ret = -1;
63745ae9d61Sreyk 	size_t		 eclen;
63845ae9d61Sreyk 	size_t		 xlen, ylen;
63945ae9d61Sreyk 
64045ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
64145ae9d61Sreyk 		goto done;
64245ae9d61Sreyk 	BN_CTX_start(bnctx);
64345ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
64445ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
64545ae9d61Sreyk 		goto done;
64645ae9d61Sreyk 
64745ae9d61Sreyk 	eclen = ec_getlen(group);
64845ae9d61Sreyk 	if (len < eclen)
64945ae9d61Sreyk 		goto done;
65045ae9d61Sreyk 	xlen = ylen = eclen / 2;
65145ae9d61Sreyk 	if ((x = BN_bin2bn(buf, xlen, x)) == NULL ||
65245ae9d61Sreyk 	    (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL)
65345ae9d61Sreyk 		goto done;
65445ae9d61Sreyk 
65545ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
65645ae9d61Sreyk 		goto done;
65745ae9d61Sreyk 
65845ae9d61Sreyk 	if ((point = EC_POINT_new(ecgroup)) == NULL)
65945ae9d61Sreyk 		goto done;
66045ae9d61Sreyk 
66145ae9d61Sreyk 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) ==
66245ae9d61Sreyk 	    NID_X9_62_prime_field) {
66345ae9d61Sreyk 		if (!EC_POINT_set_affine_coordinates_GFp(ecgroup,
66445ae9d61Sreyk 		    point, x, y, bnctx))
66545ae9d61Sreyk 			goto done;
66645ae9d61Sreyk 	} else {
66745ae9d61Sreyk 		if (!EC_POINT_set_affine_coordinates_GF2m(ecgroup,
66845ae9d61Sreyk 		    point, x, y, bnctx))
66945ae9d61Sreyk 			goto done;
67045ae9d61Sreyk 	}
67145ae9d61Sreyk 
67245ae9d61Sreyk 	ret = 0;
67345ae9d61Sreyk  done:
67445ae9d61Sreyk 	if (ret != 0 && point != NULL)
67545ae9d61Sreyk 		EC_POINT_clear_free(point);
676c900656bSmarkus 	/* Make sure to erase sensitive data */
677c900656bSmarkus 	if (x != NULL)
678c900656bSmarkus 		BN_clear(x);
679c900656bSmarkus 	if (y != NULL)
680c900656bSmarkus 		BN_clear(y);
68145ae9d61Sreyk 	BN_CTX_end(bnctx);
68245ae9d61Sreyk 	BN_CTX_free(bnctx);
68345ae9d61Sreyk 
68445ae9d61Sreyk 	return (point);
68545ae9d61Sreyk }
68645135ebcSreyk 
68745135ebcSreyk int
68845135ebcSreyk ec25519_init(struct group *group)
68945135ebcSreyk {
69045135ebcSreyk 	static const u_int8_t	 basepoint[CURVE25519_SIZE] = { 9 };
69145135ebcSreyk 	struct curve25519_key	*curve25519;
69245135ebcSreyk 
69345135ebcSreyk 	if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL)
69445135ebcSreyk 		return (-1);
69545135ebcSreyk 
69645135ebcSreyk 	group->curve25519 = curve25519;
69745135ebcSreyk 
69845135ebcSreyk 	arc4random_buf(curve25519->secret, CURVE25519_SIZE);
69945135ebcSreyk 	crypto_scalarmult_curve25519(curve25519->public,
70045135ebcSreyk 	    curve25519->secret, basepoint);
70145135ebcSreyk 
70245135ebcSreyk 	return (0);
70345135ebcSreyk }
70445135ebcSreyk 
70545135ebcSreyk int
70645135ebcSreyk ec25519_getlen(struct group *group)
70745135ebcSreyk {
70845135ebcSreyk 	if (group->spec == NULL)
70945135ebcSreyk 		return (0);
71045135ebcSreyk 	return (CURVE25519_SIZE);
71145135ebcSreyk }
71245135ebcSreyk 
71345135ebcSreyk int
71445135ebcSreyk ec25519_create_exchange(struct group *group, u_int8_t *buf)
71545135ebcSreyk {
71645135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
71745135ebcSreyk 
71845135ebcSreyk 	memcpy(buf, curve25519->public, ec25519_getlen(group));
71945135ebcSreyk 	return (0);
72045135ebcSreyk }
72145135ebcSreyk 
72245135ebcSreyk int
72345135ebcSreyk ec25519_create_shared(struct group *group, u_int8_t *shared, u_int8_t *public)
72445135ebcSreyk {
72545135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
72645135ebcSreyk 
72745135ebcSreyk 	crypto_scalarmult_curve25519(shared, curve25519->secret, public);
72845135ebcSreyk 	return (0);
72945135ebcSreyk }
730