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