xref: /openbsd/sbin/iked/dh.c (revision a699afca)
1*a699afcaSclaudio /*	$OpenBSD: dh.c,v 1.33 2023/07/28 07:31:38 claudio 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 
19d8ea035bSderaadt #include <sys/types.h>
2045ae9d61Sreyk 
21710c50d7Stobhe #include <sys/queue.h>
22710c50d7Stobhe #include <sys/socket.h>
23710c50d7Stobhe #include <sys/uio.h>
24d8ea035bSderaadt #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,
274d8ea035bSderaadt 	   (MAXIMUM(crypto_kem_sntrup761_PUBLICKEYBYTES,
2759b50bc25Stobhe 	        crypto_kem_sntrup761_CIPHERTEXTBYTES) +
2769b50bc25Stobhe 	    CURVE25519_SIZE) * 8 }
27745ae9d61Sreyk };
27845ae9d61Sreyk 
27945ae9d61Sreyk void
group_init(void)28045ae9d61Sreyk group_init(void)
28145ae9d61Sreyk {
2820d5bf58dSreyk 	/* currently not used */
28345ae9d61Sreyk 	return;
28445ae9d61Sreyk }
28545ae9d61Sreyk 
28645ae9d61Sreyk void
group_free(struct dh_group * group)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 *
group_get(uint32_t id)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 *
group_getid(uint32_t 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
dh_init(struct dh_group * group)3720e1bb3dcStobhe dh_init(struct dh_group *group)
37345ae9d61Sreyk {
37445ae9d61Sreyk 	return (group->init(group));
37545ae9d61Sreyk }
37645ae9d61Sreyk 
37745ae9d61Sreyk int
dh_getlen(struct dh_group * group)3780e1bb3dcStobhe dh_getlen(struct dh_group *group)
37945ae9d61Sreyk {
38045ae9d61Sreyk 	return (group->getlen(group));
38145ae9d61Sreyk }
38245ae9d61Sreyk 
38345ae9d61Sreyk int
dh_secretlen(struct dh_group * group)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
dh_create_exchange(struct dh_group * group,struct ibuf ** bufp,struct ibuf * iexchange)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;
404*a699afcaSclaudio 	return (group->exchange(group, ibuf_data(buf)));
40545ae9d61Sreyk }
40645ae9d61Sreyk 
40745ae9d61Sreyk int
dh_create_shared(struct dh_group * group,struct ibuf ** secretp,struct ibuf * exchange)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;
422*a699afcaSclaudio 	return (group->shared(group, ibuf_data(buf), ibuf_data(exchange)));
42345ae9d61Sreyk }
42445ae9d61Sreyk 
42545ae9d61Sreyk int
modp_init(struct dh_group * group)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
modp_getlen(struct dh_group * group)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
modp_create_exchange(struct dh_group * group,uint8_t * buf)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
modp_create_shared(struct dh_group * group,uint8_t * secret,uint8_t * exchange)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
ec_init(struct dh_group * group)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);
516ae5d40d6Stb 	if (!EC_KEY_check_key(group->ec))
517c900656bSmarkus 		return (-1);
51845ae9d61Sreyk 	return (0);
51945ae9d61Sreyk }
52045ae9d61Sreyk 
52145ae9d61Sreyk int
ec_getlen(struct dh_group * group)5220e1bb3dcStobhe ec_getlen(struct dh_group *group)
52345ae9d61Sreyk {
52445ae9d61Sreyk 	if (group->spec == NULL)
52545ae9d61Sreyk 		return (0);
52645b72fd1Smikeb 	/* NB:  Return value will always be even */
52745ae9d61Sreyk 	return ((roundup(group->spec->bits, 8) * 2) / 8);
52845ae9d61Sreyk }
52945ae9d61Sreyk 
530a6321d0fSpatrick /*
531a6321d0fSpatrick  * Note that the shared secret only includes the x value:
532a6321d0fSpatrick  *
533a6321d0fSpatrick  * See RFC 5903, 7. ECP Key Exchange Data Formats:
534a6321d0fSpatrick  *   The Diffie-Hellman shared secret value consists of the x value of the
535a6321d0fSpatrick  *   Diffie-Hellman common value.
536a6321d0fSpatrick  * See also RFC 5903, 9. Changes from RFC 4753.
537a6321d0fSpatrick  */
538a6321d0fSpatrick int
ec_secretlen(struct dh_group * group)5390e1bb3dcStobhe ec_secretlen(struct dh_group *group)
540a6321d0fSpatrick {
541a6321d0fSpatrick 	return (ec_getlen(group) / 2);
542a6321d0fSpatrick }
543a6321d0fSpatrick 
54445ae9d61Sreyk int
ec_create_exchange(struct dh_group * group,uint8_t * buf)5450e1bb3dcStobhe ec_create_exchange(struct dh_group *group, uint8_t *buf)
54645ae9d61Sreyk {
5470d5bf58dSreyk 	size_t	 len;
5480d5bf58dSreyk 
5490d5bf58dSreyk 	len = ec_getlen(group);
5500d5bf58dSreyk 	bzero(buf, len);
5510d5bf58dSreyk 
55245ae9d61Sreyk 	return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec),
553a6321d0fSpatrick 	    buf, len, EC_POINT2RAW_FULL));
55445ae9d61Sreyk }
55545ae9d61Sreyk 
55645ae9d61Sreyk int
ec_create_shared(struct dh_group * group,uint8_t * secret,uint8_t * exchange)5570e1bb3dcStobhe ec_create_shared(struct dh_group *group, uint8_t *secret, uint8_t *exchange)
55845ae9d61Sreyk {
55945ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
56045ae9d61Sreyk 	const BIGNUM	*privkey;
561c900656bSmarkus 	EC_KEY		*exkey = NULL;
56245ae9d61Sreyk 	EC_POINT	*exchangep = NULL, *secretp = NULL;
56345ae9d61Sreyk 	int		 ret = -1;
56445ae9d61Sreyk 
56545ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL ||
56645ae9d61Sreyk 	    (privkey = EC_KEY_get0_private_key(group->ec)) == NULL)
56745ae9d61Sreyk 		goto done;
56845ae9d61Sreyk 
56945ae9d61Sreyk 	if ((exchangep =
57045ae9d61Sreyk 	    ec_raw2point(group, exchange, ec_getlen(group))) == NULL)
57145ae9d61Sreyk 		goto done;
57245ae9d61Sreyk 
573c900656bSmarkus 	if ((exkey = EC_KEY_new()) == NULL)
574c900656bSmarkus 		goto done;
575c900656bSmarkus 	if (!EC_KEY_set_group(exkey, ecgroup))
576c900656bSmarkus 		goto done;
577c900656bSmarkus 	if (!EC_KEY_set_public_key(exkey, exchangep))
578c900656bSmarkus 		goto done;
579c900656bSmarkus 
580c900656bSmarkus 	/* validate exchangep */
581c900656bSmarkus 	if (!EC_KEY_check_key(exkey))
582c900656bSmarkus 		goto done;
583c900656bSmarkus 
58445ae9d61Sreyk 	if ((secretp = EC_POINT_new(ecgroup)) == NULL)
58545ae9d61Sreyk 		goto done;
58645ae9d61Sreyk 
58745ae9d61Sreyk 	if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL))
58845ae9d61Sreyk 		goto done;
58945ae9d61Sreyk 
590a6321d0fSpatrick 	ret = ec_point2raw(group, secretp, secret, ec_secretlen(group),
591a6321d0fSpatrick 	    EC_POINT2RAW_XONLY);
59245ae9d61Sreyk 
59345ae9d61Sreyk  done:
594c900656bSmarkus 	if (exkey != NULL)
595c900656bSmarkus 		EC_KEY_free(exkey);
59645ae9d61Sreyk 	if (exchangep != NULL)
59745ae9d61Sreyk 		EC_POINT_clear_free(exchangep);
59845ae9d61Sreyk 	if (secretp != NULL)
59945ae9d61Sreyk 		EC_POINT_clear_free(secretp);
60045ae9d61Sreyk 
60145ae9d61Sreyk 	return (ret);
60245ae9d61Sreyk }
60345ae9d61Sreyk 
60445ae9d61Sreyk int
ec_point2raw(struct dh_group * group,const EC_POINT * point,uint8_t * buf,size_t len,int mode)6050e1bb3dcStobhe ec_point2raw(struct dh_group *group, const EC_POINT *point,
606a6321d0fSpatrick     uint8_t *buf, size_t len, int mode)
60745ae9d61Sreyk {
60845ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
60945ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
61045ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
61145ae9d61Sreyk 	int		 ret = -1;
61245b72fd1Smikeb 	size_t		 eclen, xlen, ylen;
61345ae9d61Sreyk 	off_t		 xoff, yoff;
61445ae9d61Sreyk 
61545ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
61645ae9d61Sreyk 		goto done;
61745ae9d61Sreyk 	BN_CTX_start(bnctx);
61845ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
61945ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
62045ae9d61Sreyk 		goto done;
62145ae9d61Sreyk 
62245b72fd1Smikeb 	eclen = ec_getlen(group);
623a6321d0fSpatrick 	switch (mode) {
624a6321d0fSpatrick 	case EC_POINT2RAW_XONLY:
625a6321d0fSpatrick 		xlen = eclen / 2;
626a6321d0fSpatrick 		ylen = 0;
627a6321d0fSpatrick 		break;
628a6321d0fSpatrick 	case EC_POINT2RAW_FULL:
62945b72fd1Smikeb 		xlen = ylen = eclen / 2;
630a6321d0fSpatrick 		break;
631a6321d0fSpatrick 	default:
632a6321d0fSpatrick 		goto done;
633a6321d0fSpatrick 	}
634a6321d0fSpatrick 	if (len < xlen + ylen)
635a6321d0fSpatrick 		goto done;
63645b72fd1Smikeb 
63745ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
63845ae9d61Sreyk 		goto done;
63945ae9d61Sreyk 
640d1f8a43dStb 	if (!EC_POINT_get_affine_coordinates(ecgroup, point, x, y, bnctx))
64145ae9d61Sreyk 		goto done;
64245ae9d61Sreyk 
64345ae9d61Sreyk 	xoff = xlen - BN_num_bytes(x);
64445b72fd1Smikeb 	bzero(buf, xoff);
64545ae9d61Sreyk 	if (!BN_bn2bin(x, buf + xoff))
64645ae9d61Sreyk 		goto done;
64745ae9d61Sreyk 
648a6321d0fSpatrick 	if (ylen > 0) {
64945ae9d61Sreyk 		yoff = (ylen - BN_num_bytes(y)) + xlen;
65045b72fd1Smikeb 		bzero(buf + xlen, yoff - xlen);
65145ae9d61Sreyk 		if (!BN_bn2bin(y, buf + yoff))
65245ae9d61Sreyk 			goto done;
653a6321d0fSpatrick 	}
65445ae9d61Sreyk 
65545ae9d61Sreyk 	ret = 0;
65645ae9d61Sreyk  done:
657c900656bSmarkus 	/* Make sure to erase sensitive data */
658c900656bSmarkus 	if (x != NULL)
659c900656bSmarkus 		BN_clear(x);
660c900656bSmarkus 	if (y != NULL)
661c900656bSmarkus 		BN_clear(y);
66245ae9d61Sreyk 	BN_CTX_end(bnctx);
66345ae9d61Sreyk 	BN_CTX_free(bnctx);
66445ae9d61Sreyk 
66545ae9d61Sreyk 	return (ret);
66645ae9d61Sreyk }
66745ae9d61Sreyk 
66845ae9d61Sreyk EC_POINT *
ec_raw2point(struct dh_group * group,uint8_t * buf,size_t len)6690e1bb3dcStobhe ec_raw2point(struct dh_group *group, uint8_t *buf, size_t len)
67045ae9d61Sreyk {
67145ae9d61Sreyk 	const EC_GROUP	*ecgroup = NULL;
67245ae9d61Sreyk 	EC_POINT	*point = NULL;
67345ae9d61Sreyk 	BN_CTX		*bnctx = NULL;
67445ae9d61Sreyk 	BIGNUM		*x = NULL, *y = NULL;
67545ae9d61Sreyk 	int		 ret = -1;
67645ae9d61Sreyk 	size_t		 eclen;
67745ae9d61Sreyk 	size_t		 xlen, ylen;
67845ae9d61Sreyk 
67945ae9d61Sreyk 	if ((bnctx = BN_CTX_new()) == NULL)
68045ae9d61Sreyk 		goto done;
68145ae9d61Sreyk 	BN_CTX_start(bnctx);
68245ae9d61Sreyk 	if ((x = BN_CTX_get(bnctx)) == NULL ||
68345ae9d61Sreyk 	    (y = BN_CTX_get(bnctx)) == NULL)
68445ae9d61Sreyk 		goto done;
68545ae9d61Sreyk 
68645ae9d61Sreyk 	eclen = ec_getlen(group);
68745ae9d61Sreyk 	if (len < eclen)
68845ae9d61Sreyk 		goto done;
68945ae9d61Sreyk 	xlen = ylen = eclen / 2;
69045ae9d61Sreyk 	if ((x = BN_bin2bn(buf, xlen, x)) == NULL ||
69145ae9d61Sreyk 	    (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL)
69245ae9d61Sreyk 		goto done;
69345ae9d61Sreyk 
69445ae9d61Sreyk 	if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
69545ae9d61Sreyk 		goto done;
69645ae9d61Sreyk 
69745ae9d61Sreyk 	if ((point = EC_POINT_new(ecgroup)) == NULL)
69845ae9d61Sreyk 		goto done;
69945ae9d61Sreyk 
700d1f8a43dStb 	if (!EC_POINT_set_affine_coordinates(ecgroup, point, x, y, bnctx))
70145ae9d61Sreyk 		goto done;
70245ae9d61Sreyk 
70345ae9d61Sreyk 	ret = 0;
70445ae9d61Sreyk  done:
70545ae9d61Sreyk 	if (ret != 0 && point != NULL)
70645ae9d61Sreyk 		EC_POINT_clear_free(point);
707c900656bSmarkus 	/* Make sure to erase sensitive data */
708c900656bSmarkus 	if (x != NULL)
709c900656bSmarkus 		BN_clear(x);
710c900656bSmarkus 	if (y != NULL)
711c900656bSmarkus 		BN_clear(y);
71245ae9d61Sreyk 	BN_CTX_end(bnctx);
71345ae9d61Sreyk 	BN_CTX_free(bnctx);
71445ae9d61Sreyk 
71545ae9d61Sreyk 	return (point);
71645ae9d61Sreyk }
71745135ebcSreyk 
71845135ebcSreyk int
ec25519_init(struct dh_group * group)7190e1bb3dcStobhe ec25519_init(struct dh_group *group)
72045135ebcSreyk {
721d09d3a7dSreyk 	static const uint8_t	 basepoint[CURVE25519_SIZE] = { 9 };
72245135ebcSreyk 	struct curve25519_key	*curve25519;
72345135ebcSreyk 
72445135ebcSreyk 	if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL)
72545135ebcSreyk 		return (-1);
72645135ebcSreyk 
72745135ebcSreyk 	group->curve25519 = curve25519;
72845135ebcSreyk 
72945135ebcSreyk 	arc4random_buf(curve25519->secret, CURVE25519_SIZE);
73045135ebcSreyk 	crypto_scalarmult_curve25519(curve25519->public,
73145135ebcSreyk 	    curve25519->secret, basepoint);
73245135ebcSreyk 
73345135ebcSreyk 	return (0);
73445135ebcSreyk }
73545135ebcSreyk 
73645135ebcSreyk int
ec25519_getlen(struct dh_group * group)7370e1bb3dcStobhe ec25519_getlen(struct dh_group *group)
73845135ebcSreyk {
73945135ebcSreyk 	if (group->spec == NULL)
74045135ebcSreyk 		return (0);
74145135ebcSreyk 	return (CURVE25519_SIZE);
74245135ebcSreyk }
74345135ebcSreyk 
74445135ebcSreyk int
ec25519_create_exchange(struct dh_group * group,uint8_t * buf)7450e1bb3dcStobhe ec25519_create_exchange(struct dh_group *group, uint8_t *buf)
74645135ebcSreyk {
74745135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
74845135ebcSreyk 
74945135ebcSreyk 	memcpy(buf, curve25519->public, ec25519_getlen(group));
75045135ebcSreyk 	return (0);
75145135ebcSreyk }
75245135ebcSreyk 
75345135ebcSreyk int
ec25519_create_shared(struct dh_group * group,uint8_t * shared,uint8_t * public)7540e1bb3dcStobhe ec25519_create_shared(struct dh_group *group, uint8_t *shared, uint8_t *public)
75545135ebcSreyk {
75645135ebcSreyk 	struct curve25519_key	*curve25519 = group->curve25519;
75745135ebcSreyk 
75845135ebcSreyk 	crypto_scalarmult_curve25519(shared, curve25519->secret, public);
75945135ebcSreyk 	return (0);
76045135ebcSreyk }
7619b50bc25Stobhe 
7629b50bc25Stobhe /* combine sntrup761 with curve25519 */
7639b50bc25Stobhe 
7649b50bc25Stobhe int
kemsx_init(struct dh_group * group)7659b50bc25Stobhe kemsx_init(struct dh_group *group)
7669b50bc25Stobhe {
7679b50bc25Stobhe 	/* delayed until kemsx_create_exchange2 */
7689b50bc25Stobhe 	return (0);
7699b50bc25Stobhe }
7709b50bc25Stobhe 
7719b50bc25Stobhe int
kemsx_getlen(struct dh_group * group)7729b50bc25Stobhe kemsx_getlen(struct dh_group *group)
7739b50bc25Stobhe {
7749b50bc25Stobhe 	return (0);
7759b50bc25Stobhe }
7769b50bc25Stobhe 
7779b50bc25Stobhe int
kemsx_create_exchange2(struct dh_group * group,struct ibuf ** bufp,struct ibuf * iexchange)7789b50bc25Stobhe kemsx_create_exchange2(struct dh_group *group, struct ibuf **bufp,
7799b50bc25Stobhe     struct ibuf *iexchange)
7809b50bc25Stobhe {
7819b50bc25Stobhe 	struct kemsx_key	*kemsx;
7829b50bc25Stobhe 	struct curve25519_key	*curve25519;
7839b50bc25Stobhe 	struct ibuf		*buf = NULL;
7849b50bc25Stobhe 	u_char *cp, *pk;
7859b50bc25Stobhe 	size_t have, need;
7869b50bc25Stobhe 
7879b50bc25Stobhe 	if (ec25519_init(group) == -1)
7889b50bc25Stobhe 		return (-1);
7899b50bc25Stobhe 	if (group->curve25519 == NULL)
7909b50bc25Stobhe 		return (-1);
7919b50bc25Stobhe 	if ((kemsx = calloc(1, sizeof(*kemsx))) == NULL)
7929b50bc25Stobhe 		return (-1);
7939b50bc25Stobhe 	group->kemsx = kemsx;
7949b50bc25Stobhe 
7959b50bc25Stobhe 	if (iexchange == NULL) {
7969b50bc25Stobhe 		kemsx->initiator = 1;
7979b50bc25Stobhe 		crypto_kem_sntrup761_keypair(kemsx->public, kemsx->secret);
7989b50bc25Stobhe 		/* output */
7999b50bc25Stobhe 		need = crypto_kem_sntrup761_PUBLICKEYBYTES +
8009b50bc25Stobhe 		    CURVE25519_SIZE;
8019b50bc25Stobhe 		buf = ibuf_new(NULL, need);
8029b50bc25Stobhe 		if (buf == NULL)
8039b50bc25Stobhe 			return -1;
804*a699afcaSclaudio 		cp = ibuf_data(buf);
8059b50bc25Stobhe 		memcpy(cp, kemsx->public,
8069b50bc25Stobhe 		    crypto_kem_sntrup761_PUBLICKEYBYTES);
8079b50bc25Stobhe 		cp += crypto_kem_sntrup761_PUBLICKEYBYTES;
8089b50bc25Stobhe 	} else {
8099b50bc25Stobhe 		kemsx->initiator = 0;
8109b50bc25Stobhe 		/* input */
8119b50bc25Stobhe 		have = ibuf_size(iexchange);
8129b50bc25Stobhe 		need = crypto_kem_sntrup761_PUBLICKEYBYTES +
8139b50bc25Stobhe 		    CURVE25519_SIZE;
8149b50bc25Stobhe 		if (have != need)
8159b50bc25Stobhe 			return -1;
8169b50bc25Stobhe 		/* output */
8179b50bc25Stobhe 		need = crypto_kem_sntrup761_CIPHERTEXTBYTES +
8189b50bc25Stobhe 		    CURVE25519_SIZE;
8199b50bc25Stobhe 		buf = ibuf_new(NULL, need);
8209b50bc25Stobhe 		if (buf == NULL)
8219b50bc25Stobhe 			return -1;
822*a699afcaSclaudio 		cp = ibuf_data(buf);
823*a699afcaSclaudio 		pk = ibuf_data(iexchange);
8249b50bc25Stobhe 		crypto_kem_sntrup761_enc(cp, kemsx->kemkey, pk);
8259b50bc25Stobhe 		cp += crypto_kem_sntrup761_CIPHERTEXTBYTES;
8269b50bc25Stobhe 	}
8279b50bc25Stobhe 	curve25519 = group->curve25519;
8289b50bc25Stobhe 	memcpy(cp, curve25519->public, CURVE25519_SIZE);
8299b50bc25Stobhe 	*bufp = buf;
8309b50bc25Stobhe 	return (0);
8319b50bc25Stobhe }
8329b50bc25Stobhe 
8339b50bc25Stobhe int
kemsx_create_shared2(struct dh_group * group,struct ibuf ** sharedp,struct ibuf * exchange)8349b50bc25Stobhe kemsx_create_shared2(struct dh_group *group, struct ibuf **sharedp,
8359b50bc25Stobhe     struct ibuf *exchange)
8369b50bc25Stobhe {
8379b50bc25Stobhe 	struct curve25519_key	*curve25519 = group->curve25519;
8389b50bc25Stobhe 	struct kemsx_key	*kemsx = group->kemsx;
8399b50bc25Stobhe 	struct ibuf		*buf = NULL;
8409b50bc25Stobhe 	EVP_MD_CTX		*ctx = NULL;
841229c27f0Stobhe 	uint8_t			*cp;
842229c27f0Stobhe 	uint8_t			 shared[CURVE25519_SIZE];
8439b50bc25Stobhe 	size_t			 have, need;
8449b50bc25Stobhe 	u_int			 len;
8459b50bc25Stobhe 
8469b50bc25Stobhe 	*sharedp = NULL;
8479b50bc25Stobhe 	if (kemsx == NULL)
8489b50bc25Stobhe 		return (-1);
8499b50bc25Stobhe 	if (exchange == NULL)
8509b50bc25Stobhe 		return (-1);
8519b50bc25Stobhe 
8529b50bc25Stobhe 	have = ibuf_size(exchange);
853*a699afcaSclaudio 	cp = ibuf_data(exchange);
8549b50bc25Stobhe 	if (kemsx->initiator) {
8559b50bc25Stobhe 		/* input */
8569b50bc25Stobhe 		need = crypto_kem_sntrup761_CIPHERTEXTBYTES +
8579b50bc25Stobhe 		    CURVE25519_SIZE;
8589b50bc25Stobhe 		if (have != need)
8599b50bc25Stobhe 			return (-1);
8609b50bc25Stobhe 		crypto_kem_sntrup761_dec(kemsx->kemkey, cp, kemsx->secret);
8619b50bc25Stobhe 		cp += crypto_kem_sntrup761_CIPHERTEXTBYTES;
8629b50bc25Stobhe 	} else {
8639b50bc25Stobhe 		/* input, should have been checked before */
8649b50bc25Stobhe 		need = crypto_kem_sntrup761_PUBLICKEYBYTES +
8659b50bc25Stobhe 		    CURVE25519_SIZE;
8669b50bc25Stobhe 		if (have != need)
8679b50bc25Stobhe 			return (-1);
8689b50bc25Stobhe 		cp += crypto_kem_sntrup761_PUBLICKEYBYTES;
8699b50bc25Stobhe 	}
8709b50bc25Stobhe 	crypto_scalarmult_curve25519(shared, curve25519->secret, cp);
8719b50bc25Stobhe 
8729b50bc25Stobhe 	/* result is hash of concatenation of KEM key and DH shared secret */
8739b50bc25Stobhe 	len = SHA512_DIGEST_LENGTH;
8749b50bc25Stobhe 	buf = ibuf_new(NULL, len);
8759b50bc25Stobhe 	if (buf == NULL)
8769b50bc25Stobhe 		return (-1);
8779b50bc25Stobhe 	if ((ctx = EVP_MD_CTX_new()) == NULL ||
8789b50bc25Stobhe 	    EVP_DigestInit_ex(ctx, EVP_sha512(), NULL) != 1 ||
8799b50bc25Stobhe 	    EVP_DigestUpdate(ctx, kemsx->kemkey, sizeof(kemsx->kemkey)) != 1 ||
8809b50bc25Stobhe 	    EVP_DigestUpdate(ctx, shared, sizeof(shared)) != 1 ||
881*a699afcaSclaudio 	    EVP_DigestFinal_ex(ctx, ibuf_data(buf), &len) != 1) {
8829b50bc25Stobhe 		EVP_MD_CTX_free(ctx);
8839b50bc25Stobhe 		ibuf_free(buf);
8849b50bc25Stobhe 		return (-1);
8859b50bc25Stobhe 	}
8869b50bc25Stobhe 	EVP_MD_CTX_free(ctx);
8879b50bc25Stobhe 	*sharedp = buf;
8889b50bc25Stobhe 	return (0);
8899b50bc25Stobhe }
890