xref: /openbsd/sbin/iked/dh.c (revision d8ea035b)
1*d8ea035bSderaadt /*	$OpenBSD: dh.c,v 1.30 2021/11/29 06:43:42 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 
19*d8ea035bSderaadt #include <sys/types.h>
2045ae9d61Sreyk 
21710c50d7Stobhe #include <sys/queue.h>
22710c50d7Stobhe #include <sys/socket.h>
23710c50d7Stobhe #include <sys/uio.h>
24*d8ea035bSderaadt #include <string.h>
25710c50d7Stobhe #include <event.h>
26710c50d7Stobhe #include <imsg.h>
27710c50d7Stobhe 
28710c50d7Stobhe #include <openssl/evp.h>
29710c50d7Stobhe #include <openssl/sha.h>
3045ae9d61Sreyk #include <openssl/obj_mac.h>
3145ae9d61Sreyk #include <openssl/dh.h>
3245ae9d61Sreyk #include <openssl/ec.h>
3345ae9d61Sreyk #include <openssl/ecdh.h>
34a4194998Sjsg #include <openssl/bn.h>
3545ae9d61Sreyk 
3645ae9d61Sreyk #include "dh.h"
37710c50d7Stobhe #include "iked.h"
389b50bc25Stobhe #include "crypto_api.h"
390d5bf58dSreyk 
400e1bb3dcStobhe int	dh_init(struct dh_group *);
410e1bb3dcStobhe int	dh_getlen(struct dh_group *);
420e1bb3dcStobhe int	dh_secretlen(struct dh_group *);
4345ae9d61Sreyk 
4445135ebcSreyk /* MODP */
450e1bb3dcStobhe int	modp_init(struct dh_group *);
460e1bb3dcStobhe int	modp_getlen(struct dh_group *);
470e1bb3dcStobhe int	modp_create_exchange(struct dh_group *, uint8_t *);
480e1bb3dcStobhe int	modp_create_shared(struct dh_group *, uint8_t *, uint8_t *);
4945ae9d61Sreyk 
50bc77414bStobhe /* ECP */
510e1bb3dcStobhe int	ec_init(struct dh_group *);
520e1bb3dcStobhe int	ec_getlen(struct dh_group *);
530e1bb3dcStobhe int	ec_secretlen(struct dh_group *);
540e1bb3dcStobhe int	ec_create_exchange(struct dh_group *, uint8_t *);
550e1bb3dcStobhe int	ec_create_shared(struct dh_group *, uint8_t *, uint8_t *);
5645ae9d61Sreyk 
57a6321d0fSpatrick #define EC_POINT2RAW_FULL	0
58a6321d0fSpatrick #define EC_POINT2RAW_XONLY	1
590e1bb3dcStobhe int	ec_point2raw(struct dh_group *, const EC_POINT *, uint8_t *, size_t, int);
6045ae9d61Sreyk EC_POINT *
610e1bb3dcStobhe 	ec_raw2point(struct dh_group *, uint8_t *, size_t);
6245ae9d61Sreyk 
6345135ebcSreyk /* curve25519 */
640e1bb3dcStobhe int	ec25519_init(struct dh_group *);
650e1bb3dcStobhe int	ec25519_getlen(struct dh_group *);
660e1bb3dcStobhe int	ec25519_create_exchange(struct dh_group *, uint8_t *);
670e1bb3dcStobhe int	ec25519_create_shared(struct dh_group *, uint8_t *, uint8_t *);
6845135ebcSreyk 
6945135ebcSreyk #define CURVE25519_SIZE 32	/* 256 bits */
7045135ebcSreyk struct curve25519_key {
71d09d3a7dSreyk 	uint8_t		 secret[CURVE25519_SIZE];
72d09d3a7dSreyk 	uint8_t		 public[CURVE25519_SIZE];
7345135ebcSreyk };
74d09d3a7dSreyk extern int crypto_scalarmult_curve25519(unsigned char a[CURVE25519_SIZE],
75d09d3a7dSreyk     const unsigned char b[CURVE25519_SIZE],
76d09d3a7dSreyk     const unsigned char c[CURVE25519_SIZE])
7745135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
7845135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)))
7945135ebcSreyk 	__attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE)));
8045135ebcSreyk 
819b50bc25Stobhe /* SNTRUP761 with X25519 */
829b50bc25Stobhe int	kemsx_init(struct dh_group *);
839b50bc25Stobhe int	kemsx_getlen(struct dh_group *);
849b50bc25Stobhe int	kemsx_create_exchange2(struct dh_group *, struct ibuf **, struct ibuf *);
859b50bc25Stobhe int	kemsx_create_shared2(struct dh_group *, struct ibuf **, struct ibuf *);
869b50bc25Stobhe 
879b50bc25Stobhe struct kemsx_key {
889b50bc25Stobhe 	uint8_t		kemkey[crypto_kem_sntrup761_BYTES];
899b50bc25Stobhe 	uint8_t		secret[crypto_kem_sntrup761_SECRETKEYBYTES];
909b50bc25Stobhe 	uint8_t		public[crypto_kem_sntrup761_PUBLICKEYBYTES];
919b50bc25Stobhe 	uint8_t		initiator;
929b50bc25Stobhe };
939b50bc25Stobhe 
94e254d6eaSmikeb const struct group_id ike_groups[] = {
9545ae9d61Sreyk 	{ GROUP_MODP, 1, 768,
9645ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
9745ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
9845ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
9945ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
10045ae9d61Sreyk 	    "02"
10145ae9d61Sreyk 	},
10245ae9d61Sreyk 	{ GROUP_MODP, 2, 1024,
10345ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
10445ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
10545ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
10645ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
10745ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
10845ae9d61Sreyk 	    "FFFFFFFFFFFFFFFF",
10945ae9d61Sreyk 	    "02"
11045ae9d61Sreyk 	},
11145ae9d61Sreyk 	{ GROUP_MODP, 5, 1536,
11245ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
11345ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
11445ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
11545ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
11645ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
11745ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
11845ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
11945ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
12045ae9d61Sreyk 	    "02"
12145ae9d61Sreyk 	},
12245ae9d61Sreyk 	{ GROUP_MODP, 14, 2048,
12345ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
12445ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
12545ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
12645ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
12745ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
12845ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
12945ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
13045ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
13145ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
13245ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
13345ae9d61Sreyk 	    "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
13445ae9d61Sreyk 	    "02"
13545ae9d61Sreyk 	},
13645ae9d61Sreyk 	{ GROUP_MODP, 15, 3072,
13745ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
13845ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
13945ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
14045ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
14145ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
14245ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
14345ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
14445ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
14545ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
14645ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
14745ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
14845ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
14945ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
15045ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
15145ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
15245ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF",
15345ae9d61Sreyk 	    "02"
15445ae9d61Sreyk 	},
15545ae9d61Sreyk 	{ GROUP_MODP, 16, 4096,
15645ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
15745ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
15845ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
15945ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
16045ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
16145ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
16245ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
16345ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
16445ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
16545ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
16645ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
16745ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
16845ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
16945ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
17045ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
17145ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
17245ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
17345ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
17445ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
17545ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
17645ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
17745ae9d61Sreyk 	    "FFFFFFFFFFFFFFFF",
17845ae9d61Sreyk 	    "02"
17945ae9d61Sreyk 	},
18045ae9d61Sreyk 	{ GROUP_MODP, 17, 6144,
18145ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
18245ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
18345ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
18445ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
18545ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
18645ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
18745ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
18845ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
18945ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
19045ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
19145ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
19245ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
19345ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
19445ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
19545ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
19645ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
19745ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
19845ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
19945ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
20045ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
20145ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
20245ae9d61Sreyk 	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
20345ae9d61Sreyk 	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
20445ae9d61Sreyk 	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
20545ae9d61Sreyk 	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
20645ae9d61Sreyk 	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
20745ae9d61Sreyk 	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
20845ae9d61Sreyk 	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
20945ae9d61Sreyk 	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
21045ae9d61Sreyk 	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
21145ae9d61Sreyk 	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
21245ae9d61Sreyk 	    "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF",
21345ae9d61Sreyk 	    "02"
21445ae9d61Sreyk 	},
21545ae9d61Sreyk 	{ GROUP_MODP, 18, 8192,
21645ae9d61Sreyk 	    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
21745ae9d61Sreyk 	    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
21845ae9d61Sreyk 	    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
21945ae9d61Sreyk 	    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
22045ae9d61Sreyk 	    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
22145ae9d61Sreyk 	    "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
22245ae9d61Sreyk 	    "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
22345ae9d61Sreyk 	    "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
22445ae9d61Sreyk 	    "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
22545ae9d61Sreyk 	    "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
22645ae9d61Sreyk 	    "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
22745ae9d61Sreyk 	    "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
22845ae9d61Sreyk 	    "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
22945ae9d61Sreyk 	    "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
23045ae9d61Sreyk 	    "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
23145ae9d61Sreyk 	    "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
23245ae9d61Sreyk 	    "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
23345ae9d61Sreyk 	    "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
23445ae9d61Sreyk 	    "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
23545ae9d61Sreyk 	    "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
23645ae9d61Sreyk 	    "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
23745ae9d61Sreyk 	    "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
23845ae9d61Sreyk 	    "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
23945ae9d61Sreyk 	    "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
24045ae9d61Sreyk 	    "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
24145ae9d61Sreyk 	    "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
24245ae9d61Sreyk 	    "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
24345ae9d61Sreyk 	    "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
24445ae9d61Sreyk 	    "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
24545ae9d61Sreyk 	    "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
24645ae9d61Sreyk 	    "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
24745ae9d61Sreyk 	    "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
24845ae9d61Sreyk 	    "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
24945ae9d61Sreyk 	    "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
25045ae9d61Sreyk 	    "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
25145ae9d61Sreyk 	    "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
25245ae9d61Sreyk 	    "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
25345ae9d61Sreyk 	    "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
25445ae9d61Sreyk 	    "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
25545ae9d61Sreyk 	    "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
25645ae9d61Sreyk 	    "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
25745ae9d61Sreyk 	    "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
25845ae9d61Sreyk 	    "60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
25945ae9d61Sreyk 	    "02"
26045ae9d61Sreyk 	},
261369beec1Sreyk 	{ GROUP_ECP, 19, 256, NULL, NULL, NID_X9_62_prime256v1 },
262369beec1Sreyk 	{ GROUP_ECP, 20, 384, NULL, NULL, NID_secp384r1 },
263369beec1Sreyk 	{ GROUP_ECP, 21, 521, NULL, NULL, NID_secp521r1 },
264369beec1Sreyk 	{ GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 },
265547eb84dSreyk 	{ GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 },
266547eb84dSreyk 	{ GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 },
267547eb84dSreyk 	{ GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 },
268547eb84dSreyk 	{ GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 },
26945135ebcSreyk 	{ GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 },
2709b50bc25Stobhe 	{ GROUP_CURVE25519, 31, CURVE25519_SIZE * 8 },
2719b50bc25Stobhe 	/* "Private use" extensions */
2729b50bc25Stobhe 	/* PQC KEM */
2739b50bc25Stobhe 	{ GROUP_SNTRUP761X25519, 1035,
274*d8ea035bSderaadt 	   (MAXIMUM(crypto_kem_sntrup761_PUBLICKEYBYTES,
2759b50bc25Stobhe 	        crypto_kem_sntrup761_CIPHERTEXTBYTES) +
2769b50bc25Stobhe 	    CURVE25519_SIZE) * 8 }
27745ae9d61Sreyk };
27845ae9d61Sreyk 
27945ae9d61Sreyk void
28045ae9d61Sreyk group_init(void)
28145ae9d61Sreyk {
2820d5bf58dSreyk 	/* currently not used */
28345ae9d61Sreyk 	return;
28445ae9d61Sreyk }
28545ae9d61Sreyk 
28645ae9d61Sreyk void
2870e1bb3dcStobhe group_free(struct dh_group *group)
28845ae9d61Sreyk {
28945ae9d61Sreyk 	if (group == NULL)
29045ae9d61Sreyk 		return;
29145ae9d61Sreyk 	if (group->dh != NULL)
29245ae9d61Sreyk 		DH_free(group->dh);
29345ae9d61Sreyk 	if (group->ec != NULL)
29445ae9d61Sreyk 		EC_KEY_free(group->ec);
29529b4e2eaSderaadt 	freezero(group->curve25519, sizeof(struct curve25519_key));
2969b50bc25Stobhe 	freezero(group->kemsx, sizeof(struct kemsx_key));
29745ae9d61Sreyk 	group->spec = NULL;
29864449014Sreyk 	free(group);
29945ae9d61Sreyk }
30045ae9d61Sreyk 
3010e1bb3dcStobhe struct dh_group *
302d09d3a7dSreyk group_get(uint32_t id)
30345ae9d61Sreyk {
304e254d6eaSmikeb 	const struct group_id	*p;
3050e1bb3dcStobhe 	struct dh_group		*group;
30645ae9d61Sreyk 
307e254d6eaSmikeb 	if ((p = group_getid(id)) == NULL)
30845ae9d61Sreyk 		return (NULL);
30945ae9d61Sreyk 
31045ae9d61Sreyk 	if ((group = calloc(1, sizeof(*group))) == NULL)
31145ae9d61Sreyk 		return (NULL);
31245ae9d61Sreyk 
31345ae9d61Sreyk 	group->id = id;
31445ae9d61Sreyk 	group->spec = p;
31545ae9d61Sreyk 
31645ae9d61Sreyk 	switch (p->type) {
31745ae9d61Sreyk 	case GROUP_MODP:
31845ae9d61Sreyk 		group->init = modp_init;
31945ae9d61Sreyk 		group->getlen = modp_getlen;
32045ae9d61Sreyk 		group->exchange = modp_create_exchange;
32145ae9d61Sreyk 		group->shared = modp_create_shared;
32245ae9d61Sreyk 		break;
323369beec1Sreyk 	case GROUP_ECP:
32445ae9d61Sreyk 		group->init = ec_init;
32545ae9d61Sreyk 		group->getlen = ec_getlen;
326a6321d0fSpatrick 		group->secretlen = ec_secretlen;
32745ae9d61Sreyk 		group->exchange = ec_create_exchange;
32845ae9d61Sreyk 		group->shared = ec_create_shared;
32945ae9d61Sreyk 		break;
33045135ebcSreyk 	case GROUP_CURVE25519:
33145135ebcSreyk 		group->init = ec25519_init;
33245135ebcSreyk 		group->getlen = ec25519_getlen;
33345135ebcSreyk 		group->exchange = ec25519_create_exchange;
33445135ebcSreyk 		group->shared = ec25519_create_shared;
33545135ebcSreyk 		break;
3369b50bc25Stobhe 	case GROUP_SNTRUP761X25519:
3379b50bc25Stobhe 		group->init = kemsx_init;
3389b50bc25Stobhe 		group->getlen = kemsx_getlen;
3399b50bc25Stobhe 		group->exchange2 = kemsx_create_exchange2;
3409b50bc25Stobhe 		group->shared2 = kemsx_create_shared2;
3419b50bc25Stobhe 		break;
34245ae9d61Sreyk 	default:
34345ae9d61Sreyk 		group_free(group);
34445ae9d61Sreyk 		return (NULL);
34545ae9d61Sreyk 	}
34645ae9d61Sreyk 
34745ae9d61Sreyk 	if (dh_init(group) != 0) {
34845ae9d61Sreyk 		group_free(group);
34945ae9d61Sreyk 		return (NULL);
35045ae9d61Sreyk 	}
35145ae9d61Sreyk 
35245ae9d61Sreyk 	return (group);
35345ae9d61Sreyk }
35445ae9d61Sreyk 
355e254d6eaSmikeb const struct group_id *
356e254d6eaSmikeb group_getid(uint32_t id)
357e254d6eaSmikeb {
358e254d6eaSmikeb 	const struct group_id	*p = NULL;
359e254d6eaSmikeb 	unsigned int		 i, items;
360e254d6eaSmikeb 
361e254d6eaSmikeb 	items = sizeof(ike_groups) / sizeof(ike_groups[0]);
362e254d6eaSmikeb 	for (i = 0; i < items; i++) {
363e254d6eaSmikeb 		if (id == ike_groups[i].id) {
364e254d6eaSmikeb 			p = &ike_groups[i];
365e254d6eaSmikeb 			break;
366e254d6eaSmikeb 		}
367e254d6eaSmikeb 	}
368e254d6eaSmikeb 	return (p);
369e254d6eaSmikeb }
370e254d6eaSmikeb 
37145ae9d61Sreyk int
3720e1bb3dcStobhe dh_init(struct dh_group *group)
37345ae9d61Sreyk {
37445ae9d61Sreyk 	return (group->init(group));
37545ae9d61Sreyk }
37645ae9d61Sreyk 
37745ae9d61Sreyk int
3780e1bb3dcStobhe dh_getlen(struct dh_group *group)
37945ae9d61Sreyk {
38045ae9d61Sreyk 	return (group->getlen(group));
38145ae9d61Sreyk }
38245ae9d61Sreyk 
38345ae9d61Sreyk int
3840e1bb3dcStobhe dh_secretlen(struct dh_group *group)
385a6321d0fSpatrick {
386a6321d0fSpatrick 	if (group->secretlen)
387a6321d0fSpatrick 		return (group->secretlen(group));
388a6321d0fSpatrick 	else
389a6321d0fSpatrick 		return (group->getlen(group));
390a6321d0fSpatrick }
391a6321d0fSpatrick 
392a6321d0fSpatrick int
3930e1bb3dcStobhe dh_create_exchange(struct dh_group *group, struct ibuf **bufp, struct ibuf *iexchange)
39445ae9d61Sreyk {
395710c50d7Stobhe 	struct ibuf *buf;
396710c50d7Stobhe 
397710c50d7Stobhe 	*bufp = NULL;
3989b50bc25Stobhe 	if (group->exchange2)
3999b50bc25Stobhe 		return (group->exchange2(group, bufp, iexchange));
400710c50d7Stobhe 	buf = ibuf_new(NULL, dh_getlen(group));
401710c50d7Stobhe 	if (buf == NULL)
402710c50d7Stobhe 		return -1;
403710c50d7Stobhe 	*bufp = buf;
404710c50d7Stobhe 	return (group->exchange(group, buf->buf));
40545ae9d61Sreyk }
40645ae9d61Sreyk 
40745ae9d61Sreyk int
4080e1bb3dcStobhe dh_create_shared(struct dh_group *group, struct ibuf **secretp, struct ibuf *exchange)
40945ae9d61Sreyk {
410710c50d7Stobhe 	struct ibuf *buf;
411710c50d7Stobhe 
412710c50d7Stobhe 	*secretp = NULL;
4139b50bc25Stobhe 	if (group->shared2)
4149b50bc25Stobhe 		return (group->shared2(group, secretp, exchange));
415710c50d7Stobhe 	if (exchange == NULL ||
416710c50d7Stobhe 	    (ssize_t)ibuf_size(exchange) != dh_getlen(group))
417710c50d7Stobhe 		return -1;
418710c50d7Stobhe 	buf = ibuf_new(NULL, dh_secretlen(group));
419710c50d7Stobhe 	if (buf == NULL)
420710c50d7Stobhe 		return -1;
421710c50d7Stobhe 	*secretp = buf;
422710c50d7Stobhe 	return (group->shared(group, buf->buf, exchange->buf));
42345ae9d61Sreyk }
42445ae9d61Sreyk 
42545ae9d61Sreyk int
4260e1bb3dcStobhe modp_init(struct dh_group *group)
42745ae9d61Sreyk {
42808c24fddStobhe 	BIGNUM	*g = NULL, *p = NULL;
42945ae9d61Sreyk 	DH	*dh;
43008c24fddStobhe 	int	 ret = -1;
43145ae9d61Sreyk 
43245ae9d61Sreyk 	if ((dh = DH_new()) == NULL)
43345ae9d61Sreyk 		return (-1);
43408c24fddStobhe 
43508c24fddStobhe 	if (!BN_hex2bn(&p, group->spec->prime) ||
43608c24fddStobhe 	    !BN_hex2bn(&g, group->spec->generator) ||
43708c24fddStobhe 	    DH_set0_pqg(dh, p, NULL, g) == 0)
43808c24fddStobhe 		goto done;
43908c24fddStobhe 
44008c24fddStobhe 	p = g = NULL;
4417d7b0856Sreyk 	group->dh = dh;
44245ae9d61Sreyk 
44308c24fddStobhe 	ret = 0;
44408c24fddStobhe  done:
44508c24fddStobhe 	BN_clear_free(g);
44608c24fddStobhe 	BN_clear_free(p);
44745ae9d61Sreyk 
44808c24fddStobhe 	return (ret);
44945ae9d61Sreyk }
45045ae9d61Sreyk 
45145ae9d61Sreyk int
4520e1bb3dcStobhe modp_getlen(struct dh_group *group)
45345ae9d61Sreyk {
45445ae9d61Sreyk 	if (group->spec == NULL)
45545ae9d61Sreyk 		return (0);
45645ae9d61Sreyk 	return (roundup(group->spec->bits, 8) / 8);
45745ae9d61Sreyk }
45845ae9d61Sreyk 
45945ae9d61Sreyk int
4600e1bb3dcStobhe modp_create_exchange(struct dh_group *group, uint8_t *buf)
46145ae9d61Sreyk {
46208c24fddStobhe 	const BIGNUM	*pub;
46345ae9d61Sreyk 	DH		*dh = group->dh;
46412abf43bSmikeb 	int		 len, ret;
46545ae9d61Sreyk 
46645ae9d61Sreyk 	if (!DH_generate_key(dh))
46745ae9d61Sreyk 		return (-1);
46808c24fddStobhe 	DH_get0_key(group->dh, &pub, NULL);
46908c24fddStobhe 	ret = BN_bn2bin(pub, buf);
47012abf43bSmikeb 	if (!ret)
47145ae9d61Sreyk 		return (-1);
47245ae9d61Sreyk 
47312abf43bSmikeb 	len = dh_getlen(group);
47412abf43bSmikeb 
47512abf43bSmikeb 	/* add zero padding */
47612abf43bSmikeb 	if (ret < len) {
47712abf43bSmikeb 		bcopy(buf, buf + (len - ret), ret);
47812abf43bSmikeb 		bzero(buf, len - ret);
47912abf43bSmikeb 	}
48012abf43bSmikeb 
4817d7b0856Sreyk 	return (0);
48245ae9d61Sreyk }
48345ae9d61Sreyk 
48445ae9d61Sreyk int
4850e1bb3dcStobhe modp_create_shared(struct dh_group *group, uint8_t *secret, uint8_t *exchange)
48645ae9d61Sreyk {
48745ae9d61Sreyk 	BIGNUM	*ex;
48812abf43bSmikeb 	int	 len, ret;
48945ae9d61Sreyk 
49012abf43bSmikeb 	len = dh_getlen(group);
49112abf43bSmikeb 
49212abf43bSmikeb 	if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL)
49345ae9d61Sreyk 		return (-1);
4947d7b0856Sreyk 
4957d7b0856Sreyk 	ret = DH_compute_key(secret, ex, group->dh);
4967d7b0856Sreyk 	BN_clear_free(ex);
4972ffa77eaSjsg 	if (ret <= 0)
49845ae9d61Sreyk 		return (-1);
49945ae9d61Sreyk 
50012abf43bSmikeb 	/* add zero padding */
50112abf43bSmikeb 	if (ret < len) {
50212abf43bSmikeb 		bcopy(secret, secret + (len - ret), ret);
50312abf43bSmikeb 		bzero(secret, len - ret);
50412abf43bSmikeb 	}
50512abf43bSmikeb 
5067d7b0856Sreyk 	return (0);
50745ae9d61Sreyk }
50845ae9d61Sreyk 
50945ae9d61Sreyk int
5100e1bb3dcStobhe ec_init(struct dh_group *group)
51145ae9d61Sreyk {
51245ae9d61Sreyk 	if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL)
51345ae9d61Sreyk 		return (-1);
51445ae9d61Sreyk 	if (!EC_KEY_generate_key(group->ec))
51545ae9d61Sreyk 		return (-1);
516c900656bSmarkus 	if (!EC_KEY_check_key(group->ec)) {
517c900656bSmarkus 		EC_KEY_free(group->ec);
518c900656bSmarkus 		return (-1);
519c900656bSmarkus 	}
52045ae9d61Sreyk 	return (0);
52145ae9d61Sreyk }
52245ae9d61Sreyk 
52345ae9d61Sreyk int
5240e1bb3dcStobhe ec_getlen(struct dh_group *group)
52545ae9d61Sreyk {
52645ae9d61Sreyk 	if (group->spec == NULL)
52745ae9d61Sreyk 		return (0);
52845b72fd1Smikeb 	/* NB:  Return value will always be even */
52945ae9d61Sreyk 	return ((roundup(group->spec->bits, 8) * 2) / 8);
53045ae9d61Sreyk }
53145ae9d61Sreyk 
532a6321d0fSpatrick /*
533a6321d0fSpatrick  * Note that the shared secret only includes the x value:
534a6321d0fSpatrick  *
535a6321d0fSpatrick  * See RFC 5903, 7. ECP Key Exchange Data Formats:
536a6321d0fSpatrick  *   The Diffie-Hellman shared secret value consists of the x value of the
537a6321d0fSpatrick  *   Diffie-Hellman common value.
538a6321d0fSpatrick  * See also RFC 5903, 9. Changes from RFC 4753.
539a6321d0fSpatrick  */
540a6321d0fSpatrick int
5410e1bb3dcStobhe ec_secretlen(struct dh_group *group)
542a6321d0fSpatrick {
543a6321d0fSpatrick 	return (ec_getlen(group) / 2);
544a6321d0fSpatrick }
545a6321d0fSpatrick 
54645ae9d61Sreyk int
5470e1bb3dcStobhe ec_create_exchange(struct dh_group *group, uint8_t *buf)
54845ae9d61Sreyk {
5490d5bf58dSreyk 	size_t	 len;
5500d5bf58dSreyk 
5510d5bf58dSreyk 	len = ec_getlen(group);
5520d5bf58dSreyk 	bzero(buf, len);
5530d5bf58dSreyk 
55445ae9d61Sreyk 	return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec),
555a6321d0fSpatrick 	    buf, len, EC_POINT2RAW_FULL));
55645ae9d61Sreyk }
55745ae9d61Sreyk 
55845ae9d61Sreyk int
5590e1bb3dcStobhe ec_create_shared(struct dh_group *group, uint8_t *secret, uint8_t *exchange)
56045ae9d61Sreyk {
56145ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
56245ae9d61Sreyk 	const BIGNUM	*privkey;
563c900656bSmarkus 	EC_KEY		*exkey = NULL;
56445ae9d61Sreyk 	EC_POINT	*exchangep = NULL, *secretp = NULL;
56545ae9d61Sreyk 	int		 ret = -1;
56645ae9d61Sreyk 
56745ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL ||
56845ae9d61Sreyk 	    (privkey = EC_KEY_get0_private_key(group->ec)) == NULL)
56945ae9d61Sreyk 		goto done;
57045ae9d61Sreyk 
57145ae9d61Sreyk 	if ((exchangep =
57245ae9d61Sreyk 	    ec_raw2point(group, exchange, ec_getlen(group))) == NULL)
57345ae9d61Sreyk 		goto done;
57445ae9d61Sreyk 
575c900656bSmarkus 	if ((exkey = EC_KEY_new()) == NULL)
576c900656bSmarkus 		goto done;
577c900656bSmarkus 	if (!EC_KEY_set_group(exkey, ecgroup))
578c900656bSmarkus 		goto done;
579c900656bSmarkus 	if (!EC_KEY_set_public_key(exkey, exchangep))
580c900656bSmarkus 		goto done;
581c900656bSmarkus 
582c900656bSmarkus 	/* validate exchangep */
583c900656bSmarkus 	if (!EC_KEY_check_key(exkey))
584c900656bSmarkus 		goto done;
585c900656bSmarkus 
58645ae9d61Sreyk 	if ((secretp = EC_POINT_new(ecgroup)) == NULL)
58745ae9d61Sreyk 		goto done;
58845ae9d61Sreyk 
58945ae9d61Sreyk 	if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL))
59045ae9d61Sreyk 		goto done;
59145ae9d61Sreyk 
592a6321d0fSpatrick 	ret = ec_point2raw(group, secretp, secret, ec_secretlen(group),
593a6321d0fSpatrick 	    EC_POINT2RAW_XONLY);
59445ae9d61Sreyk 
59545ae9d61Sreyk  done:
596c900656bSmarkus 	if (exkey != NULL)
597c900656bSmarkus 		EC_KEY_free(exkey);
59845ae9d61Sreyk 	if (exchangep != NULL)
59945ae9d61Sreyk 		EC_POINT_clear_free(exchangep);
60045ae9d61Sreyk 	if (secretp != NULL)
60145ae9d61Sreyk 		EC_POINT_clear_free(secretp);
60245ae9d61Sreyk 
60345ae9d61Sreyk 	return (ret);
60445ae9d61Sreyk }
60545ae9d61Sreyk 
60645ae9d61Sreyk int
6070e1bb3dcStobhe ec_point2raw(struct dh_group *group, const EC_POINT *point,
608a6321d0fSpatrick     uint8_t *buf, size_t len, int mode)
60945ae9d61Sreyk {
61045ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
61145ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
61245ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
61345ae9d61Sreyk 	int		 ret = -1;
61445b72fd1Smikeb 	size_t		 eclen, xlen, ylen;
61545ae9d61Sreyk 	off_t		 xoff, yoff;
61645ae9d61Sreyk 
61745ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
61845ae9d61Sreyk 		goto done;
61945ae9d61Sreyk 	BN_CTX_start(bnctx);
62045ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
62145ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
62245ae9d61Sreyk 		goto done;
62345ae9d61Sreyk 
62445b72fd1Smikeb 	eclen = ec_getlen(group);
625a6321d0fSpatrick 	switch (mode) {
626a6321d0fSpatrick 	case EC_POINT2RAW_XONLY:
627a6321d0fSpatrick 		xlen = eclen / 2;
628a6321d0fSpatrick 		ylen = 0;
629a6321d0fSpatrick 		break;
630a6321d0fSpatrick 	case EC_POINT2RAW_FULL:
63145b72fd1Smikeb 		xlen = ylen = eclen / 2;
632a6321d0fSpatrick 		break;
633a6321d0fSpatrick 	default:
634a6321d0fSpatrick 		goto done;
635a6321d0fSpatrick 	}
636a6321d0fSpatrick 	if (len < xlen + ylen)
637a6321d0fSpatrick 		goto done;
63845b72fd1Smikeb 
63945ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
64045ae9d61Sreyk 		goto done;
64145ae9d61Sreyk 
642d1f8a43dStb 	if (!EC_POINT_get_affine_coordinates(ecgroup, point, x, y, bnctx))
64345ae9d61Sreyk 		goto done;
64445ae9d61Sreyk 
64545ae9d61Sreyk 	xoff = xlen - BN_num_bytes(x);
64645b72fd1Smikeb 	bzero(buf, xoff);
64745ae9d61Sreyk 	if (!BN_bn2bin(x, buf + xoff))
64845ae9d61Sreyk 		goto done;
64945ae9d61Sreyk 
650a6321d0fSpatrick 	if (ylen > 0) {
65145ae9d61Sreyk 		yoff = (ylen - BN_num_bytes(y)) + xlen;
65245b72fd1Smikeb 		bzero(buf + xlen, yoff - xlen);
65345ae9d61Sreyk 		if (!BN_bn2bin(y, buf + yoff))
65445ae9d61Sreyk 			goto done;
655a6321d0fSpatrick 	}
65645ae9d61Sreyk 
65745ae9d61Sreyk 	ret = 0;
65845ae9d61Sreyk  done:
659c900656bSmarkus 	/* Make sure to erase sensitive data */
660c900656bSmarkus 	if (x != NULL)
661c900656bSmarkus 		BN_clear(x);
662c900656bSmarkus 	if (y != NULL)
663c900656bSmarkus 		BN_clear(y);
66445ae9d61Sreyk 	BN_CTX_end(bnctx);
66545ae9d61Sreyk 	BN_CTX_free(bnctx);
66645ae9d61Sreyk 
66745ae9d61Sreyk 	return (ret);
66845ae9d61Sreyk }
66945ae9d61Sreyk 
67045ae9d61Sreyk EC_POINT *
6710e1bb3dcStobhe ec_raw2point(struct dh_group *group, uint8_t *buf, size_t len)
67245ae9d61Sreyk {
67345ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
67445ae9d61Sreyk 	EC_POINT	*point = NULL;
67545ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
67645ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
67745ae9d61Sreyk 	int		 ret = -1;
67845ae9d61Sreyk 	size_t		 eclen;
67945ae9d61Sreyk 	size_t		 xlen, ylen;
68045ae9d61Sreyk 
68145ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
68245ae9d61Sreyk 		goto done;
68345ae9d61Sreyk 	BN_CTX_start(bnctx);
68445ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
68545ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
68645ae9d61Sreyk 		goto done;
68745ae9d61Sreyk 
68845ae9d61Sreyk 	eclen = ec_getlen(group);
68945ae9d61Sreyk 	if (len < eclen)
69045ae9d61Sreyk 		goto done;
69145ae9d61Sreyk 	xlen = ylen = eclen / 2;
69245ae9d61Sreyk 	if ((x = BN_bin2bn(buf, xlen, x)) == NULL ||
69345ae9d61Sreyk 	    (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL)
69445ae9d61Sreyk 		goto done;
69545ae9d61Sreyk 
69645ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
69745ae9d61Sreyk 		goto done;
69845ae9d61Sreyk 
69945ae9d61Sreyk 	if ((point = EC_POINT_new(ecgroup)) == NULL)
70045ae9d61Sreyk 		goto done;
70145ae9d61Sreyk 
702d1f8a43dStb 	if (!EC_POINT_set_affine_coordinates(ecgroup, point, x, y, bnctx))
70345ae9d61Sreyk 		goto done;
70445ae9d61Sreyk 
70545ae9d61Sreyk 	ret = 0;
70645ae9d61Sreyk  done:
70745ae9d61Sreyk 	if (ret != 0 && point != NULL)
70845ae9d61Sreyk 		EC_POINT_clear_free(point);
709c900656bSmarkus 	/* Make sure to erase sensitive data */
710c900656bSmarkus 	if (x != NULL)
711c900656bSmarkus 		BN_clear(x);
712c900656bSmarkus 	if (y != NULL)
713c900656bSmarkus 		BN_clear(y);
71445ae9d61Sreyk 	BN_CTX_end(bnctx);
71545ae9d61Sreyk 	BN_CTX_free(bnctx);
71645ae9d61Sreyk 
71745ae9d61Sreyk 	return (point);
71845ae9d61Sreyk }
71945135ebcSreyk 
72045135ebcSreyk int
7210e1bb3dcStobhe ec25519_init(struct dh_group *group)
72245135ebcSreyk {
723d09d3a7dSreyk 	static const uint8_t	 basepoint[CURVE25519_SIZE] = { 9 };
72445135ebcSreyk 	struct curve25519_key	*curve25519;
72545135ebcSreyk 
72645135ebcSreyk 	if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL)
72745135ebcSreyk 		return (-1);
72845135ebcSreyk 
72945135ebcSreyk 	group->curve25519 = curve25519;
73045135ebcSreyk 
73145135ebcSreyk 	arc4random_buf(curve25519->secret, CURVE25519_SIZE);
73245135ebcSreyk 	crypto_scalarmult_curve25519(curve25519->public,
73345135ebcSreyk 	    curve25519->secret, basepoint);
73445135ebcSreyk 
73545135ebcSreyk 	return (0);
73645135ebcSreyk }
73745135ebcSreyk 
73845135ebcSreyk int
7390e1bb3dcStobhe ec25519_getlen(struct dh_group *group)
74045135ebcSreyk {
74145135ebcSreyk 	if (group->spec == NULL)
74245135ebcSreyk 		return (0);
74345135ebcSreyk 	return (CURVE25519_SIZE);
74445135ebcSreyk }
74545135ebcSreyk 
74645135ebcSreyk int
7470e1bb3dcStobhe ec25519_create_exchange(struct dh_group *group, uint8_t *buf)
74845135ebcSreyk {
74945135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
75045135ebcSreyk 
75145135ebcSreyk 	memcpy(buf, curve25519->public, ec25519_getlen(group));
75245135ebcSreyk 	return (0);
75345135ebcSreyk }
75445135ebcSreyk 
75545135ebcSreyk int
7560e1bb3dcStobhe ec25519_create_shared(struct dh_group *group, uint8_t *shared, uint8_t *public)
75745135ebcSreyk {
75845135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
75945135ebcSreyk 
76045135ebcSreyk 	crypto_scalarmult_curve25519(shared, curve25519->secret, public);
76145135ebcSreyk 	return (0);
76245135ebcSreyk }
7639b50bc25Stobhe 
7649b50bc25Stobhe /* combine sntrup761 with curve25519 */
7659b50bc25Stobhe 
7669b50bc25Stobhe int
7679b50bc25Stobhe kemsx_init(struct dh_group *group)
7689b50bc25Stobhe {
7699b50bc25Stobhe 	/* delayed until kemsx_create_exchange2 */
7709b50bc25Stobhe 	return (0);
7719b50bc25Stobhe }
7729b50bc25Stobhe 
7739b50bc25Stobhe int
7749b50bc25Stobhe kemsx_getlen(struct dh_group *group)
7759b50bc25Stobhe {
7769b50bc25Stobhe 	return (0);
7779b50bc25Stobhe }
7789b50bc25Stobhe 
7799b50bc25Stobhe int
7809b50bc25Stobhe kemsx_create_exchange2(struct dh_group *group, struct ibuf **bufp,
7819b50bc25Stobhe     struct ibuf *iexchange)
7829b50bc25Stobhe {
7839b50bc25Stobhe 	struct kemsx_key	*kemsx;
7849b50bc25Stobhe 	struct curve25519_key	*curve25519;
7859b50bc25Stobhe 	struct ibuf		*buf = NULL;
7869b50bc25Stobhe 	u_char *cp, *pk;
7879b50bc25Stobhe 	size_t have, need;
7889b50bc25Stobhe 
7899b50bc25Stobhe 	if (ec25519_init(group) == -1)
7909b50bc25Stobhe 		return (-1);
7919b50bc25Stobhe 	if (group->curve25519 == NULL)
7929b50bc25Stobhe 		return (-1);
7939b50bc25Stobhe 	if ((kemsx = calloc(1, sizeof(*kemsx))) == NULL)
7949b50bc25Stobhe 		return (-1);
7959b50bc25Stobhe 	group->kemsx = kemsx;
7969b50bc25Stobhe 
7979b50bc25Stobhe 	if (iexchange == NULL) {
7989b50bc25Stobhe 		kemsx->initiator = 1;
7999b50bc25Stobhe 		crypto_kem_sntrup761_keypair(kemsx->public, kemsx->secret);
8009b50bc25Stobhe 		/* output */
8019b50bc25Stobhe 		need = crypto_kem_sntrup761_PUBLICKEYBYTES +
8029b50bc25Stobhe 		    CURVE25519_SIZE;
8039b50bc25Stobhe 		buf = ibuf_new(NULL, need);
8049b50bc25Stobhe 		if (buf == NULL)
8059b50bc25Stobhe 			return -1;
8069b50bc25Stobhe 		cp = buf->buf;
8079b50bc25Stobhe 		memcpy(cp, kemsx->public,
8089b50bc25Stobhe 		    crypto_kem_sntrup761_PUBLICKEYBYTES);
8099b50bc25Stobhe 		cp += crypto_kem_sntrup761_PUBLICKEYBYTES;
8109b50bc25Stobhe 	} else {
8119b50bc25Stobhe 		kemsx->initiator = 0;
8129b50bc25Stobhe 		/* input */
8139b50bc25Stobhe 		have = ibuf_size(iexchange);
8149b50bc25Stobhe 		need = crypto_kem_sntrup761_PUBLICKEYBYTES +
8159b50bc25Stobhe 		    CURVE25519_SIZE;
8169b50bc25Stobhe 		if (have != need)
8179b50bc25Stobhe 			return -1;
8189b50bc25Stobhe 		/* output */
8199b50bc25Stobhe 		need = crypto_kem_sntrup761_CIPHERTEXTBYTES +
8209b50bc25Stobhe 		    CURVE25519_SIZE;
8219b50bc25Stobhe 		buf = ibuf_new(NULL, need);
8229b50bc25Stobhe 		if (buf == NULL)
8239b50bc25Stobhe 			return -1;
8249b50bc25Stobhe 		cp = buf->buf;
8259b50bc25Stobhe 		pk = iexchange->buf;
8269b50bc25Stobhe 		crypto_kem_sntrup761_enc(cp, kemsx->kemkey, pk);
8279b50bc25Stobhe 		cp += crypto_kem_sntrup761_CIPHERTEXTBYTES;
8289b50bc25Stobhe 	}
8299b50bc25Stobhe 	curve25519 = group->curve25519;
8309b50bc25Stobhe 	memcpy(cp, curve25519->public, CURVE25519_SIZE);
8319b50bc25Stobhe 	*bufp = buf;
8329b50bc25Stobhe 	return (0);
8339b50bc25Stobhe }
8349b50bc25Stobhe 
8359b50bc25Stobhe int
8369b50bc25Stobhe kemsx_create_shared2(struct dh_group *group, struct ibuf **sharedp,
8379b50bc25Stobhe     struct ibuf *exchange)
8389b50bc25Stobhe {
8399b50bc25Stobhe 	struct curve25519_key	*curve25519 = group->curve25519;
8409b50bc25Stobhe 	struct kemsx_key	*kemsx = group->kemsx;
8419b50bc25Stobhe 	struct ibuf		*buf = NULL;
8429b50bc25Stobhe 	EVP_MD_CTX		*ctx = NULL;
8439b50bc25Stobhe 	u_int8_t		*cp;
8449b50bc25Stobhe 	u_int8_t		 shared[CURVE25519_SIZE];
8459b50bc25Stobhe 	size_t			 have, need;
8469b50bc25Stobhe 	u_int			 len;
8479b50bc25Stobhe 
8489b50bc25Stobhe 	*sharedp = NULL;
8499b50bc25Stobhe 	if (kemsx == NULL)
8509b50bc25Stobhe 		return (-1);
8519b50bc25Stobhe 	if (exchange == NULL)
8529b50bc25Stobhe 		return (-1);
8539b50bc25Stobhe 
8549b50bc25Stobhe 	have = ibuf_size(exchange);
8559b50bc25Stobhe 	cp = exchange->buf;
8569b50bc25Stobhe 	if (kemsx->initiator) {
8579b50bc25Stobhe 		/* input */
8589b50bc25Stobhe 		need = crypto_kem_sntrup761_CIPHERTEXTBYTES +
8599b50bc25Stobhe 		    CURVE25519_SIZE;
8609b50bc25Stobhe 		if (have != need)
8619b50bc25Stobhe 			return (-1);
8629b50bc25Stobhe 		crypto_kem_sntrup761_dec(kemsx->kemkey, cp, kemsx->secret);
8639b50bc25Stobhe 		cp += crypto_kem_sntrup761_CIPHERTEXTBYTES;
8649b50bc25Stobhe 	} else {
8659b50bc25Stobhe 		/* input, should have been checked before */
8669b50bc25Stobhe 		need = crypto_kem_sntrup761_PUBLICKEYBYTES +
8679b50bc25Stobhe 		    CURVE25519_SIZE;
8689b50bc25Stobhe 		if (have != need)
8699b50bc25Stobhe 			return (-1);
8709b50bc25Stobhe 		cp += crypto_kem_sntrup761_PUBLICKEYBYTES;
8719b50bc25Stobhe 	}
8729b50bc25Stobhe 	crypto_scalarmult_curve25519(shared, curve25519->secret, cp);
8739b50bc25Stobhe 
8749b50bc25Stobhe 	/* result is hash of concatenation of KEM key and DH shared secret */
8759b50bc25Stobhe 	len = SHA512_DIGEST_LENGTH;
8769b50bc25Stobhe 	buf = ibuf_new(NULL, len);
8779b50bc25Stobhe 	if (buf == NULL)
8789b50bc25Stobhe 		return (-1);
8799b50bc25Stobhe 	if ((ctx = EVP_MD_CTX_new()) == NULL ||
8809b50bc25Stobhe 	    EVP_DigestInit_ex(ctx, EVP_sha512(), NULL) != 1 ||
8819b50bc25Stobhe 	    EVP_DigestUpdate(ctx, kemsx->kemkey, sizeof(kemsx->kemkey)) != 1 ||
8829b50bc25Stobhe 	    EVP_DigestUpdate(ctx, shared, sizeof(shared)) != 1 ||
8839b50bc25Stobhe 	    EVP_DigestFinal_ex(ctx, buf->buf, &len) != 1) {
8849b50bc25Stobhe 		EVP_MD_CTX_free(ctx);
8859b50bc25Stobhe 		ibuf_free(buf);
8869b50bc25Stobhe 		return (-1);
8879b50bc25Stobhe 	}
8889b50bc25Stobhe 	EVP_MD_CTX_free(ctx);
8899b50bc25Stobhe 	*sharedp = buf;
8909b50bc25Stobhe 	return (0);
8919b50bc25Stobhe }
892