xref: /openbsd/sbin/iked/dh.c (revision 29b4e2ea)
1*29b4e2eaSderaadt /*	$OpenBSD: dh.c,v 1.20 2017/05/21 02:37:52 deraadt 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 *);
35d09d3a7dSreyk int	modp_create_exchange(struct group *, uint8_t *);
36d09d3a7dSreyk 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 *);
41d09d3a7dSreyk int	ec_create_exchange(struct group *, uint8_t *);
42d09d3a7dSreyk int	ec_create_shared(struct group *, uint8_t *, uint8_t *);
4345ae9d61Sreyk 
44d09d3a7dSreyk int	ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t);
4545ae9d61Sreyk EC_POINT *
46d09d3a7dSreyk 	ec_raw2point(struct group *, uint8_t *, size_t);
4745ae9d61Sreyk 
4845135ebcSreyk /* curve25519 */
4945135ebcSreyk int	ec25519_init(struct group *);
5045135ebcSreyk int	ec25519_getlen(struct group *);
51d09d3a7dSreyk int	ec25519_create_exchange(struct group *, uint8_t *);
52d09d3a7dSreyk int	ec25519_create_shared(struct group *, uint8_t *, uint8_t *);
5345135ebcSreyk 
5445135ebcSreyk #define CURVE25519_SIZE 32	/* 256 bits */
5545135ebcSreyk struct curve25519_key {
56d09d3a7dSreyk 	uint8_t		 secret[CURVE25519_SIZE];
57d09d3a7dSreyk 	uint8_t		 public[CURVE25519_SIZE];
5845135ebcSreyk };
59d09d3a7dSreyk extern int crypto_scalarmult_curve25519(unsigned char a[CURVE25519_SIZE],
60d09d3a7dSreyk     const unsigned char b[CURVE25519_SIZE],
61d09d3a7dSreyk     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 
66e254d6eaSmikeb const 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 },
238369beec1Sreyk 	{ GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 },
239547eb84dSreyk 	{ GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 },
240547eb84dSreyk 	{ GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 },
241547eb84dSreyk 	{ GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 },
242547eb84dSreyk 	{ GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 },
24345135ebcSreyk 	{ GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 },
24445135ebcSreyk 
24545135ebcSreyk 	/* "Private use" extensions */
24645135ebcSreyk 	{ GROUP_CURVE25519, 1034, CURVE25519_SIZE * 8 }
24745ae9d61Sreyk };
24845ae9d61Sreyk 
24945ae9d61Sreyk void
25045ae9d61Sreyk group_init(void)
25145ae9d61Sreyk {
2520d5bf58dSreyk 	/* currently not used */
25345ae9d61Sreyk 	return;
25445ae9d61Sreyk }
25545ae9d61Sreyk 
25645ae9d61Sreyk void
25745ae9d61Sreyk group_free(struct group *group)
25845ae9d61Sreyk {
25945ae9d61Sreyk 	if (group == NULL)
26045ae9d61Sreyk 		return;
26145ae9d61Sreyk 	if (group->dh != NULL)
26245ae9d61Sreyk 		DH_free(group->dh);
26345ae9d61Sreyk 	if (group->ec != NULL)
26445ae9d61Sreyk 		EC_KEY_free(group->ec);
265*29b4e2eaSderaadt 	freezero(group->curve25519, sizeof(struct curve25519_key));
26645ae9d61Sreyk 	group->spec = NULL;
26764449014Sreyk 	free(group);
26845ae9d61Sreyk }
26945ae9d61Sreyk 
27045ae9d61Sreyk struct group *
271d09d3a7dSreyk group_get(uint32_t id)
27245ae9d61Sreyk {
273e254d6eaSmikeb 	const struct group_id	*p;
27445ae9d61Sreyk 	struct group		*group;
27545ae9d61Sreyk 
276e254d6eaSmikeb 	if ((p = group_getid(id)) == NULL)
27745ae9d61Sreyk 		return (NULL);
27845ae9d61Sreyk 
27945ae9d61Sreyk 	if ((group = calloc(1, sizeof(*group))) == NULL)
28045ae9d61Sreyk 		return (NULL);
28145ae9d61Sreyk 
28245ae9d61Sreyk 	group->id = id;
28345ae9d61Sreyk 	group->spec = p;
28445ae9d61Sreyk 
28545ae9d61Sreyk 	switch (p->type) {
28645ae9d61Sreyk 	case GROUP_MODP:
28745ae9d61Sreyk 		group->init = modp_init;
28845ae9d61Sreyk 		group->getlen = modp_getlen;
28945ae9d61Sreyk 		group->exchange = modp_create_exchange;
29045ae9d61Sreyk 		group->shared = modp_create_shared;
29145ae9d61Sreyk 		break;
292369beec1Sreyk 	case GROUP_EC2N:
293369beec1Sreyk 	case GROUP_ECP:
29445ae9d61Sreyk 		group->init = ec_init;
29545ae9d61Sreyk 		group->getlen = ec_getlen;
29645ae9d61Sreyk 		group->exchange = ec_create_exchange;
29745ae9d61Sreyk 		group->shared = ec_create_shared;
29845ae9d61Sreyk 		break;
29945135ebcSreyk 	case GROUP_CURVE25519:
30045135ebcSreyk 		group->init = ec25519_init;
30145135ebcSreyk 		group->getlen = ec25519_getlen;
30245135ebcSreyk 		group->exchange = ec25519_create_exchange;
30345135ebcSreyk 		group->shared = ec25519_create_shared;
30445135ebcSreyk 		break;
30545ae9d61Sreyk 	default:
30645ae9d61Sreyk 		group_free(group);
30745ae9d61Sreyk 		return (NULL);
30845ae9d61Sreyk 	}
30945ae9d61Sreyk 
31045ae9d61Sreyk 	if (dh_init(group) != 0) {
31145ae9d61Sreyk 		group_free(group);
31245ae9d61Sreyk 		return (NULL);
31345ae9d61Sreyk 	}
31445ae9d61Sreyk 
31545ae9d61Sreyk 	return (group);
31645ae9d61Sreyk }
31745ae9d61Sreyk 
318e254d6eaSmikeb const struct group_id *
319e254d6eaSmikeb group_getid(uint32_t id)
320e254d6eaSmikeb {
321e254d6eaSmikeb 	const struct group_id	*p = NULL;
322e254d6eaSmikeb 	unsigned int		 i, items;
323e254d6eaSmikeb 
324e254d6eaSmikeb 	items = sizeof(ike_groups) / sizeof(ike_groups[0]);
325e254d6eaSmikeb 	for (i = 0; i < items; i++) {
326e254d6eaSmikeb 		if (id == ike_groups[i].id) {
327e254d6eaSmikeb 			p = &ike_groups[i];
328e254d6eaSmikeb 			break;
329e254d6eaSmikeb 		}
330e254d6eaSmikeb 	}
331e254d6eaSmikeb 	return (p);
332e254d6eaSmikeb }
333e254d6eaSmikeb 
33445ae9d61Sreyk int
33545ae9d61Sreyk dh_init(struct group *group)
33645ae9d61Sreyk {
33745ae9d61Sreyk 	return (group->init(group));
33845ae9d61Sreyk }
33945ae9d61Sreyk 
34045ae9d61Sreyk int
34145ae9d61Sreyk dh_getlen(struct group *group)
34245ae9d61Sreyk {
34345ae9d61Sreyk 	return (group->getlen(group));
34445ae9d61Sreyk }
34545ae9d61Sreyk 
34645ae9d61Sreyk int
347d09d3a7dSreyk dh_create_exchange(struct group *group, uint8_t *buf)
34845ae9d61Sreyk {
34945ae9d61Sreyk 	return (group->exchange(group, buf));
35045ae9d61Sreyk }
35145ae9d61Sreyk 
35245ae9d61Sreyk int
353d09d3a7dSreyk dh_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange)
35445ae9d61Sreyk {
35545ae9d61Sreyk 	return (group->shared(group, secret, exchange));
35645ae9d61Sreyk }
35745ae9d61Sreyk 
35845ae9d61Sreyk int
35945ae9d61Sreyk modp_init(struct group *group)
36045ae9d61Sreyk {
36145ae9d61Sreyk 	DH	*dh;
36245ae9d61Sreyk 
36345ae9d61Sreyk 	if ((dh = DH_new()) == NULL)
36445ae9d61Sreyk 		return (-1);
3657d7b0856Sreyk 	group->dh = dh;
36645ae9d61Sreyk 
36745ae9d61Sreyk 	if (!BN_hex2bn(&dh->p, group->spec->prime) ||
36845ae9d61Sreyk 	    !BN_hex2bn(&dh->g, group->spec->generator))
36945ae9d61Sreyk 		return (-1);
37045ae9d61Sreyk 
37145ae9d61Sreyk 	return (0);
37245ae9d61Sreyk }
37345ae9d61Sreyk 
37445ae9d61Sreyk int
37545ae9d61Sreyk modp_getlen(struct group *group)
37645ae9d61Sreyk {
37745ae9d61Sreyk 	if (group->spec == NULL)
37845ae9d61Sreyk 		return (0);
37945ae9d61Sreyk 	return (roundup(group->spec->bits, 8) / 8);
38045ae9d61Sreyk }
38145ae9d61Sreyk 
38245ae9d61Sreyk int
383d09d3a7dSreyk modp_create_exchange(struct group *group, uint8_t *buf)
38445ae9d61Sreyk {
38545ae9d61Sreyk 	DH	*dh = group->dh;
38612abf43bSmikeb 	int	 len, ret;
38745ae9d61Sreyk 
38845ae9d61Sreyk 	if (!DH_generate_key(dh))
38945ae9d61Sreyk 		return (-1);
39012abf43bSmikeb 	ret = BN_bn2bin(dh->pub_key, buf);
39112abf43bSmikeb 	if (!ret)
39245ae9d61Sreyk 		return (-1);
39345ae9d61Sreyk 
39412abf43bSmikeb 	len = dh_getlen(group);
39512abf43bSmikeb 
39612abf43bSmikeb 	/* add zero padding */
39712abf43bSmikeb 	if (ret < len) {
39812abf43bSmikeb 		bcopy(buf, buf + (len - ret), ret);
39912abf43bSmikeb 		bzero(buf, len - ret);
40012abf43bSmikeb 	}
40112abf43bSmikeb 
4027d7b0856Sreyk 	return (0);
40345ae9d61Sreyk }
40445ae9d61Sreyk 
40545ae9d61Sreyk int
406d09d3a7dSreyk modp_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange)
40745ae9d61Sreyk {
40845ae9d61Sreyk 	BIGNUM	*ex;
40912abf43bSmikeb 	int	 len, ret;
41045ae9d61Sreyk 
41112abf43bSmikeb 	len = dh_getlen(group);
41212abf43bSmikeb 
41312abf43bSmikeb 	if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL)
41445ae9d61Sreyk 		return (-1);
4157d7b0856Sreyk 
4167d7b0856Sreyk 	ret = DH_compute_key(secret, ex, group->dh);
4177d7b0856Sreyk 	BN_clear_free(ex);
4182ffa77eaSjsg 	if (ret <= 0)
41945ae9d61Sreyk 		return (-1);
42045ae9d61Sreyk 
42112abf43bSmikeb 	/* add zero padding */
42212abf43bSmikeb 	if (ret < len) {
42312abf43bSmikeb 		bcopy(secret, secret + (len - ret), ret);
42412abf43bSmikeb 		bzero(secret, len - ret);
42512abf43bSmikeb 	}
42612abf43bSmikeb 
4277d7b0856Sreyk 	return (0);
42845ae9d61Sreyk }
42945ae9d61Sreyk 
43045ae9d61Sreyk int
43145ae9d61Sreyk ec_init(struct group *group)
43245ae9d61Sreyk {
43345ae9d61Sreyk 	if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL)
43445ae9d61Sreyk 		return (-1);
43545ae9d61Sreyk 	if (!EC_KEY_generate_key(group->ec))
43645ae9d61Sreyk 		return (-1);
437c900656bSmarkus 	if (!EC_KEY_check_key(group->ec)) {
438c900656bSmarkus 		EC_KEY_free(group->ec);
439c900656bSmarkus 		return (-1);
440c900656bSmarkus 	}
44145ae9d61Sreyk 	return (0);
44245ae9d61Sreyk }
44345ae9d61Sreyk 
44445ae9d61Sreyk int
44545ae9d61Sreyk ec_getlen(struct group *group)
44645ae9d61Sreyk {
44745ae9d61Sreyk 	if (group->spec == NULL)
44845ae9d61Sreyk 		return (0);
44945b72fd1Smikeb 	/* NB:  Return value will always be even */
45045ae9d61Sreyk 	return ((roundup(group->spec->bits, 8) * 2) / 8);
45145ae9d61Sreyk }
45245ae9d61Sreyk 
45345ae9d61Sreyk int
454d09d3a7dSreyk ec_create_exchange(struct group *group, uint8_t *buf)
45545ae9d61Sreyk {
4560d5bf58dSreyk 	size_t	 len;
4570d5bf58dSreyk 
4580d5bf58dSreyk 	len = ec_getlen(group);
4590d5bf58dSreyk 	bzero(buf, len);
4600d5bf58dSreyk 
46145ae9d61Sreyk 	return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec),
4620d5bf58dSreyk 	    buf, len));
46345ae9d61Sreyk }
46445ae9d61Sreyk 
46545ae9d61Sreyk int
466d09d3a7dSreyk ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange)
46745ae9d61Sreyk {
46845ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
46945ae9d61Sreyk 	const BIGNUM	*privkey;
470c900656bSmarkus 	EC_KEY		*exkey = NULL;
47145ae9d61Sreyk 	EC_POINT	*exchangep = NULL, *secretp = NULL;
47245ae9d61Sreyk 	int		 ret = -1;
47345ae9d61Sreyk 
47445ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL ||
47545ae9d61Sreyk 	    (privkey = EC_KEY_get0_private_key(group->ec)) == NULL)
47645ae9d61Sreyk 		goto done;
47745ae9d61Sreyk 
47845ae9d61Sreyk 	if ((exchangep =
47945ae9d61Sreyk 	    ec_raw2point(group, exchange, ec_getlen(group))) == NULL)
48045ae9d61Sreyk 		goto done;
48145ae9d61Sreyk 
482c900656bSmarkus 	if ((exkey = EC_KEY_new()) == NULL)
483c900656bSmarkus 		goto done;
484c900656bSmarkus 	if (!EC_KEY_set_group(exkey, ecgroup))
485c900656bSmarkus 		goto done;
486c900656bSmarkus 	if (!EC_KEY_set_public_key(exkey, exchangep))
487c900656bSmarkus 		goto done;
488c900656bSmarkus 
489c900656bSmarkus 	/* validate exchangep */
490c900656bSmarkus 	if (!EC_KEY_check_key(exkey))
491c900656bSmarkus 		goto done;
492c900656bSmarkus 
49345ae9d61Sreyk 	if ((secretp = EC_POINT_new(ecgroup)) == NULL)
49445ae9d61Sreyk 		goto done;
49545ae9d61Sreyk 
49645ae9d61Sreyk 	if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL))
49745ae9d61Sreyk 		goto done;
49845ae9d61Sreyk 
49945ae9d61Sreyk 	ret = ec_point2raw(group, secretp, secret, ec_getlen(group));
50045ae9d61Sreyk 
50145ae9d61Sreyk  done:
502c900656bSmarkus 	if (exkey != NULL)
503c900656bSmarkus 		EC_KEY_free(exkey);
50445ae9d61Sreyk 	if (exchangep != NULL)
50545ae9d61Sreyk 		EC_POINT_clear_free(exchangep);
50645ae9d61Sreyk 	if (secretp != NULL)
50745ae9d61Sreyk 		EC_POINT_clear_free(secretp);
50845ae9d61Sreyk 
50945ae9d61Sreyk 	return (ret);
51045ae9d61Sreyk }
51145ae9d61Sreyk 
51245ae9d61Sreyk int
51345ae9d61Sreyk ec_point2raw(struct group *group, const EC_POINT *point,
514d09d3a7dSreyk     uint8_t *buf, size_t len)
51545ae9d61Sreyk {
51645ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
51745ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
51845ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
51945ae9d61Sreyk 	int		 ret = -1;
52045b72fd1Smikeb 	size_t		 eclen, xlen, ylen;
52145ae9d61Sreyk 	off_t		 xoff, yoff;
52245ae9d61Sreyk 
52345ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
52445ae9d61Sreyk 		goto done;
52545ae9d61Sreyk 	BN_CTX_start(bnctx);
52645ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
52745ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
52845ae9d61Sreyk 		goto done;
52945ae9d61Sreyk 
53045b72fd1Smikeb 	eclen = ec_getlen(group);
53145b72fd1Smikeb 	if (len < eclen)
53245b72fd1Smikeb 		goto done;
53345b72fd1Smikeb 	xlen = ylen = eclen / 2;
53445b72fd1Smikeb 
53545ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
53645ae9d61Sreyk 		goto done;
53745ae9d61Sreyk 
53845ae9d61Sreyk 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) ==
53945ae9d61Sreyk 	    NID_X9_62_prime_field) {
54045ae9d61Sreyk 		if (!EC_POINT_get_affine_coordinates_GFp(ecgroup,
54145ae9d61Sreyk 		    point, x, y, bnctx))
54245ae9d61Sreyk 			goto done;
54345ae9d61Sreyk 	} else {
54445ae9d61Sreyk 		if (!EC_POINT_get_affine_coordinates_GF2m(ecgroup,
54545ae9d61Sreyk 		    point, x, y, bnctx))
54645ae9d61Sreyk 			goto done;
54745ae9d61Sreyk 	}
54845ae9d61Sreyk 
54945ae9d61Sreyk 	xoff = xlen - BN_num_bytes(x);
55045b72fd1Smikeb 	bzero(buf, xoff);
55145ae9d61Sreyk 	if (!BN_bn2bin(x, buf + xoff))
55245ae9d61Sreyk 		goto done;
55345ae9d61Sreyk 
55445ae9d61Sreyk 	yoff = (ylen - BN_num_bytes(y)) + xlen;
55545b72fd1Smikeb 	bzero(buf + xlen, yoff - xlen);
55645ae9d61Sreyk 	if (!BN_bn2bin(y, buf + yoff))
55745ae9d61Sreyk 		goto done;
55845ae9d61Sreyk 
55945ae9d61Sreyk 	ret = 0;
56045ae9d61Sreyk  done:
561c900656bSmarkus 	/* Make sure to erase sensitive data */
562c900656bSmarkus 	if (x != NULL)
563c900656bSmarkus 		BN_clear(x);
564c900656bSmarkus 	if (y != NULL)
565c900656bSmarkus 		BN_clear(y);
56645ae9d61Sreyk 	BN_CTX_end(bnctx);
56745ae9d61Sreyk 	BN_CTX_free(bnctx);
56845ae9d61Sreyk 
56945ae9d61Sreyk 	return (ret);
57045ae9d61Sreyk }
57145ae9d61Sreyk 
57245ae9d61Sreyk EC_POINT *
573d09d3a7dSreyk ec_raw2point(struct group *group, uint8_t *buf, size_t len)
57445ae9d61Sreyk {
57545ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
57645ae9d61Sreyk 	EC_POINT	*point = NULL;
57745ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
57845ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
57945ae9d61Sreyk 	int		 ret = -1;
58045ae9d61Sreyk 	size_t		 eclen;
58145ae9d61Sreyk 	size_t		 xlen, ylen;
58245ae9d61Sreyk 
58345ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
58445ae9d61Sreyk 		goto done;
58545ae9d61Sreyk 	BN_CTX_start(bnctx);
58645ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
58745ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
58845ae9d61Sreyk 		goto done;
58945ae9d61Sreyk 
59045ae9d61Sreyk 	eclen = ec_getlen(group);
59145ae9d61Sreyk 	if (len < eclen)
59245ae9d61Sreyk 		goto done;
59345ae9d61Sreyk 	xlen = ylen = eclen / 2;
59445ae9d61Sreyk 	if ((x = BN_bin2bn(buf, xlen, x)) == NULL ||
59545ae9d61Sreyk 	    (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL)
59645ae9d61Sreyk 		goto done;
59745ae9d61Sreyk 
59845ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
59945ae9d61Sreyk 		goto done;
60045ae9d61Sreyk 
60145ae9d61Sreyk 	if ((point = EC_POINT_new(ecgroup)) == NULL)
60245ae9d61Sreyk 		goto done;
60345ae9d61Sreyk 
60445ae9d61Sreyk 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) ==
60545ae9d61Sreyk 	    NID_X9_62_prime_field) {
60645ae9d61Sreyk 		if (!EC_POINT_set_affine_coordinates_GFp(ecgroup,
60745ae9d61Sreyk 		    point, x, y, bnctx))
60845ae9d61Sreyk 			goto done;
60945ae9d61Sreyk 	} else {
61045ae9d61Sreyk 		if (!EC_POINT_set_affine_coordinates_GF2m(ecgroup,
61145ae9d61Sreyk 		    point, x, y, bnctx))
61245ae9d61Sreyk 			goto done;
61345ae9d61Sreyk 	}
61445ae9d61Sreyk 
61545ae9d61Sreyk 	ret = 0;
61645ae9d61Sreyk  done:
61745ae9d61Sreyk 	if (ret != 0 && point != NULL)
61845ae9d61Sreyk 		EC_POINT_clear_free(point);
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 (point);
62845ae9d61Sreyk }
62945135ebcSreyk 
63045135ebcSreyk int
63145135ebcSreyk ec25519_init(struct group *group)
63245135ebcSreyk {
633d09d3a7dSreyk 	static const uint8_t	 basepoint[CURVE25519_SIZE] = { 9 };
63445135ebcSreyk 	struct curve25519_key	*curve25519;
63545135ebcSreyk 
63645135ebcSreyk 	if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL)
63745135ebcSreyk 		return (-1);
63845135ebcSreyk 
63945135ebcSreyk 	group->curve25519 = curve25519;
64045135ebcSreyk 
64145135ebcSreyk 	arc4random_buf(curve25519->secret, CURVE25519_SIZE);
64245135ebcSreyk 	crypto_scalarmult_curve25519(curve25519->public,
64345135ebcSreyk 	    curve25519->secret, basepoint);
64445135ebcSreyk 
64545135ebcSreyk 	return (0);
64645135ebcSreyk }
64745135ebcSreyk 
64845135ebcSreyk int
64945135ebcSreyk ec25519_getlen(struct group *group)
65045135ebcSreyk {
65145135ebcSreyk 	if (group->spec == NULL)
65245135ebcSreyk 		return (0);
65345135ebcSreyk 	return (CURVE25519_SIZE);
65445135ebcSreyk }
65545135ebcSreyk 
65645135ebcSreyk int
657d09d3a7dSreyk ec25519_create_exchange(struct group *group, uint8_t *buf)
65845135ebcSreyk {
65945135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
66045135ebcSreyk 
66145135ebcSreyk 	memcpy(buf, curve25519->public, ec25519_getlen(group));
66245135ebcSreyk 	return (0);
66345135ebcSreyk }
66445135ebcSreyk 
66545135ebcSreyk int
666d09d3a7dSreyk ec25519_create_shared(struct group *group, uint8_t *shared, uint8_t *public)
66745135ebcSreyk {
66845135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
66945135ebcSreyk 
67045135ebcSreyk 	crypto_scalarmult_curve25519(shared, curve25519->secret, public);
67145135ebcSreyk 	return (0);
67245135ebcSreyk }
673