1*a6321d0fSpatrick /* $OpenBSD: dh.c,v 1.21 2017/10/27 14:26:35 patrick 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 3845135ebcSreyk /* EC2N/ECP */ 3945ae9d61Sreyk int ec_init(struct group *); 4045ae9d61Sreyk int ec_getlen(struct group *); 41*a6321d0fSpatrick 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 45*a6321d0fSpatrick #define EC_POINT2RAW_FULL 0 46*a6321d0fSpatrick #define EC_POINT2RAW_XONLY 1 47*a6321d0fSpatrick 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 }, 86369beec1Sreyk { GROUP_EC2N, 3, 155, NULL, NULL, NID_ipsec3 }, 87369beec1Sreyk { GROUP_EC2N, 4, 185, NULL, NULL, NID_ipsec4 }, 8845ae9d61Sreyk { GROUP_MODP, 5, 1536, 8945ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 9045ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 9145ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 9245ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 9345ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 9445ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 9545ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 9645ae9d61Sreyk "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 9745ae9d61Sreyk "02" 9845ae9d61Sreyk }, 9945ae9d61Sreyk { GROUP_MODP, 14, 2048, 10045ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 10145ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 10245ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 10345ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 10445ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 10545ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 10645ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 10745ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 10845ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 10945ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 11045ae9d61Sreyk "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 11145ae9d61Sreyk "02" 11245ae9d61Sreyk }, 11345ae9d61Sreyk { GROUP_MODP, 15, 3072, 11445ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 11545ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 11645ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 11745ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 11845ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 11945ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 12045ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 12145ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 12245ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 12345ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 12445ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 12545ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 12645ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 12745ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 12845ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 12945ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 13045ae9d61Sreyk "02" 13145ae9d61Sreyk }, 13245ae9d61Sreyk { GROUP_MODP, 16, 4096, 13345ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 13445ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 13545ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 13645ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 13745ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 13845ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 13945ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 14045ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 14145ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 14245ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 14345ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 14445ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 14545ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 14645ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 14745ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 14845ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" 14945ae9d61Sreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" 15045ae9d61Sreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" 15145ae9d61Sreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" 15245ae9d61Sreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" 15345ae9d61Sreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" 15445ae9d61Sreyk "FFFFFFFFFFFFFFFF", 15545ae9d61Sreyk "02" 15645ae9d61Sreyk }, 15745ae9d61Sreyk { GROUP_MODP, 17, 6144, 15845ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 15945ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 16045ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 16145ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 16245ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 16345ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 16445ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 16545ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 16645ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 16745ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 16845ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 16945ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 17045ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 17145ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 17245ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 17345ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" 17445ae9d61Sreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" 17545ae9d61Sreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" 17645ae9d61Sreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" 17745ae9d61Sreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" 17845ae9d61Sreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" 17945ae9d61Sreyk "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" 18045ae9d61Sreyk "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" 18145ae9d61Sreyk "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" 18245ae9d61Sreyk "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" 18345ae9d61Sreyk "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" 18445ae9d61Sreyk "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" 18545ae9d61Sreyk "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" 18645ae9d61Sreyk "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" 18745ae9d61Sreyk "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" 18845ae9d61Sreyk "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" 18945ae9d61Sreyk "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", 19045ae9d61Sreyk "02" 19145ae9d61Sreyk }, 19245ae9d61Sreyk { GROUP_MODP, 18, 8192, 19345ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 19445ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 19545ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 19645ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 19745ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 19845ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 19945ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 20045ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 20145ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 20245ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 20345ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 20445ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 20545ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 20645ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 20745ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 20845ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" 20945ae9d61Sreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" 21045ae9d61Sreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" 21145ae9d61Sreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" 21245ae9d61Sreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" 21345ae9d61Sreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" 21445ae9d61Sreyk "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" 21545ae9d61Sreyk "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" 21645ae9d61Sreyk "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" 21745ae9d61Sreyk "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" 21845ae9d61Sreyk "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" 21945ae9d61Sreyk "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" 22045ae9d61Sreyk "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" 22145ae9d61Sreyk "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" 22245ae9d61Sreyk "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" 22345ae9d61Sreyk "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" 22445ae9d61Sreyk "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" 22545ae9d61Sreyk "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" 22645ae9d61Sreyk "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" 22745ae9d61Sreyk "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" 22845ae9d61Sreyk "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" 22945ae9d61Sreyk "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" 23045ae9d61Sreyk "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" 23145ae9d61Sreyk "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" 23245ae9d61Sreyk "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" 23345ae9d61Sreyk "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" 23445ae9d61Sreyk "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" 23545ae9d61Sreyk "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 23645ae9d61Sreyk "02" 23745ae9d61Sreyk }, 238369beec1Sreyk { GROUP_ECP, 19, 256, NULL, NULL, NID_X9_62_prime256v1 }, 239369beec1Sreyk { GROUP_ECP, 20, 384, NULL, NULL, NID_secp384r1 }, 240369beec1Sreyk { GROUP_ECP, 21, 521, NULL, NULL, NID_secp521r1 }, 241369beec1Sreyk { GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 }, 242547eb84dSreyk { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 }, 243547eb84dSreyk { GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 }, 244547eb84dSreyk { GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 }, 245547eb84dSreyk { GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 }, 24645135ebcSreyk { GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 }, 24745135ebcSreyk 24845135ebcSreyk /* "Private use" extensions */ 24945135ebcSreyk { GROUP_CURVE25519, 1034, CURVE25519_SIZE * 8 } 25045ae9d61Sreyk }; 25145ae9d61Sreyk 25245ae9d61Sreyk void 25345ae9d61Sreyk group_init(void) 25445ae9d61Sreyk { 2550d5bf58dSreyk /* currently not used */ 25645ae9d61Sreyk return; 25745ae9d61Sreyk } 25845ae9d61Sreyk 25945ae9d61Sreyk void 26045ae9d61Sreyk group_free(struct group *group) 26145ae9d61Sreyk { 26245ae9d61Sreyk if (group == NULL) 26345ae9d61Sreyk return; 26445ae9d61Sreyk if (group->dh != NULL) 26545ae9d61Sreyk DH_free(group->dh); 26645ae9d61Sreyk if (group->ec != NULL) 26745ae9d61Sreyk EC_KEY_free(group->ec); 26829b4e2eaSderaadt freezero(group->curve25519, sizeof(struct curve25519_key)); 26945ae9d61Sreyk group->spec = NULL; 27064449014Sreyk free(group); 27145ae9d61Sreyk } 27245ae9d61Sreyk 27345ae9d61Sreyk struct group * 274d09d3a7dSreyk group_get(uint32_t id) 27545ae9d61Sreyk { 276e254d6eaSmikeb const struct group_id *p; 27745ae9d61Sreyk struct group *group; 27845ae9d61Sreyk 279e254d6eaSmikeb if ((p = group_getid(id)) == NULL) 28045ae9d61Sreyk return (NULL); 28145ae9d61Sreyk 28245ae9d61Sreyk if ((group = calloc(1, sizeof(*group))) == NULL) 28345ae9d61Sreyk return (NULL); 28445ae9d61Sreyk 28545ae9d61Sreyk group->id = id; 28645ae9d61Sreyk group->spec = p; 28745ae9d61Sreyk 28845ae9d61Sreyk switch (p->type) { 28945ae9d61Sreyk case GROUP_MODP: 29045ae9d61Sreyk group->init = modp_init; 29145ae9d61Sreyk group->getlen = modp_getlen; 29245ae9d61Sreyk group->exchange = modp_create_exchange; 29345ae9d61Sreyk group->shared = modp_create_shared; 29445ae9d61Sreyk break; 295369beec1Sreyk case GROUP_EC2N: 296369beec1Sreyk case GROUP_ECP: 29745ae9d61Sreyk group->init = ec_init; 29845ae9d61Sreyk group->getlen = ec_getlen; 299*a6321d0fSpatrick group->secretlen = ec_secretlen; 30045ae9d61Sreyk group->exchange = ec_create_exchange; 30145ae9d61Sreyk group->shared = ec_create_shared; 30245ae9d61Sreyk break; 30345135ebcSreyk case GROUP_CURVE25519: 30445135ebcSreyk group->init = ec25519_init; 30545135ebcSreyk group->getlen = ec25519_getlen; 30645135ebcSreyk group->exchange = ec25519_create_exchange; 30745135ebcSreyk group->shared = ec25519_create_shared; 30845135ebcSreyk break; 30945ae9d61Sreyk default: 31045ae9d61Sreyk group_free(group); 31145ae9d61Sreyk return (NULL); 31245ae9d61Sreyk } 31345ae9d61Sreyk 31445ae9d61Sreyk if (dh_init(group) != 0) { 31545ae9d61Sreyk group_free(group); 31645ae9d61Sreyk return (NULL); 31745ae9d61Sreyk } 31845ae9d61Sreyk 31945ae9d61Sreyk return (group); 32045ae9d61Sreyk } 32145ae9d61Sreyk 322e254d6eaSmikeb const struct group_id * 323e254d6eaSmikeb group_getid(uint32_t id) 324e254d6eaSmikeb { 325e254d6eaSmikeb const struct group_id *p = NULL; 326e254d6eaSmikeb unsigned int i, items; 327e254d6eaSmikeb 328e254d6eaSmikeb items = sizeof(ike_groups) / sizeof(ike_groups[0]); 329e254d6eaSmikeb for (i = 0; i < items; i++) { 330e254d6eaSmikeb if (id == ike_groups[i].id) { 331e254d6eaSmikeb p = &ike_groups[i]; 332e254d6eaSmikeb break; 333e254d6eaSmikeb } 334e254d6eaSmikeb } 335e254d6eaSmikeb return (p); 336e254d6eaSmikeb } 337e254d6eaSmikeb 33845ae9d61Sreyk int 33945ae9d61Sreyk dh_init(struct group *group) 34045ae9d61Sreyk { 34145ae9d61Sreyk return (group->init(group)); 34245ae9d61Sreyk } 34345ae9d61Sreyk 34445ae9d61Sreyk int 34545ae9d61Sreyk dh_getlen(struct group *group) 34645ae9d61Sreyk { 34745ae9d61Sreyk return (group->getlen(group)); 34845ae9d61Sreyk } 34945ae9d61Sreyk 35045ae9d61Sreyk int 351*a6321d0fSpatrick dh_secretlen(struct group *group) 352*a6321d0fSpatrick { 353*a6321d0fSpatrick if (group->secretlen) 354*a6321d0fSpatrick return (group->secretlen(group)); 355*a6321d0fSpatrick else 356*a6321d0fSpatrick return (group->getlen(group)); 357*a6321d0fSpatrick } 358*a6321d0fSpatrick 359*a6321d0fSpatrick int 360d09d3a7dSreyk dh_create_exchange(struct group *group, uint8_t *buf) 36145ae9d61Sreyk { 36245ae9d61Sreyk return (group->exchange(group, buf)); 36345ae9d61Sreyk } 36445ae9d61Sreyk 36545ae9d61Sreyk int 366d09d3a7dSreyk dh_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) 36745ae9d61Sreyk { 36845ae9d61Sreyk return (group->shared(group, secret, exchange)); 36945ae9d61Sreyk } 37045ae9d61Sreyk 37145ae9d61Sreyk int 37245ae9d61Sreyk modp_init(struct group *group) 37345ae9d61Sreyk { 37445ae9d61Sreyk DH *dh; 37545ae9d61Sreyk 37645ae9d61Sreyk if ((dh = DH_new()) == NULL) 37745ae9d61Sreyk return (-1); 3787d7b0856Sreyk group->dh = dh; 37945ae9d61Sreyk 38045ae9d61Sreyk if (!BN_hex2bn(&dh->p, group->spec->prime) || 38145ae9d61Sreyk !BN_hex2bn(&dh->g, group->spec->generator)) 38245ae9d61Sreyk return (-1); 38345ae9d61Sreyk 38445ae9d61Sreyk return (0); 38545ae9d61Sreyk } 38645ae9d61Sreyk 38745ae9d61Sreyk int 38845ae9d61Sreyk modp_getlen(struct group *group) 38945ae9d61Sreyk { 39045ae9d61Sreyk if (group->spec == NULL) 39145ae9d61Sreyk return (0); 39245ae9d61Sreyk return (roundup(group->spec->bits, 8) / 8); 39345ae9d61Sreyk } 39445ae9d61Sreyk 39545ae9d61Sreyk int 396d09d3a7dSreyk modp_create_exchange(struct group *group, uint8_t *buf) 39745ae9d61Sreyk { 39845ae9d61Sreyk DH *dh = group->dh; 39912abf43bSmikeb int len, ret; 40045ae9d61Sreyk 40145ae9d61Sreyk if (!DH_generate_key(dh)) 40245ae9d61Sreyk return (-1); 40312abf43bSmikeb ret = BN_bn2bin(dh->pub_key, buf); 40412abf43bSmikeb if (!ret) 40545ae9d61Sreyk return (-1); 40645ae9d61Sreyk 40712abf43bSmikeb len = dh_getlen(group); 40812abf43bSmikeb 40912abf43bSmikeb /* add zero padding */ 41012abf43bSmikeb if (ret < len) { 41112abf43bSmikeb bcopy(buf, buf + (len - ret), ret); 41212abf43bSmikeb bzero(buf, len - ret); 41312abf43bSmikeb } 41412abf43bSmikeb 4157d7b0856Sreyk return (0); 41645ae9d61Sreyk } 41745ae9d61Sreyk 41845ae9d61Sreyk int 419d09d3a7dSreyk modp_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) 42045ae9d61Sreyk { 42145ae9d61Sreyk BIGNUM *ex; 42212abf43bSmikeb int len, ret; 42345ae9d61Sreyk 42412abf43bSmikeb len = dh_getlen(group); 42512abf43bSmikeb 42612abf43bSmikeb if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL) 42745ae9d61Sreyk return (-1); 4287d7b0856Sreyk 4297d7b0856Sreyk ret = DH_compute_key(secret, ex, group->dh); 4307d7b0856Sreyk BN_clear_free(ex); 4312ffa77eaSjsg if (ret <= 0) 43245ae9d61Sreyk return (-1); 43345ae9d61Sreyk 43412abf43bSmikeb /* add zero padding */ 43512abf43bSmikeb if (ret < len) { 43612abf43bSmikeb bcopy(secret, secret + (len - ret), ret); 43712abf43bSmikeb bzero(secret, len - ret); 43812abf43bSmikeb } 43912abf43bSmikeb 4407d7b0856Sreyk return (0); 44145ae9d61Sreyk } 44245ae9d61Sreyk 44345ae9d61Sreyk int 44445ae9d61Sreyk ec_init(struct group *group) 44545ae9d61Sreyk { 44645ae9d61Sreyk if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL) 44745ae9d61Sreyk return (-1); 44845ae9d61Sreyk if (!EC_KEY_generate_key(group->ec)) 44945ae9d61Sreyk return (-1); 450c900656bSmarkus if (!EC_KEY_check_key(group->ec)) { 451c900656bSmarkus EC_KEY_free(group->ec); 452c900656bSmarkus return (-1); 453c900656bSmarkus } 45445ae9d61Sreyk return (0); 45545ae9d61Sreyk } 45645ae9d61Sreyk 45745ae9d61Sreyk int 45845ae9d61Sreyk ec_getlen(struct group *group) 45945ae9d61Sreyk { 46045ae9d61Sreyk if (group->spec == NULL) 46145ae9d61Sreyk return (0); 46245b72fd1Smikeb /* NB: Return value will always be even */ 46345ae9d61Sreyk return ((roundup(group->spec->bits, 8) * 2) / 8); 46445ae9d61Sreyk } 46545ae9d61Sreyk 466*a6321d0fSpatrick /* 467*a6321d0fSpatrick * Note that the shared secret only includes the x value: 468*a6321d0fSpatrick * 469*a6321d0fSpatrick * See RFC 5903, 7. ECP Key Exchange Data Formats: 470*a6321d0fSpatrick * The Diffie-Hellman shared secret value consists of the x value of the 471*a6321d0fSpatrick * Diffie-Hellman common value. 472*a6321d0fSpatrick * See also RFC 5903, 9. Changes from RFC 4753. 473*a6321d0fSpatrick */ 474*a6321d0fSpatrick int 475*a6321d0fSpatrick ec_secretlen(struct group *group) 476*a6321d0fSpatrick { 477*a6321d0fSpatrick return (ec_getlen(group) / 2); 478*a6321d0fSpatrick } 479*a6321d0fSpatrick 48045ae9d61Sreyk int 481d09d3a7dSreyk ec_create_exchange(struct group *group, uint8_t *buf) 48245ae9d61Sreyk { 4830d5bf58dSreyk size_t len; 4840d5bf58dSreyk 4850d5bf58dSreyk len = ec_getlen(group); 4860d5bf58dSreyk bzero(buf, len); 4870d5bf58dSreyk 48845ae9d61Sreyk return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec), 489*a6321d0fSpatrick buf, len, EC_POINT2RAW_FULL)); 49045ae9d61Sreyk } 49145ae9d61Sreyk 49245ae9d61Sreyk int 493d09d3a7dSreyk ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) 49445ae9d61Sreyk { 49545ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 49645ae9d61Sreyk const BIGNUM *privkey; 497c900656bSmarkus EC_KEY *exkey = NULL; 49845ae9d61Sreyk EC_POINT *exchangep = NULL, *secretp = NULL; 49945ae9d61Sreyk int ret = -1; 50045ae9d61Sreyk 50145ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL || 50245ae9d61Sreyk (privkey = EC_KEY_get0_private_key(group->ec)) == NULL) 50345ae9d61Sreyk goto done; 50445ae9d61Sreyk 50545ae9d61Sreyk if ((exchangep = 50645ae9d61Sreyk ec_raw2point(group, exchange, ec_getlen(group))) == NULL) 50745ae9d61Sreyk goto done; 50845ae9d61Sreyk 509c900656bSmarkus if ((exkey = EC_KEY_new()) == NULL) 510c900656bSmarkus goto done; 511c900656bSmarkus if (!EC_KEY_set_group(exkey, ecgroup)) 512c900656bSmarkus goto done; 513c900656bSmarkus if (!EC_KEY_set_public_key(exkey, exchangep)) 514c900656bSmarkus goto done; 515c900656bSmarkus 516c900656bSmarkus /* validate exchangep */ 517c900656bSmarkus if (!EC_KEY_check_key(exkey)) 518c900656bSmarkus goto done; 519c900656bSmarkus 52045ae9d61Sreyk if ((secretp = EC_POINT_new(ecgroup)) == NULL) 52145ae9d61Sreyk goto done; 52245ae9d61Sreyk 52345ae9d61Sreyk if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL)) 52445ae9d61Sreyk goto done; 52545ae9d61Sreyk 526*a6321d0fSpatrick ret = ec_point2raw(group, secretp, secret, ec_secretlen(group), 527*a6321d0fSpatrick EC_POINT2RAW_XONLY); 52845ae9d61Sreyk 52945ae9d61Sreyk done: 530c900656bSmarkus if (exkey != NULL) 531c900656bSmarkus EC_KEY_free(exkey); 53245ae9d61Sreyk if (exchangep != NULL) 53345ae9d61Sreyk EC_POINT_clear_free(exchangep); 53445ae9d61Sreyk if (secretp != NULL) 53545ae9d61Sreyk EC_POINT_clear_free(secretp); 53645ae9d61Sreyk 53745ae9d61Sreyk return (ret); 53845ae9d61Sreyk } 53945ae9d61Sreyk 54045ae9d61Sreyk int 54145ae9d61Sreyk ec_point2raw(struct group *group, const EC_POINT *point, 542*a6321d0fSpatrick uint8_t *buf, size_t len, int mode) 54345ae9d61Sreyk { 54445ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 54545ae9d61Sreyk BN_CTX *bnctx = NULL; 54645ae9d61Sreyk BIGNUM *x = NULL, *y = NULL; 54745ae9d61Sreyk int ret = -1; 54845b72fd1Smikeb size_t eclen, xlen, ylen; 54945ae9d61Sreyk off_t xoff, yoff; 55045ae9d61Sreyk 55145ae9d61Sreyk if ((bnctx = BN_CTX_new()) == NULL) 55245ae9d61Sreyk goto done; 55345ae9d61Sreyk BN_CTX_start(bnctx); 55445ae9d61Sreyk if ((x = BN_CTX_get(bnctx)) == NULL || 55545ae9d61Sreyk (y = BN_CTX_get(bnctx)) == NULL) 55645ae9d61Sreyk goto done; 55745ae9d61Sreyk 55845b72fd1Smikeb eclen = ec_getlen(group); 559*a6321d0fSpatrick switch (mode) { 560*a6321d0fSpatrick case EC_POINT2RAW_XONLY: 561*a6321d0fSpatrick xlen = eclen / 2; 562*a6321d0fSpatrick ylen = 0; 563*a6321d0fSpatrick break; 564*a6321d0fSpatrick case EC_POINT2RAW_FULL: 56545b72fd1Smikeb xlen = ylen = eclen / 2; 566*a6321d0fSpatrick break; 567*a6321d0fSpatrick default: 568*a6321d0fSpatrick goto done; 569*a6321d0fSpatrick } 570*a6321d0fSpatrick if (len < xlen + ylen) 571*a6321d0fSpatrick goto done; 57245b72fd1Smikeb 57345ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL) 57445ae9d61Sreyk goto done; 57545ae9d61Sreyk 57645ae9d61Sreyk if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) == 57745ae9d61Sreyk NID_X9_62_prime_field) { 57845ae9d61Sreyk if (!EC_POINT_get_affine_coordinates_GFp(ecgroup, 57945ae9d61Sreyk point, x, y, bnctx)) 58045ae9d61Sreyk goto done; 58145ae9d61Sreyk } else { 58245ae9d61Sreyk if (!EC_POINT_get_affine_coordinates_GF2m(ecgroup, 58345ae9d61Sreyk point, x, y, bnctx)) 58445ae9d61Sreyk goto done; 58545ae9d61Sreyk } 58645ae9d61Sreyk 58745ae9d61Sreyk xoff = xlen - BN_num_bytes(x); 58845b72fd1Smikeb bzero(buf, xoff); 58945ae9d61Sreyk if (!BN_bn2bin(x, buf + xoff)) 59045ae9d61Sreyk goto done; 59145ae9d61Sreyk 592*a6321d0fSpatrick if (ylen > 0) { 59345ae9d61Sreyk yoff = (ylen - BN_num_bytes(y)) + xlen; 59445b72fd1Smikeb bzero(buf + xlen, yoff - xlen); 59545ae9d61Sreyk if (!BN_bn2bin(y, buf + yoff)) 59645ae9d61Sreyk goto done; 597*a6321d0fSpatrick } 59845ae9d61Sreyk 59945ae9d61Sreyk ret = 0; 60045ae9d61Sreyk done: 601c900656bSmarkus /* Make sure to erase sensitive data */ 602c900656bSmarkus if (x != NULL) 603c900656bSmarkus BN_clear(x); 604c900656bSmarkus if (y != NULL) 605c900656bSmarkus BN_clear(y); 60645ae9d61Sreyk BN_CTX_end(bnctx); 60745ae9d61Sreyk BN_CTX_free(bnctx); 60845ae9d61Sreyk 60945ae9d61Sreyk return (ret); 61045ae9d61Sreyk } 61145ae9d61Sreyk 61245ae9d61Sreyk EC_POINT * 613d09d3a7dSreyk ec_raw2point(struct group *group, uint8_t *buf, size_t len) 61445ae9d61Sreyk { 61545ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 61645ae9d61Sreyk EC_POINT *point = NULL; 61745ae9d61Sreyk BN_CTX *bnctx = NULL; 61845ae9d61Sreyk BIGNUM *x = NULL, *y = NULL; 61945ae9d61Sreyk int ret = -1; 62045ae9d61Sreyk size_t eclen; 62145ae9d61Sreyk size_t xlen, ylen; 62245ae9d61Sreyk 62345ae9d61Sreyk if ((bnctx = BN_CTX_new()) == NULL) 62445ae9d61Sreyk goto done; 62545ae9d61Sreyk BN_CTX_start(bnctx); 62645ae9d61Sreyk if ((x = BN_CTX_get(bnctx)) == NULL || 62745ae9d61Sreyk (y = BN_CTX_get(bnctx)) == NULL) 62845ae9d61Sreyk goto done; 62945ae9d61Sreyk 63045ae9d61Sreyk eclen = ec_getlen(group); 63145ae9d61Sreyk if (len < eclen) 63245ae9d61Sreyk goto done; 63345ae9d61Sreyk xlen = ylen = eclen / 2; 63445ae9d61Sreyk if ((x = BN_bin2bn(buf, xlen, x)) == NULL || 63545ae9d61Sreyk (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL) 63645ae9d61Sreyk goto done; 63745ae9d61Sreyk 63845ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL) 63945ae9d61Sreyk goto done; 64045ae9d61Sreyk 64145ae9d61Sreyk if ((point = EC_POINT_new(ecgroup)) == NULL) 64245ae9d61Sreyk goto done; 64345ae9d61Sreyk 64445ae9d61Sreyk if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) == 64545ae9d61Sreyk NID_X9_62_prime_field) { 64645ae9d61Sreyk if (!EC_POINT_set_affine_coordinates_GFp(ecgroup, 64745ae9d61Sreyk point, x, y, bnctx)) 64845ae9d61Sreyk goto done; 64945ae9d61Sreyk } else { 65045ae9d61Sreyk if (!EC_POINT_set_affine_coordinates_GF2m(ecgroup, 65145ae9d61Sreyk point, x, y, bnctx)) 65245ae9d61Sreyk goto done; 65345ae9d61Sreyk } 65445ae9d61Sreyk 65545ae9d61Sreyk ret = 0; 65645ae9d61Sreyk done: 65745ae9d61Sreyk if (ret != 0 && point != NULL) 65845ae9d61Sreyk EC_POINT_clear_free(point); 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 (point); 66845ae9d61Sreyk } 66945135ebcSreyk 67045135ebcSreyk int 67145135ebcSreyk ec25519_init(struct group *group) 67245135ebcSreyk { 673d09d3a7dSreyk static const uint8_t basepoint[CURVE25519_SIZE] = { 9 }; 67445135ebcSreyk struct curve25519_key *curve25519; 67545135ebcSreyk 67645135ebcSreyk if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL) 67745135ebcSreyk return (-1); 67845135ebcSreyk 67945135ebcSreyk group->curve25519 = curve25519; 68045135ebcSreyk 68145135ebcSreyk arc4random_buf(curve25519->secret, CURVE25519_SIZE); 68245135ebcSreyk crypto_scalarmult_curve25519(curve25519->public, 68345135ebcSreyk curve25519->secret, basepoint); 68445135ebcSreyk 68545135ebcSreyk return (0); 68645135ebcSreyk } 68745135ebcSreyk 68845135ebcSreyk int 68945135ebcSreyk ec25519_getlen(struct group *group) 69045135ebcSreyk { 69145135ebcSreyk if (group->spec == NULL) 69245135ebcSreyk return (0); 69345135ebcSreyk return (CURVE25519_SIZE); 69445135ebcSreyk } 69545135ebcSreyk 69645135ebcSreyk int 697d09d3a7dSreyk ec25519_create_exchange(struct group *group, uint8_t *buf) 69845135ebcSreyk { 69945135ebcSreyk struct curve25519_key *curve25519 = group->curve25519; 70045135ebcSreyk 70145135ebcSreyk memcpy(buf, curve25519->public, ec25519_getlen(group)); 70245135ebcSreyk return (0); 70345135ebcSreyk } 70445135ebcSreyk 70545135ebcSreyk int 706d09d3a7dSreyk ec25519_create_shared(struct group *group, uint8_t *shared, uint8_t *public) 70745135ebcSreyk { 70845135ebcSreyk struct curve25519_key *curve25519 = group->curve25519; 70945135ebcSreyk 71045135ebcSreyk crypto_scalarmult_curve25519(shared, curve25519->secret, public); 71145135ebcSreyk return (0); 71245135ebcSreyk } 713