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