1*29b4e2eaSderaadt /* $OpenBSD: dh.c,v 1.20 2017/05/21 02:37:52 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 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 *); 41d09d3a7dSreyk int ec_create_exchange(struct group *, uint8_t *); 42d09d3a7dSreyk int ec_create_shared(struct group *, uint8_t *, uint8_t *); 4345ae9d61Sreyk 44d09d3a7dSreyk int ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t); 4545ae9d61Sreyk EC_POINT * 46d09d3a7dSreyk ec_raw2point(struct group *, uint8_t *, size_t); 4745ae9d61Sreyk 4845135ebcSreyk /* curve25519 */ 4945135ebcSreyk int ec25519_init(struct group *); 5045135ebcSreyk int ec25519_getlen(struct group *); 51d09d3a7dSreyk int ec25519_create_exchange(struct group *, uint8_t *); 52d09d3a7dSreyk int ec25519_create_shared(struct group *, uint8_t *, uint8_t *); 5345135ebcSreyk 5445135ebcSreyk #define CURVE25519_SIZE 32 /* 256 bits */ 5545135ebcSreyk struct curve25519_key { 56d09d3a7dSreyk uint8_t secret[CURVE25519_SIZE]; 57d09d3a7dSreyk uint8_t public[CURVE25519_SIZE]; 5845135ebcSreyk }; 59d09d3a7dSreyk extern int crypto_scalarmult_curve25519(unsigned char a[CURVE25519_SIZE], 60d09d3a7dSreyk const unsigned char b[CURVE25519_SIZE], 61d09d3a7dSreyk const unsigned char c[CURVE25519_SIZE]) 6245135ebcSreyk __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) 6345135ebcSreyk __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))) 6445135ebcSreyk __attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE))); 6545135ebcSreyk 66e254d6eaSmikeb const struct group_id ike_groups[] = { 6745ae9d61Sreyk { GROUP_MODP, 1, 768, 6845ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 6945ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 7045ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 7145ae9d61Sreyk "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 7245ae9d61Sreyk "02" 7345ae9d61Sreyk }, 7445ae9d61Sreyk { GROUP_MODP, 2, 1024, 7545ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 7645ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 7745ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 7845ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 7945ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" 8045ae9d61Sreyk "FFFFFFFFFFFFFFFF", 8145ae9d61Sreyk "02" 8245ae9d61Sreyk }, 83369beec1Sreyk { GROUP_EC2N, 3, 155, NULL, NULL, NID_ipsec3 }, 84369beec1Sreyk { GROUP_EC2N, 4, 185, NULL, NULL, NID_ipsec4 }, 8545ae9d61Sreyk { GROUP_MODP, 5, 1536, 8645ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 8745ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 8845ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 8945ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 9045ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 9145ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 9245ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 9345ae9d61Sreyk "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 9445ae9d61Sreyk "02" 9545ae9d61Sreyk }, 9645ae9d61Sreyk { GROUP_MODP, 14, 2048, 9745ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 9845ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 9945ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 10045ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 10145ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 10245ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 10345ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 10445ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 10545ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 10645ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 10745ae9d61Sreyk "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 10845ae9d61Sreyk "02" 10945ae9d61Sreyk }, 11045ae9d61Sreyk { GROUP_MODP, 15, 3072, 11145ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 11245ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 11345ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 11445ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 11545ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 11645ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 11745ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 11845ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 11945ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 12045ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 12145ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 12245ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 12345ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 12445ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 12545ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 12645ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 12745ae9d61Sreyk "02" 12845ae9d61Sreyk }, 12945ae9d61Sreyk { GROUP_MODP, 16, 4096, 13045ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 13145ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 13245ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 13345ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 13445ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 13545ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 13645ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 13745ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 13845ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 13945ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 14045ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 14145ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 14245ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 14345ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 14445ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 14545ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" 14645ae9d61Sreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" 14745ae9d61Sreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" 14845ae9d61Sreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" 14945ae9d61Sreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" 15045ae9d61Sreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" 15145ae9d61Sreyk "FFFFFFFFFFFFFFFF", 15245ae9d61Sreyk "02" 15345ae9d61Sreyk }, 15445ae9d61Sreyk { GROUP_MODP, 17, 6144, 15545ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 15645ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 15745ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 15845ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 15945ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 16045ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 16145ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 16245ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 16345ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 16445ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 16545ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 16645ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 16745ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 16845ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 16945ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 17045ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" 17145ae9d61Sreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" 17245ae9d61Sreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" 17345ae9d61Sreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" 17445ae9d61Sreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" 17545ae9d61Sreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" 17645ae9d61Sreyk "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" 17745ae9d61Sreyk "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" 17845ae9d61Sreyk "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" 17945ae9d61Sreyk "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" 18045ae9d61Sreyk "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" 18145ae9d61Sreyk "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" 18245ae9d61Sreyk "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" 18345ae9d61Sreyk "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" 18445ae9d61Sreyk "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" 18545ae9d61Sreyk "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" 18645ae9d61Sreyk "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", 18745ae9d61Sreyk "02" 18845ae9d61Sreyk }, 18945ae9d61Sreyk { GROUP_MODP, 18, 8192, 19045ae9d61Sreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" 19145ae9d61Sreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" 19245ae9d61Sreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" 19345ae9d61Sreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" 19445ae9d61Sreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" 19545ae9d61Sreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" 19645ae9d61Sreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D" 19745ae9d61Sreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" 19845ae9d61Sreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" 19945ae9d61Sreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" 20045ae9d61Sreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" 20145ae9d61Sreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" 20245ae9d61Sreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" 20345ae9d61Sreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" 20445ae9d61Sreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" 20545ae9d61Sreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" 20645ae9d61Sreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" 20745ae9d61Sreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" 20845ae9d61Sreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" 20945ae9d61Sreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" 21045ae9d61Sreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" 21145ae9d61Sreyk "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" 21245ae9d61Sreyk "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" 21345ae9d61Sreyk "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" 21445ae9d61Sreyk "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" 21545ae9d61Sreyk "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" 21645ae9d61Sreyk "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" 21745ae9d61Sreyk "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" 21845ae9d61Sreyk "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" 21945ae9d61Sreyk "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" 22045ae9d61Sreyk "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" 22145ae9d61Sreyk "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" 22245ae9d61Sreyk "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" 22345ae9d61Sreyk "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" 22445ae9d61Sreyk "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" 22545ae9d61Sreyk "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" 22645ae9d61Sreyk "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" 22745ae9d61Sreyk "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" 22845ae9d61Sreyk "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" 22945ae9d61Sreyk "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" 23045ae9d61Sreyk "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" 23145ae9d61Sreyk "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" 23245ae9d61Sreyk "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 23345ae9d61Sreyk "02" 23445ae9d61Sreyk }, 235369beec1Sreyk { GROUP_ECP, 19, 256, NULL, NULL, NID_X9_62_prime256v1 }, 236369beec1Sreyk { GROUP_ECP, 20, 384, NULL, NULL, NID_secp384r1 }, 237369beec1Sreyk { GROUP_ECP, 21, 521, NULL, NULL, NID_secp521r1 }, 238369beec1Sreyk { GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 }, 239547eb84dSreyk { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 }, 240547eb84dSreyk { GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 }, 241547eb84dSreyk { GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 }, 242547eb84dSreyk { GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 }, 24345135ebcSreyk { GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 }, 24445135ebcSreyk 24545135ebcSreyk /* "Private use" extensions */ 24645135ebcSreyk { GROUP_CURVE25519, 1034, CURVE25519_SIZE * 8 } 24745ae9d61Sreyk }; 24845ae9d61Sreyk 24945ae9d61Sreyk void 25045ae9d61Sreyk group_init(void) 25145ae9d61Sreyk { 2520d5bf58dSreyk /* currently not used */ 25345ae9d61Sreyk return; 25445ae9d61Sreyk } 25545ae9d61Sreyk 25645ae9d61Sreyk void 25745ae9d61Sreyk group_free(struct group *group) 25845ae9d61Sreyk { 25945ae9d61Sreyk if (group == NULL) 26045ae9d61Sreyk return; 26145ae9d61Sreyk if (group->dh != NULL) 26245ae9d61Sreyk DH_free(group->dh); 26345ae9d61Sreyk if (group->ec != NULL) 26445ae9d61Sreyk EC_KEY_free(group->ec); 265*29b4e2eaSderaadt freezero(group->curve25519, sizeof(struct curve25519_key)); 26645ae9d61Sreyk group->spec = NULL; 26764449014Sreyk free(group); 26845ae9d61Sreyk } 26945ae9d61Sreyk 27045ae9d61Sreyk struct group * 271d09d3a7dSreyk group_get(uint32_t id) 27245ae9d61Sreyk { 273e254d6eaSmikeb const struct group_id *p; 27445ae9d61Sreyk struct group *group; 27545ae9d61Sreyk 276e254d6eaSmikeb if ((p = group_getid(id)) == NULL) 27745ae9d61Sreyk return (NULL); 27845ae9d61Sreyk 27945ae9d61Sreyk if ((group = calloc(1, sizeof(*group))) == NULL) 28045ae9d61Sreyk return (NULL); 28145ae9d61Sreyk 28245ae9d61Sreyk group->id = id; 28345ae9d61Sreyk group->spec = p; 28445ae9d61Sreyk 28545ae9d61Sreyk switch (p->type) { 28645ae9d61Sreyk case GROUP_MODP: 28745ae9d61Sreyk group->init = modp_init; 28845ae9d61Sreyk group->getlen = modp_getlen; 28945ae9d61Sreyk group->exchange = modp_create_exchange; 29045ae9d61Sreyk group->shared = modp_create_shared; 29145ae9d61Sreyk break; 292369beec1Sreyk case GROUP_EC2N: 293369beec1Sreyk case GROUP_ECP: 29445ae9d61Sreyk group->init = ec_init; 29545ae9d61Sreyk group->getlen = ec_getlen; 29645ae9d61Sreyk group->exchange = ec_create_exchange; 29745ae9d61Sreyk group->shared = ec_create_shared; 29845ae9d61Sreyk break; 29945135ebcSreyk case GROUP_CURVE25519: 30045135ebcSreyk group->init = ec25519_init; 30145135ebcSreyk group->getlen = ec25519_getlen; 30245135ebcSreyk group->exchange = ec25519_create_exchange; 30345135ebcSreyk group->shared = ec25519_create_shared; 30445135ebcSreyk break; 30545ae9d61Sreyk default: 30645ae9d61Sreyk group_free(group); 30745ae9d61Sreyk return (NULL); 30845ae9d61Sreyk } 30945ae9d61Sreyk 31045ae9d61Sreyk if (dh_init(group) != 0) { 31145ae9d61Sreyk group_free(group); 31245ae9d61Sreyk return (NULL); 31345ae9d61Sreyk } 31445ae9d61Sreyk 31545ae9d61Sreyk return (group); 31645ae9d61Sreyk } 31745ae9d61Sreyk 318e254d6eaSmikeb const struct group_id * 319e254d6eaSmikeb group_getid(uint32_t id) 320e254d6eaSmikeb { 321e254d6eaSmikeb const struct group_id *p = NULL; 322e254d6eaSmikeb unsigned int i, items; 323e254d6eaSmikeb 324e254d6eaSmikeb items = sizeof(ike_groups) / sizeof(ike_groups[0]); 325e254d6eaSmikeb for (i = 0; i < items; i++) { 326e254d6eaSmikeb if (id == ike_groups[i].id) { 327e254d6eaSmikeb p = &ike_groups[i]; 328e254d6eaSmikeb break; 329e254d6eaSmikeb } 330e254d6eaSmikeb } 331e254d6eaSmikeb return (p); 332e254d6eaSmikeb } 333e254d6eaSmikeb 33445ae9d61Sreyk int 33545ae9d61Sreyk dh_init(struct group *group) 33645ae9d61Sreyk { 33745ae9d61Sreyk return (group->init(group)); 33845ae9d61Sreyk } 33945ae9d61Sreyk 34045ae9d61Sreyk int 34145ae9d61Sreyk dh_getlen(struct group *group) 34245ae9d61Sreyk { 34345ae9d61Sreyk return (group->getlen(group)); 34445ae9d61Sreyk } 34545ae9d61Sreyk 34645ae9d61Sreyk int 347d09d3a7dSreyk dh_create_exchange(struct group *group, uint8_t *buf) 34845ae9d61Sreyk { 34945ae9d61Sreyk return (group->exchange(group, buf)); 35045ae9d61Sreyk } 35145ae9d61Sreyk 35245ae9d61Sreyk int 353d09d3a7dSreyk dh_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) 35445ae9d61Sreyk { 35545ae9d61Sreyk return (group->shared(group, secret, exchange)); 35645ae9d61Sreyk } 35745ae9d61Sreyk 35845ae9d61Sreyk int 35945ae9d61Sreyk modp_init(struct group *group) 36045ae9d61Sreyk { 36145ae9d61Sreyk DH *dh; 36245ae9d61Sreyk 36345ae9d61Sreyk if ((dh = DH_new()) == NULL) 36445ae9d61Sreyk return (-1); 3657d7b0856Sreyk group->dh = dh; 36645ae9d61Sreyk 36745ae9d61Sreyk if (!BN_hex2bn(&dh->p, group->spec->prime) || 36845ae9d61Sreyk !BN_hex2bn(&dh->g, group->spec->generator)) 36945ae9d61Sreyk return (-1); 37045ae9d61Sreyk 37145ae9d61Sreyk return (0); 37245ae9d61Sreyk } 37345ae9d61Sreyk 37445ae9d61Sreyk int 37545ae9d61Sreyk modp_getlen(struct group *group) 37645ae9d61Sreyk { 37745ae9d61Sreyk if (group->spec == NULL) 37845ae9d61Sreyk return (0); 37945ae9d61Sreyk return (roundup(group->spec->bits, 8) / 8); 38045ae9d61Sreyk } 38145ae9d61Sreyk 38245ae9d61Sreyk int 383d09d3a7dSreyk modp_create_exchange(struct group *group, uint8_t *buf) 38445ae9d61Sreyk { 38545ae9d61Sreyk DH *dh = group->dh; 38612abf43bSmikeb int len, ret; 38745ae9d61Sreyk 38845ae9d61Sreyk if (!DH_generate_key(dh)) 38945ae9d61Sreyk return (-1); 39012abf43bSmikeb ret = BN_bn2bin(dh->pub_key, buf); 39112abf43bSmikeb if (!ret) 39245ae9d61Sreyk return (-1); 39345ae9d61Sreyk 39412abf43bSmikeb len = dh_getlen(group); 39512abf43bSmikeb 39612abf43bSmikeb /* add zero padding */ 39712abf43bSmikeb if (ret < len) { 39812abf43bSmikeb bcopy(buf, buf + (len - ret), ret); 39912abf43bSmikeb bzero(buf, len - ret); 40012abf43bSmikeb } 40112abf43bSmikeb 4027d7b0856Sreyk return (0); 40345ae9d61Sreyk } 40445ae9d61Sreyk 40545ae9d61Sreyk int 406d09d3a7dSreyk modp_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) 40745ae9d61Sreyk { 40845ae9d61Sreyk BIGNUM *ex; 40912abf43bSmikeb int len, ret; 41045ae9d61Sreyk 41112abf43bSmikeb len = dh_getlen(group); 41212abf43bSmikeb 41312abf43bSmikeb if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL) 41445ae9d61Sreyk return (-1); 4157d7b0856Sreyk 4167d7b0856Sreyk ret = DH_compute_key(secret, ex, group->dh); 4177d7b0856Sreyk BN_clear_free(ex); 4182ffa77eaSjsg if (ret <= 0) 41945ae9d61Sreyk return (-1); 42045ae9d61Sreyk 42112abf43bSmikeb /* add zero padding */ 42212abf43bSmikeb if (ret < len) { 42312abf43bSmikeb bcopy(secret, secret + (len - ret), ret); 42412abf43bSmikeb bzero(secret, len - ret); 42512abf43bSmikeb } 42612abf43bSmikeb 4277d7b0856Sreyk return (0); 42845ae9d61Sreyk } 42945ae9d61Sreyk 43045ae9d61Sreyk int 43145ae9d61Sreyk ec_init(struct group *group) 43245ae9d61Sreyk { 43345ae9d61Sreyk if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL) 43445ae9d61Sreyk return (-1); 43545ae9d61Sreyk if (!EC_KEY_generate_key(group->ec)) 43645ae9d61Sreyk return (-1); 437c900656bSmarkus if (!EC_KEY_check_key(group->ec)) { 438c900656bSmarkus EC_KEY_free(group->ec); 439c900656bSmarkus return (-1); 440c900656bSmarkus } 44145ae9d61Sreyk return (0); 44245ae9d61Sreyk } 44345ae9d61Sreyk 44445ae9d61Sreyk int 44545ae9d61Sreyk ec_getlen(struct group *group) 44645ae9d61Sreyk { 44745ae9d61Sreyk if (group->spec == NULL) 44845ae9d61Sreyk return (0); 44945b72fd1Smikeb /* NB: Return value will always be even */ 45045ae9d61Sreyk return ((roundup(group->spec->bits, 8) * 2) / 8); 45145ae9d61Sreyk } 45245ae9d61Sreyk 45345ae9d61Sreyk int 454d09d3a7dSreyk ec_create_exchange(struct group *group, uint8_t *buf) 45545ae9d61Sreyk { 4560d5bf58dSreyk size_t len; 4570d5bf58dSreyk 4580d5bf58dSreyk len = ec_getlen(group); 4590d5bf58dSreyk bzero(buf, len); 4600d5bf58dSreyk 46145ae9d61Sreyk return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec), 4620d5bf58dSreyk buf, len)); 46345ae9d61Sreyk } 46445ae9d61Sreyk 46545ae9d61Sreyk int 466d09d3a7dSreyk ec_create_shared(struct group *group, uint8_t *secret, uint8_t *exchange) 46745ae9d61Sreyk { 46845ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 46945ae9d61Sreyk const BIGNUM *privkey; 470c900656bSmarkus EC_KEY *exkey = NULL; 47145ae9d61Sreyk EC_POINT *exchangep = NULL, *secretp = NULL; 47245ae9d61Sreyk int ret = -1; 47345ae9d61Sreyk 47445ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL || 47545ae9d61Sreyk (privkey = EC_KEY_get0_private_key(group->ec)) == NULL) 47645ae9d61Sreyk goto done; 47745ae9d61Sreyk 47845ae9d61Sreyk if ((exchangep = 47945ae9d61Sreyk ec_raw2point(group, exchange, ec_getlen(group))) == NULL) 48045ae9d61Sreyk goto done; 48145ae9d61Sreyk 482c900656bSmarkus if ((exkey = EC_KEY_new()) == NULL) 483c900656bSmarkus goto done; 484c900656bSmarkus if (!EC_KEY_set_group(exkey, ecgroup)) 485c900656bSmarkus goto done; 486c900656bSmarkus if (!EC_KEY_set_public_key(exkey, exchangep)) 487c900656bSmarkus goto done; 488c900656bSmarkus 489c900656bSmarkus /* validate exchangep */ 490c900656bSmarkus if (!EC_KEY_check_key(exkey)) 491c900656bSmarkus goto done; 492c900656bSmarkus 49345ae9d61Sreyk if ((secretp = EC_POINT_new(ecgroup)) == NULL) 49445ae9d61Sreyk goto done; 49545ae9d61Sreyk 49645ae9d61Sreyk if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL)) 49745ae9d61Sreyk goto done; 49845ae9d61Sreyk 49945ae9d61Sreyk ret = ec_point2raw(group, secretp, secret, ec_getlen(group)); 50045ae9d61Sreyk 50145ae9d61Sreyk done: 502c900656bSmarkus if (exkey != NULL) 503c900656bSmarkus EC_KEY_free(exkey); 50445ae9d61Sreyk if (exchangep != NULL) 50545ae9d61Sreyk EC_POINT_clear_free(exchangep); 50645ae9d61Sreyk if (secretp != NULL) 50745ae9d61Sreyk EC_POINT_clear_free(secretp); 50845ae9d61Sreyk 50945ae9d61Sreyk return (ret); 51045ae9d61Sreyk } 51145ae9d61Sreyk 51245ae9d61Sreyk int 51345ae9d61Sreyk ec_point2raw(struct group *group, const EC_POINT *point, 514d09d3a7dSreyk uint8_t *buf, size_t len) 51545ae9d61Sreyk { 51645ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 51745ae9d61Sreyk BN_CTX *bnctx = NULL; 51845ae9d61Sreyk BIGNUM *x = NULL, *y = NULL; 51945ae9d61Sreyk int ret = -1; 52045b72fd1Smikeb size_t eclen, xlen, ylen; 52145ae9d61Sreyk off_t xoff, yoff; 52245ae9d61Sreyk 52345ae9d61Sreyk if ((bnctx = BN_CTX_new()) == NULL) 52445ae9d61Sreyk goto done; 52545ae9d61Sreyk BN_CTX_start(bnctx); 52645ae9d61Sreyk if ((x = BN_CTX_get(bnctx)) == NULL || 52745ae9d61Sreyk (y = BN_CTX_get(bnctx)) == NULL) 52845ae9d61Sreyk goto done; 52945ae9d61Sreyk 53045b72fd1Smikeb eclen = ec_getlen(group); 53145b72fd1Smikeb if (len < eclen) 53245b72fd1Smikeb goto done; 53345b72fd1Smikeb xlen = ylen = eclen / 2; 53445b72fd1Smikeb 53545ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL) 53645ae9d61Sreyk goto done; 53745ae9d61Sreyk 53845ae9d61Sreyk if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) == 53945ae9d61Sreyk NID_X9_62_prime_field) { 54045ae9d61Sreyk if (!EC_POINT_get_affine_coordinates_GFp(ecgroup, 54145ae9d61Sreyk point, x, y, bnctx)) 54245ae9d61Sreyk goto done; 54345ae9d61Sreyk } else { 54445ae9d61Sreyk if (!EC_POINT_get_affine_coordinates_GF2m(ecgroup, 54545ae9d61Sreyk point, x, y, bnctx)) 54645ae9d61Sreyk goto done; 54745ae9d61Sreyk } 54845ae9d61Sreyk 54945ae9d61Sreyk xoff = xlen - BN_num_bytes(x); 55045b72fd1Smikeb bzero(buf, xoff); 55145ae9d61Sreyk if (!BN_bn2bin(x, buf + xoff)) 55245ae9d61Sreyk goto done; 55345ae9d61Sreyk 55445ae9d61Sreyk yoff = (ylen - BN_num_bytes(y)) + xlen; 55545b72fd1Smikeb bzero(buf + xlen, yoff - xlen); 55645ae9d61Sreyk if (!BN_bn2bin(y, buf + yoff)) 55745ae9d61Sreyk goto done; 55845ae9d61Sreyk 55945ae9d61Sreyk ret = 0; 56045ae9d61Sreyk done: 561c900656bSmarkus /* Make sure to erase sensitive data */ 562c900656bSmarkus if (x != NULL) 563c900656bSmarkus BN_clear(x); 564c900656bSmarkus if (y != NULL) 565c900656bSmarkus BN_clear(y); 56645ae9d61Sreyk BN_CTX_end(bnctx); 56745ae9d61Sreyk BN_CTX_free(bnctx); 56845ae9d61Sreyk 56945ae9d61Sreyk return (ret); 57045ae9d61Sreyk } 57145ae9d61Sreyk 57245ae9d61Sreyk EC_POINT * 573d09d3a7dSreyk ec_raw2point(struct group *group, uint8_t *buf, size_t len) 57445ae9d61Sreyk { 57545ae9d61Sreyk const EC_GROUP *ecgroup = NULL; 57645ae9d61Sreyk EC_POINT *point = NULL; 57745ae9d61Sreyk BN_CTX *bnctx = NULL; 57845ae9d61Sreyk BIGNUM *x = NULL, *y = NULL; 57945ae9d61Sreyk int ret = -1; 58045ae9d61Sreyk size_t eclen; 58145ae9d61Sreyk size_t xlen, ylen; 58245ae9d61Sreyk 58345ae9d61Sreyk if ((bnctx = BN_CTX_new()) == NULL) 58445ae9d61Sreyk goto done; 58545ae9d61Sreyk BN_CTX_start(bnctx); 58645ae9d61Sreyk if ((x = BN_CTX_get(bnctx)) == NULL || 58745ae9d61Sreyk (y = BN_CTX_get(bnctx)) == NULL) 58845ae9d61Sreyk goto done; 58945ae9d61Sreyk 59045ae9d61Sreyk eclen = ec_getlen(group); 59145ae9d61Sreyk if (len < eclen) 59245ae9d61Sreyk goto done; 59345ae9d61Sreyk xlen = ylen = eclen / 2; 59445ae9d61Sreyk if ((x = BN_bin2bn(buf, xlen, x)) == NULL || 59545ae9d61Sreyk (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL) 59645ae9d61Sreyk goto done; 59745ae9d61Sreyk 59845ae9d61Sreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL) 59945ae9d61Sreyk goto done; 60045ae9d61Sreyk 60145ae9d61Sreyk if ((point = EC_POINT_new(ecgroup)) == NULL) 60245ae9d61Sreyk goto done; 60345ae9d61Sreyk 60445ae9d61Sreyk if (EC_METHOD_get_field_type(EC_GROUP_method_of(ecgroup)) == 60545ae9d61Sreyk NID_X9_62_prime_field) { 60645ae9d61Sreyk if (!EC_POINT_set_affine_coordinates_GFp(ecgroup, 60745ae9d61Sreyk point, x, y, bnctx)) 60845ae9d61Sreyk goto done; 60945ae9d61Sreyk } else { 61045ae9d61Sreyk if (!EC_POINT_set_affine_coordinates_GF2m(ecgroup, 61145ae9d61Sreyk point, x, y, bnctx)) 61245ae9d61Sreyk goto done; 61345ae9d61Sreyk } 61445ae9d61Sreyk 61545ae9d61Sreyk ret = 0; 61645ae9d61Sreyk done: 61745ae9d61Sreyk if (ret != 0 && point != NULL) 61845ae9d61Sreyk EC_POINT_clear_free(point); 619c900656bSmarkus /* Make sure to erase sensitive data */ 620c900656bSmarkus if (x != NULL) 621c900656bSmarkus BN_clear(x); 622c900656bSmarkus if (y != NULL) 623c900656bSmarkus BN_clear(y); 62445ae9d61Sreyk BN_CTX_end(bnctx); 62545ae9d61Sreyk BN_CTX_free(bnctx); 62645ae9d61Sreyk 62745ae9d61Sreyk return (point); 62845ae9d61Sreyk } 62945135ebcSreyk 63045135ebcSreyk int 63145135ebcSreyk ec25519_init(struct group *group) 63245135ebcSreyk { 633d09d3a7dSreyk static const uint8_t basepoint[CURVE25519_SIZE] = { 9 }; 63445135ebcSreyk struct curve25519_key *curve25519; 63545135ebcSreyk 63645135ebcSreyk if ((curve25519 = calloc(1, sizeof(*curve25519))) == NULL) 63745135ebcSreyk return (-1); 63845135ebcSreyk 63945135ebcSreyk group->curve25519 = curve25519; 64045135ebcSreyk 64145135ebcSreyk arc4random_buf(curve25519->secret, CURVE25519_SIZE); 64245135ebcSreyk crypto_scalarmult_curve25519(curve25519->public, 64345135ebcSreyk curve25519->secret, basepoint); 64445135ebcSreyk 64545135ebcSreyk return (0); 64645135ebcSreyk } 64745135ebcSreyk 64845135ebcSreyk int 64945135ebcSreyk ec25519_getlen(struct group *group) 65045135ebcSreyk { 65145135ebcSreyk if (group->spec == NULL) 65245135ebcSreyk return (0); 65345135ebcSreyk return (CURVE25519_SIZE); 65445135ebcSreyk } 65545135ebcSreyk 65645135ebcSreyk int 657d09d3a7dSreyk ec25519_create_exchange(struct group *group, uint8_t *buf) 65845135ebcSreyk { 65945135ebcSreyk struct curve25519_key *curve25519 = group->curve25519; 66045135ebcSreyk 66145135ebcSreyk memcpy(buf, curve25519->public, ec25519_getlen(group)); 66245135ebcSreyk return (0); 66345135ebcSreyk } 66445135ebcSreyk 66545135ebcSreyk int 666d09d3a7dSreyk ec25519_create_shared(struct group *group, uint8_t *shared, uint8_t *public) 66745135ebcSreyk { 66845135ebcSreyk struct curve25519_key *curve25519 = group->curve25519; 66945135ebcSreyk 67045135ebcSreyk crypto_scalarmult_curve25519(shared, curve25519->secret, public); 67145135ebcSreyk return (0); 67245135ebcSreyk } 673