1*ae5d40d6Stb /* $OpenBSD: dh.c,v 1.31 2021/12/13 18:06:56 tb 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 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); 516*ae5d40d6Stb if (!EC_KEY_check_key(group->ec)) 517c900656bSmarkus return (-1); 51845ae9d61Sreyk return (0); 51945ae9d61Sreyk } 52045ae9d61Sreyk 52145ae9d61Sreyk int 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 5390e1bb3dcStobhe ec_secretlen(struct dh_group *group) 540a6321d0fSpatrick { 541a6321d0fSpatrick return (ec_getlen(group) / 2); 542a6321d0fSpatrick } 543a6321d0fSpatrick 54445ae9d61Sreyk int 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 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 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 * 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 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 7370e1bb3dcStobhe ec25519_getlen(struct dh_group *group) 73845135ebcSreyk { 73945135ebcSreyk if (group->spec == NULL) 74045135ebcSreyk return (0); 74145135ebcSreyk return (CURVE25519_SIZE); 74245135ebcSreyk } 74345135ebcSreyk 74445135ebcSreyk int 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 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 7659b50bc25Stobhe kemsx_init(struct dh_group *group) 7669b50bc25Stobhe { 7679b50bc25Stobhe /* delayed until kemsx_create_exchange2 */ 7689b50bc25Stobhe return (0); 7699b50bc25Stobhe } 7709b50bc25Stobhe 7719b50bc25Stobhe int 7729b50bc25Stobhe kemsx_getlen(struct dh_group *group) 7739b50bc25Stobhe { 7749b50bc25Stobhe return (0); 7759b50bc25Stobhe } 7769b50bc25Stobhe 7779b50bc25Stobhe int 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; 8049b50bc25Stobhe cp = buf->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; 8229b50bc25Stobhe cp = buf->buf; 8239b50bc25Stobhe pk = iexchange->buf; 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 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; 8419b50bc25Stobhe u_int8_t *cp; 8429b50bc25Stobhe u_int8_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); 8539b50bc25Stobhe cp = exchange->buf; 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 || 8819b50bc25Stobhe EVP_DigestFinal_ex(ctx, buf->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