1*bc77414bStobhe /* $OpenBSD: dh.c,v 1.23 2020/04/28 15:18:52 tobhe Exp $ */ 245ae9d61Sreyk 345ae9d61Sreyk /* 4547eb84dSreyk * Copyright (c) 2010-2014 Reyk Floeter <reyk@openbsd.org> 545ae9d61Sreyk * 645ae9d61Sreyk * Permission to use, copy, modify, and distribute this software for any 745ae9d61Sreyk * purpose with or without fee is hereby granted, provided that the above 845ae9d61Sreyk * copyright notice and this permission notice appear in all copies. 945ae9d61Sreyk * 1045ae9d61Sreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1145ae9d61Sreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1245ae9d61Sreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1345ae9d61Sreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1445ae9d61Sreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1545ae9d61Sreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1645ae9d61Sreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1745ae9d61Sreyk */ 1845ae9d61Sreyk 19b9fc9a72Sderaadt #include <sys/param.h> /* roundup */ 2045ae9d61Sreyk #include <string.h> 2145ae9d61Sreyk 2245ae9d61Sreyk #include <openssl/obj_mac.h> 2345ae9d61Sreyk #include <openssl/dh.h> 2445ae9d61Sreyk #include <openssl/ec.h> 2545ae9d61Sreyk #include <openssl/ecdh.h> 26a4194998Sjsg #include <openssl/bn.h> 2745ae9d61Sreyk 2845ae9d61Sreyk #include "dh.h" 290d5bf58dSreyk 300d5bf58dSreyk int dh_init(struct group *); 3145ae9d61Sreyk 3245135ebcSreyk /* MODP */ 3345ae9d61Sreyk int modp_init(struct group *); 3445ae9d61Sreyk int modp_getlen(struct group *); 35d09d3a7dSreyk int modp_create_exchange(struct group *, uint8_t *); 36d09d3a7dSreyk int modp_create_shared(struct group *, uint8_t *, uint8_t *); 3745ae9d61Sreyk 38*bc77414bStobhe /* ECP */ 3945ae9d61Sreyk int ec_init(struct group *); 4045ae9d61Sreyk int ec_getlen(struct group *); 41a6321d0fSpatrick int ec_secretlen(struct group *); 42d09d3a7dSreyk int ec_create_exchange(struct group *, uint8_t *); 43d09d3a7dSreyk int ec_create_shared(struct group *, uint8_t *, uint8_t *); 4445ae9d61Sreyk 45a6321d0fSpatrick #define EC_POINT2RAW_FULL 0 46a6321d0fSpatrick #define EC_POINT2RAW_XONLY 1 47a6321d0fSpatrick int ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t, int); 4845ae9d61Sreyk EC_POINT * 49d09d3a7dSreyk ec_raw2point(struct group *, uint8_t *, size_t); 5045ae9d61Sreyk 5145135ebcSreyk /* curve25519 */ 5245135ebcSreyk int ec25519_init(struct group *); 5345135ebcSreyk int ec25519_getlen(struct group *); 54d09d3a7dSreyk int ec25519_create_exchange(struct group *, uint8_t *); 55d09d3a7dSreyk int ec25519_create_shared(struct group *, uint8_t *, uint8_t *); 5645135ebcSreyk 5745135ebcSreyk #define CURVE25519_SIZE 32 /* 256 bits */ 5845135ebcSreyk struct curve25519_key { 59d09d3a7dSreyk uint8_t secret[CURVE25519_SIZE]; 60d09d3a7dSreyk uint8_t public[CURVE25519_SIZE]; 6145135ebcSreyk }; 62d09d3a7dSreyk extern int crypto_scalarmult_curve25519(unsigned char a[CURVE25519_SIZE], 63d09d3a7dSreyk const unsigned char b[CURVE25519_SIZE], 64d09d3a7dSreyk const unsigned char c[CURVE25519_SIZE]) 6545135ebcSreyk __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) 6645135ebcSreyk __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))) 6745135ebcSreyk __attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE))); 6845135ebcSreyk 69e254d6eaSmikeb const struct group_id ike_groups[] = { 7045ae9d61Sreyk { GROUP_MODP, 1, 768, 7145ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 7245ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 7345ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 7445ae9d61Sreyk "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 7545ae9d61Sreyk "02" 7645ae9d61Sreyk }, 7745ae9d61Sreyk { GROUP_MODP, 2, 1024, 7845ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 7945ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 8045ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 8145ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 8245ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" 8345ae9d61Sreyk "FFFFFFFFFFFFFFFF", 8445ae9d61Sreyk "02" 8545ae9d61Sreyk }, 8645ae9d61Sreyk { GROUP_MODP, 5, 1536, 8745ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 8845ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 8945ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 9045ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 9145ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 9245ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 9345ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 9445ae9d61Sreyk "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 9545ae9d61Sreyk "02" 9645ae9d61Sreyk }, 9745ae9d61Sreyk { GROUP_MODP, 14, 2048, 9845ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 9945ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 10045ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 10145ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 10245ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 10345ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 10445ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 10545ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 10645ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 10745ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 10845ae9d61Sreyk "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 10945ae9d61Sreyk "02" 11045ae9d61Sreyk }, 11145ae9d61Sreyk { GROUP_MODP, 15, 3072, 11245ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 11345ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 11445ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 11545ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 11645ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 11745ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 11845ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 11945ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 12045ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 12145ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 12245ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 12345ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 12445ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 12545ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 12645ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 12745ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 12845ae9d61Sreyk "02" 12945ae9d61Sreyk }, 13045ae9d61Sreyk { GROUP_MODP, 16, 4096, 13145ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 13245ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 13345ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 13445ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 13545ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 13645ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 13745ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 13845ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 13945ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 14045ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 14145ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 14245ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 14345ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 14445ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 14545ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 14645ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" 14745ae9d61Sreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" 14845ae9d61Sreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" 14945ae9d61Sreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" 15045ae9d61Sreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" 15145ae9d61Sreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" 15245ae9d61Sreyk "FFFFFFFFFFFFFFFF", 15345ae9d61Sreyk "02" 15445ae9d61Sreyk }, 15545ae9d61Sreyk { GROUP_MODP, 17, 6144, 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 "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" 17745ae9d61Sreyk "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" 17845ae9d61Sreyk "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" 17945ae9d61Sreyk "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" 18045ae9d61Sreyk "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" 18145ae9d61Sreyk "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" 18245ae9d61Sreyk "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" 18345ae9d61Sreyk "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" 18445ae9d61Sreyk "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" 18545ae9d61Sreyk "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" 18645ae9d61Sreyk "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" 18745ae9d61Sreyk "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", 18845ae9d61Sreyk "02" 18945ae9d61Sreyk }, 19045ae9d61Sreyk { GROUP_MODP, 18, 8192, 19145ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 19245ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 19345ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 19445ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 19545ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 19645ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 19745ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 19845ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 19945ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 20045ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 20145ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 20245ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 20345ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 20445ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 20545ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 20645ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" 20745ae9d61Sreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" 20845ae9d61Sreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" 20945ae9d61Sreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" 21045ae9d61Sreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" 21145ae9d61Sreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" 21245ae9d61Sreyk "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" 21345ae9d61Sreyk "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" 21445ae9d61Sreyk "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" 21545ae9d61Sreyk "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" 21645ae9d61Sreyk "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" 21745ae9d61Sreyk "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" 21845ae9d61Sreyk "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" 21945ae9d61Sreyk "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" 22045ae9d61Sreyk "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" 22145ae9d61Sreyk "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" 22245ae9d61Sreyk "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" 22345ae9d61Sreyk "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" 22445ae9d61Sreyk "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" 22545ae9d61Sreyk "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" 22645ae9d61Sreyk "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" 22745ae9d61Sreyk "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" 22845ae9d61Sreyk "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" 22945ae9d61Sreyk "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" 23045ae9d61Sreyk "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" 23145ae9d61Sreyk "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" 23245ae9d61Sreyk "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" 23345ae9d61Sreyk "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 23445ae9d61Sreyk "02" 23545ae9d61Sreyk }, 236369beec1Sreyk { GROUP_ECP, 19, 256, NULL, NULL, NID_X9_62_prime256v1 }, 237369beec1Sreyk { GROUP_ECP, 20, 384, NULL, NULL, NID_secp384r1 }, 238369beec1Sreyk { GROUP_ECP, 21, 521, NULL, NULL, NID_secp521r1 }, 239369beec1Sreyk { GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 }, 240547eb84dSreyk { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 }, 241547eb84dSreyk { GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 }, 242547eb84dSreyk { GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 }, 243547eb84dSreyk { GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 }, 24445135ebcSreyk { GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 }, 245337280ecSsthen { GROUP_CURVE25519, 31, CURVE25519_SIZE * 8 } 24645ae9d61Sreyk }; 24745ae9d61Sreyk 24845ae9d61Sreyk void 24945ae9d61Sreyk group_init(void) 25045ae9d61Sreyk { 2510d5bf58dSreyk /* currently not used */ 25245ae9d61Sreyk return; 25345ae9d61Sreyk } 25445ae9d61Sreyk 25545ae9d61Sreyk void 25645ae9d61Sreyk group_free(struct group *group) 25745ae9d61Sreyk { 25845ae9d61Sreyk if (group == NULL) 25945ae9d61Sreyk return; 26045ae9d61Sreyk if (group->dh != NULL) 26145ae9d61Sreyk DH_free(group->dh); 26245ae9d61Sreyk if (group->ec != NULL) 26345ae9d61Sreyk EC_KEY_free(group->ec); 26429b4e2eaSderaadt freezero(group->curve25519, sizeof(struct curve25519_key)); 26545ae9d61Sreyk group->spec = NULL; 26664449014Sreyk free(group); 26745ae9d61Sreyk } 26845ae9d61Sreyk 26945ae9d61Sreyk struct group * 270d09d3a7dSreyk group_get(uint32_t id) 27145ae9d61Sreyk { 272e254d6eaSmikeb const struct group_id *p; 27345ae9d61Sreyk struct group *group; 27445ae9d61Sreyk 275e254d6eaSmikeb if ((p = group_getid(id)) == NULL) 27645ae9d61Sreyk return (NULL); 27745ae9d61Sreyk 27845ae9d61Sreyk if ((group = calloc(1, sizeof(*group))) == NULL) 27945ae9d61Sreyk return (NULL); 28045ae9d61Sreyk 28145ae9d61Sreyk group->id = id; 28245ae9d61Sreyk group->spec = p; 28345ae9d61Sreyk 28445ae9d61Sreyk switch (p->type) { 28545ae9d61Sreyk case GROUP_MODP: 28645ae9d61Sreyk group->init = modp_init; 28745ae9d61Sreyk group->getlen = modp_getlen; 28845ae9d61Sreyk group->exchange = modp_create_exchange; 28945ae9d61Sreyk group->shared = modp_create_shared; 29045ae9d61Sreyk break; 291369beec1Sreyk case GROUP_ECP: 29245ae9d61Sreyk group->init = ec_init; 29345ae9d61Sreyk group->getlen = ec_getlen; 294a6321d0fSpatrick group->secretlen = ec_secretlen; 29545ae9d61Sreyk group->exchange = ec_create_exchange; 29645ae9d61Sreyk group->shared = ec_create_shared; 29745ae9d61Sreyk break; 29845135ebcSreyk case GROUP_CURVE25519: 29945135ebcSreyk group->init = ec25519_init; 30045135ebcSreyk group->getlen = ec25519_getlen; 30145135ebcSreyk group->exchange = ec25519_create_exchange; 30245135ebcSreyk group->shared = ec25519_create_shared; 30345135ebcSreyk break; 30445ae9d61Sreyk default: 30545ae9d61Sreyk group_free(group); 30645ae9d61Sreyk return (NULL); 30745ae9d61Sreyk } 30845ae9d61Sreyk 30945ae9d61Sreyk if (dh_init(group) != 0) { 31045ae9d61Sreyk group_free(group); 31145ae9d61Sreyk return (NULL); 31245ae9d61Sreyk } 31345ae9d61Sreyk 31445ae9d61Sreyk return (group); 31545ae9d61Sreyk } 31645ae9d61Sreyk 317e254d6eaSmikeb const struct group_id * 318e254d6eaSmikeb group_getid(uint32_t id) 319e254d6eaSmikeb { 320e254d6eaSmikeb const struct group_id *p = NULL; 321e254d6eaSmikeb unsigned int i, items; 322e254d6eaSmikeb 323e254d6eaSmikeb items = sizeof(ike_groups) / sizeof(ike_groups[0]); 324e254d6eaSmikeb for (i = 0; i < items; i++) { 325e254d6eaSmikeb if (id == ike_groups[i].id) { 326e254d6eaSmikeb p = &ike_groups[i]; 327e254d6eaSmikeb break; 328e254d6eaSmikeb } 329e254d6eaSmikeb } 330e254d6eaSmikeb return (p); 331e254d6eaSmikeb } 332e254d6eaSmikeb 33345ae9d61Sreyk int 33445ae9d61Sreyk dh_init(struct group *group) 33545ae9d61Sreyk { 33645ae9d61Sreyk return (group->init(group)); 33745ae9d61Sreyk } 33845ae9d61Sreyk 33945ae9d61Sreyk int 34045ae9d61Sreyk dh_getlen(struct group *group) 34145ae9d61Sreyk { 34245ae9d61Sreyk return (group->getlen(group)); 34345ae9d61Sreyk } 34445ae9d61Sreyk 34545ae9d61Sreyk int 346a6321d0fSpatrick dh_secretlen(struct group *group) 347a6321d0fSpatrick { 348a6321d0fSpatrick if (group->secretlen) 349a6321d0fSpatrick return (group->secretlen(group)); 350a6321d0fSpatrick else 351a6321d0fSpatrick return (group->getlen(group)); 352a6321d0fSpatrick } 353a6321d0fSpatrick 354a6321d0fSpatrick int 355d09d3a7dSreyk dh_create_exchange(struct group *group, uint8_t *buf) 35645ae9d61Sreyk { 35745ae9d61Sreyk return (group->exchange(group, buf)); 35845ae9d61Sreyk } 35945ae9d61Sreyk 36045ae9d61Sreyk int 361d09d3a7dSreyk dh_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) 36245ae9d61Sreyk { 36345ae9d61Sreyk return (group->shared(group, secret, exchange)); 36445ae9d61Sreyk } 36545ae9d61Sreyk 36645ae9d61Sreyk int 36745ae9d61Sreyk modp_init(struct group *group) 36845ae9d61Sreyk { 36945ae9d61Sreyk DH *dh; 37045ae9d61Sreyk 37145ae9d61Sreyk if ((dh = DH_new()) == NULL) 37245ae9d61Sreyk return (-1); 3737d7b0856Sreyk group->dh = dh; 37445ae9d61Sreyk 37545ae9d61Sreyk if (!BN_hex2bn(&dh->p, group->spec->prime) || 37645ae9d61Sreyk !BN_hex2bn(&dh->g, group->spec->generator)) 37745ae9d61Sreyk return (-1); 37845ae9d61Sreyk 37945ae9d61Sreyk return (0); 38045ae9d61Sreyk } 38145ae9d61Sreyk 38245ae9d61Sreyk int 38345ae9d61Sreyk modp_getlen(struct group *group) 38445ae9d61Sreyk { 38545ae9d61Sreyk if (group->spec == NULL) 38645ae9d61Sreyk return (0); 38745ae9d61Sreyk return (roundup(group->spec->bits, 8) / 8); 38845ae9d61Sreyk } 38945ae9d61Sreyk 39045ae9d61Sreyk int 391d09d3a7dSreyk modp_create_exchange(struct group *group, uint8_t *buf) 39245ae9d61Sreyk { 39345ae9d61Sreyk DH *dh = group->dh; 39412abf43bSmikeb int len, ret; 39545ae9d61Sreyk 39645ae9d61Sreyk if (!DH_generate_key(dh)) 39745ae9d61Sreyk return (-1); 39812abf43bSmikeb ret = BN_bn2bin(dh->pub_key, buf); 39912abf43bSmikeb if (!ret) 40045ae9d61Sreyk return (-1); 40145ae9d61Sreyk 40212abf43bSmikeb len = dh_getlen(group); 40312abf43bSmikeb 40412abf43bSmikeb /* add zero padding */ 40512abf43bSmikeb if (ret < len) { 40612abf43bSmikeb bcopy(buf, buf + (len - ret), ret); 40712abf43bSmikeb bzero(buf, len - ret); 40812abf43bSmikeb } 40912abf43bSmikeb 4107d7b0856Sreyk return (0); 41145ae9d61Sreyk } 41245ae9d61Sreyk 41345ae9d61Sreyk int 414d09d3a7dSreyk modp_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) 41545ae9d61Sreyk { 41645ae9d61Sreyk BIGNUM *ex; 41712abf43bSmikeb int len, ret; 41845ae9d61Sreyk 41912abf43bSmikeb len = dh_getlen(group); 42012abf43bSmikeb 42112abf43bSmikeb if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL) 42245ae9d61Sreyk return (-1); 4237d7b0856Sreyk 4247d7b0856Sreyk ret = DH_compute_key(secret, ex, group->dh); 4257d7b0856Sreyk BN_clear_free(ex); 4262ffa77eaSjsg if (ret <= 0) 42745ae9d61Sreyk return (-1); 42845ae9d61Sreyk 42912abf43bSmikeb /* add zero padding */ 43012abf43bSmikeb if (ret < len) { 43112abf43bSmikeb bcopy(secret, secret + (len - ret), ret); 43212abf43bSmikeb bzero(secret, len - ret); 43312abf43bSmikeb } 43412abf43bSmikeb 4357d7b0856Sreyk return (0); 43645ae9d61Sreyk } 43745ae9d61Sreyk 43845ae9d61Sreyk int 43945ae9d61Sreyk ec_init(struct group *group) 44045ae9d61Sreyk { 44145ae9d61Sreyk if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL) 44245ae9d61Sreyk return (-1); 44345ae9d61Sreyk if (!EC_KEY_generate_key(group->ec)) 44445ae9d61Sreyk return (-1); 445c900656bSmarkus if (!EC_KEY_check_key(group->ec)) { 446c900656bSmarkus EC_KEY_free(group->ec); 447c900656bSmarkus return (-1); 448c900656bSmarkus } 44945ae9d61Sreyk return (0); 45045ae9d61Sreyk } 45145ae9d61Sreyk 45245ae9d61Sreyk int 45345ae9d61Sreyk ec_getlen(struct group *group) 45445ae9d61Sreyk { 45545ae9d61Sreyk if (group->spec == NULL) 45645ae9d61Sreyk return (0); 45745b72fd1Smikeb /* NB: Return value will always be even */ 45845ae9d61Sreyk return ((roundup(group->spec->bits, 8) * 2) / 8); 45945ae9d61Sreyk } 46045ae9d61Sreyk 461a6321d0fSpatrick /* 462a6321d0fSpatrick * Note that the shared secret only includes the x value: 463a6321d0fSpatrick * 464a6321d0fSpatrick * See RFC 5903, 7. ECP Key Exchange Data Formats: 465a6321d0fSpatrick * The Diffie-Hellman shared secret value consists of the x value of the 466a6321d0fSpatrick * Diffie-Hellman common value. 467a6321d0fSpatrick * See also RFC 5903, 9. Changes from RFC 4753. 468a6321d0fSpatrick */ 469a6321d0fSpatrick int 470a6321d0fSpatrick ec_secretlen(struct group *group) 471a6321d0fSpatrick { 472a6321d0fSpatrick return (ec_getlen(group) / 2); 473a6321d0fSpatrick } 474a6321d0fSpatrick 47545ae9d61Sreyk int 476d09d3a7dSreyk ec_create_exchange(struct group *group, uint8_t *buf) 47745ae9d61Sreyk { 4780d5bf58dSreyk size_t len; 4790d5bf58dSreyk 4800d5bf58dSreyk len = ec_getlen(group); 4810d5bf58dSreyk bzero(buf, len); 4820d5bf58dSreyk 48345ae9d61Sreyk return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec), 484a6321d0fSpatrick buf, len, EC_POINT2RAW_FULL)); 48545ae9d61Sreyk } 48645ae9d61Sreyk 48745ae9d61Sreyk int 488d09d3a7dSreyk ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) 48945ae9d61Sreyk { 49045ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 49145ae9d61Sreyk const BIGNUM *privkey; 492c900656bSmarkus EC_KEY *exkey = NULL; 49345ae9d61Sreyk EC_POINT *exchangep = NULL, *secretp = NULL; 49445ae9d61Sreyk int ret = -1; 49545ae9d61Sreyk 49645ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL || 49745ae9d61Sreyk (privkey = EC_KEY_get0_private_key(group->ec)) == NULL) 49845ae9d61Sreyk goto done; 49945ae9d61Sreyk 50045ae9d61Sreyk if ((exchangep = 50145ae9d61Sreyk ec_raw2point(group, exchange, ec_getlen(group))) == NULL) 50245ae9d61Sreyk goto done; 50345ae9d61Sreyk 504c900656bSmarkus if ((exkey = EC_KEY_new()) == NULL) 505c900656bSmarkus goto done; 506c900656bSmarkus if (!EC_KEY_set_group(exkey, ecgroup)) 507c900656bSmarkus goto done; 508c900656bSmarkus if (!EC_KEY_set_public_key(exkey, exchangep)) 509c900656bSmarkus goto done; 510c900656bSmarkus 511c900656bSmarkus /* validate exchangep */ 512c900656bSmarkus if (!EC_KEY_check_key(exkey)) 513c900656bSmarkus goto done; 514c900656bSmarkus 51545ae9d61Sreyk if ((secretp = EC_POINT_new(ecgroup)) == NULL) 51645ae9d61Sreyk goto done; 51745ae9d61Sreyk 51845ae9d61Sreyk if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL)) 51945ae9d61Sreyk goto done; 52045ae9d61Sreyk 521a6321d0fSpatrick ret = ec_point2raw(group, secretp, secret, ec_secretlen(group), 522a6321d0fSpatrick EC_POINT2RAW_XONLY); 52345ae9d61Sreyk 52445ae9d61Sreyk done: 525c900656bSmarkus if (exkey != NULL) 526c900656bSmarkus EC_KEY_free(exkey); 52745ae9d61Sreyk if (exchangep != NULL) 52845ae9d61Sreyk EC_POINT_clear_free(exchangep); 52945ae9d61Sreyk if (secretp != NULL) 53045ae9d61Sreyk EC_POINT_clear_free(secretp); 53145ae9d61Sreyk 53245ae9d61Sreyk return (ret); 53345ae9d61Sreyk } 53445ae9d61Sreyk 53545ae9d61Sreyk int 53645ae9d61Sreyk ec_point2raw(struct group *group, const EC_POINT *point, 537a6321d0fSpatrick uint8_t *buf, size_t len, int mode) 53845ae9d61Sreyk { 53945ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 54045ae9d61Sreyk BN_CTX *bnctx = NULL; 54145ae9d61Sreyk BIGNUM *x = NULL, *y = NULL; 54245ae9d61Sreyk int ret = -1; 54345b72fd1Smikeb size_t eclen, xlen, ylen; 54445ae9d61Sreyk off_t xoff, yoff; 54545ae9d61Sreyk 54645ae9d61Sreyk if ((bnctx = BN_CTX_new()) == NULL) 54745ae9d61Sreyk goto done; 54845ae9d61Sreyk BN_CTX_start(bnctx); 54945ae9d61Sreyk if ((x = BN_CTX_get(bnctx)) == NULL || 55045ae9d61Sreyk (y = BN_CTX_get(bnctx)) == NULL) 55145ae9d61Sreyk goto done; 55245ae9d61Sreyk 55345b72fd1Smikeb eclen = ec_getlen(group); 554a6321d0fSpatrick switch (mode) { 555a6321d0fSpatrick case EC_POINT2RAW_XONLY: 556a6321d0fSpatrick xlen = eclen / 2; 557a6321d0fSpatrick ylen = 0; 558a6321d0fSpatrick break; 559a6321d0fSpatrick case EC_POINT2RAW_FULL: 56045b72fd1Smikeb xlen = ylen = eclen / 2; 561a6321d0fSpatrick break; 562a6321d0fSpatrick default: 563a6321d0fSpatrick goto done; 564a6321d0fSpatrick } 565a6321d0fSpatrick if (len < xlen + ylen) 566a6321d0fSpatrick goto done; 56745b72fd1Smikeb 56845ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL) 56945ae9d61Sreyk goto done; 57045ae9d61Sreyk 57145ae9d61Sreyk if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) == 57245ae9d61Sreyk NID_X9_62_prime_field) { 57345ae9d61Sreyk if (!EC_POINT_get_affine_coordinates_GFp(ecgroup, 57445ae9d61Sreyk point, x, y, bnctx)) 57545ae9d61Sreyk goto done; 57645ae9d61Sreyk } else { 57745ae9d61Sreyk if (!EC_POINT_get_affine_coordinates_GF2m(ecgroup, 57845ae9d61Sreyk point, x, y, bnctx)) 57945ae9d61Sreyk goto done; 58045ae9d61Sreyk } 58145ae9d61Sreyk 58245ae9d61Sreyk xoff = xlen - BN_num_bytes(x); 58345b72fd1Smikeb bzero(buf, xoff); 58445ae9d61Sreyk if (!BN_bn2bin(x, buf + xoff)) 58545ae9d61Sreyk goto done; 58645ae9d61Sreyk 587a6321d0fSpatrick if (ylen > 0) { 58845ae9d61Sreyk yoff = (ylen - BN_num_bytes(y)) + xlen; 58945b72fd1Smikeb bzero(buf + xlen, yoff - xlen); 59045ae9d61Sreyk if (!BN_bn2bin(y, buf + yoff)) 59145ae9d61Sreyk goto done; 592a6321d0fSpatrick } 59345ae9d61Sreyk 59445ae9d61Sreyk ret = 0; 59545ae9d61Sreyk done: 596c900656bSmarkus /* Make sure to erase sensitive data */ 597c900656bSmarkus if (x != NULL) 598c900656bSmarkus BN_clear(x); 599c900656bSmarkus if (y != NULL) 600c900656bSmarkus BN_clear(y); 60145ae9d61Sreyk BN_CTX_end(bnctx); 60245ae9d61Sreyk BN_CTX_free(bnctx); 60345ae9d61Sreyk 60445ae9d61Sreyk return (ret); 60545ae9d61Sreyk } 60645ae9d61Sreyk 60745ae9d61Sreyk EC_POINT * 608d09d3a7dSreyk ec_raw2point(struct group *group, uint8_t *buf, size_t len) 60945ae9d61Sreyk { 61045ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 61145ae9d61Sreyk EC_POINT *point = NULL; 61245ae9d61Sreyk BN_CTX *bnctx = NULL; 61345ae9d61Sreyk BIGNUM *x = NULL, *y = NULL; 61445ae9d61Sreyk int ret = -1; 61545ae9d61Sreyk size_t eclen; 61645ae9d61Sreyk size_t xlen, ylen; 61745ae9d61Sreyk 61845ae9d61Sreyk if ((bnctx = BN_CTX_new()) == NULL) 61945ae9d61Sreyk goto done; 62045ae9d61Sreyk BN_CTX_start(bnctx); 62145ae9d61Sreyk if ((x = BN_CTX_get(bnctx)) == NULL || 62245ae9d61Sreyk (y = BN_CTX_get(bnctx)) == NULL) 62345ae9d61Sreyk goto done; 62445ae9d61Sreyk 62545ae9d61Sreyk eclen = ec_getlen(group); 62645ae9d61Sreyk if (len < eclen) 62745ae9d61Sreyk goto done; 62845ae9d61Sreyk xlen = ylen = eclen / 2; 62945ae9d61Sreyk if ((x = BN_bin2bn(buf, xlen, x)) == NULL || 63045ae9d61Sreyk (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL) 63145ae9d61Sreyk goto done; 63245ae9d61Sreyk 63345ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL) 63445ae9d61Sreyk goto done; 63545ae9d61Sreyk 63645ae9d61Sreyk if ((point = EC_POINT_new(ecgroup)) == NULL) 63745ae9d61Sreyk goto done; 63845ae9d61Sreyk 63945ae9d61Sreyk if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) == 64045ae9d61Sreyk NID_X9_62_prime_field) { 64145ae9d61Sreyk if (!EC_POINT_set_affine_coordinates_GFp(ecgroup, 64245ae9d61Sreyk point, x, y, bnctx)) 64345ae9d61Sreyk goto done; 64445ae9d61Sreyk } else { 64545ae9d61Sreyk if (!EC_POINT_set_affine_coordinates_GF2m(ecgroup, 64645ae9d61Sreyk point, x, y, bnctx)) 64745ae9d61Sreyk goto done; 64845ae9d61Sreyk } 64945ae9d61Sreyk 65045ae9d61Sreyk ret = 0; 65145ae9d61Sreyk done: 65245ae9d61Sreyk if (ret != 0 && point != NULL) 65345ae9d61Sreyk EC_POINT_clear_free(point); 654c900656bSmarkus /* Make sure to erase sensitive data */ 655c900656bSmarkus if (x != NULL) 656c900656bSmarkus BN_clear(x); 657c900656bSmarkus if (y != NULL) 658c900656bSmarkus BN_clear(y); 65945ae9d61Sreyk BN_CTX_end(bnctx); 66045ae9d61Sreyk BN_CTX_free(bnctx); 66145ae9d61Sreyk 66245ae9d61Sreyk return (point); 66345ae9d61Sreyk } 66445135ebcSreyk 66545135ebcSreyk int 66645135ebcSreyk ec25519_init(struct group *group) 66745135ebcSreyk { 668d09d3a7dSreyk static const uint8_t basepoint[CURVE25519_SIZE] = { 9 }; 66945135ebcSreyk struct curve25519_key *curve25519; 67045135ebcSreyk 67145135ebcSreyk if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL) 67245135ebcSreyk return (-1); 67345135ebcSreyk 67445135ebcSreyk group->curve25519 = curve25519; 67545135ebcSreyk 67645135ebcSreyk arc4random_buf(curve25519->secret, CURVE25519_SIZE); 67745135ebcSreyk crypto_scalarmult_curve25519(curve25519->public, 67845135ebcSreyk curve25519->secret, basepoint); 67945135ebcSreyk 68045135ebcSreyk return (0); 68145135ebcSreyk } 68245135ebcSreyk 68345135ebcSreyk int 68445135ebcSreyk ec25519_getlen(struct group *group) 68545135ebcSreyk { 68645135ebcSreyk if (group->spec == NULL) 68745135ebcSreyk return (0); 68845135ebcSreyk return (CURVE25519_SIZE); 68945135ebcSreyk } 69045135ebcSreyk 69145135ebcSreyk int 692d09d3a7dSreyk ec25519_create_exchange(struct group *group, uint8_t *buf) 69345135ebcSreyk { 69445135ebcSreyk struct curve25519_key *curve25519 = group->curve25519; 69545135ebcSreyk 69645135ebcSreyk memcpy(buf, curve25519->public, ec25519_getlen(group)); 69745135ebcSreyk return (0); 69845135ebcSreyk } 69945135ebcSreyk 70045135ebcSreyk int 701d09d3a7dSreyk ec25519_create_shared(struct group *group, uint8_t *shared, uint8_t *public) 70245135ebcSreyk { 70345135ebcSreyk struct curve25519_key *curve25519 = group->curve25519; 70445135ebcSreyk 70545135ebcSreyk crypto_scalarmult_curve25519(shared, curve25519->secret, public); 70645135ebcSreyk return (0); 70745135ebcSreyk } 708