1*f51d8a34Stb /* $OpenBSD: dh.c,v 1.27 2023/03/31 07:28:46 tb Exp $ */
22040585eSniklas
32040585eSniklas /*
48978eb1dSreyk * Copyright (c) 2010-2014 Reyk Floeter <reyk@openbsd.org>
52040585eSniklas *
6fefcb31aSreyk * Permission to use, copy, modify, and distribute this software for any
7fefcb31aSreyk * purpose with or without fee is hereby granted, provided that the above
8fefcb31aSreyk * copyright notice and this permission notice appear in all copies.
92040585eSniklas *
10fefcb31aSreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11fefcb31aSreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12fefcb31aSreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13fefcb31aSreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14fefcb31aSreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15fefcb31aSreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16fefcb31aSreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172040585eSniklas */
182040585eSniklas
19fefcb31aSreyk #include <string.h>
202040585eSniklas
21fefcb31aSreyk #include <openssl/obj_mac.h>
22fefcb31aSreyk #include <openssl/dh.h>
23fefcb31aSreyk #include <openssl/ec.h>
24fefcb31aSreyk #include <openssl/ecdh.h>
258978eb1dSreyk #include <openssl/bn.h>
26fefcb31aSreyk
272040585eSniklas #include "dh.h"
282040585eSniklas
2913c7cd53Sderaadt #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
3013c7cd53Sderaadt
31fefcb31aSreyk int dh_init(struct group *);
32fefcb31aSreyk
33fefcb31aSreyk int modp_init(struct group *);
34fefcb31aSreyk int modp_getlen(struct group *);
35fefcb31aSreyk int modp_create_exchange(struct group *, u_int8_t *);
36fefcb31aSreyk int modp_create_shared(struct group *, u_int8_t *, u_int8_t *);
37fefcb31aSreyk
38fefcb31aSreyk int ec_init(struct group *);
39fefcb31aSreyk int ec_getlen(struct group *);
40f2c2b5e4Spatrick int ec_secretlen(struct group *);
41fefcb31aSreyk int ec_create_exchange(struct group *, u_int8_t *);
42fefcb31aSreyk int ec_create_shared(struct group *, u_int8_t *, u_int8_t *);
43fefcb31aSreyk
44f2c2b5e4Spatrick #define EC_POINT2RAW_FULL 0
45f2c2b5e4Spatrick #define EC_POINT2RAW_XONLY 1
46f2c2b5e4Spatrick int ec_point2raw(struct group *, const EC_POINT *, uint8_t *, size_t, int);
47fefcb31aSreyk EC_POINT *
48fefcb31aSreyk ec_raw2point(struct group *, u_int8_t *, size_t);
49fefcb31aSreyk
50fefcb31aSreyk struct group_id ike_groups[] = {
51fefcb31aSreyk { GROUP_MODP, 1, 768,
52fefcb31aSreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
53fefcb31aSreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
54fefcb31aSreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
55fefcb31aSreyk "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF",
56fefcb31aSreyk "02"
57fefcb31aSreyk },
58fefcb31aSreyk { GROUP_MODP, 2, 1024,
59fefcb31aSreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
60fefcb31aSreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
61fefcb31aSreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
62fefcb31aSreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
63fefcb31aSreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
64fefcb31aSreyk "FFFFFFFFFFFFFFFF",
65fefcb31aSreyk "02"
66fefcb31aSreyk },
67*f51d8a34Stb #ifndef OPENSSL_NO_EC2M
68fefcb31aSreyk { GROUP_EC2N, 3, 155, NULL, NULL, NID_ipsec3 },
69fefcb31aSreyk { GROUP_EC2N, 4, 185, NULL, NULL, NID_ipsec4 },
70*f51d8a34Stb #endif
71fefcb31aSreyk { GROUP_MODP, 5, 1536,
72fefcb31aSreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
73fefcb31aSreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
74fefcb31aSreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
75fefcb31aSreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
76fefcb31aSreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
77fefcb31aSreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
78fefcb31aSreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
79fefcb31aSreyk "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF",
80fefcb31aSreyk "02"
81fefcb31aSreyk },
82fefcb31aSreyk { GROUP_MODP, 14, 2048,
83fefcb31aSreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
84fefcb31aSreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
85fefcb31aSreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
86fefcb31aSreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
87fefcb31aSreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
88fefcb31aSreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
89fefcb31aSreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
90fefcb31aSreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
91fefcb31aSreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
92fefcb31aSreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
93fefcb31aSreyk "15728E5A8AACAA68FFFFFFFFFFFFFFFF",
94fefcb31aSreyk "02"
95fefcb31aSreyk },
96fefcb31aSreyk { GROUP_MODP, 15, 3072,
97fefcb31aSreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
98fefcb31aSreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
99fefcb31aSreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
100fefcb31aSreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
101fefcb31aSreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
102fefcb31aSreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
103fefcb31aSreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
104fefcb31aSreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
105fefcb31aSreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
106fefcb31aSreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
107fefcb31aSreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
108fefcb31aSreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
109fefcb31aSreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
110fefcb31aSreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
111fefcb31aSreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
112fefcb31aSreyk "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF",
113fefcb31aSreyk "02"
114fefcb31aSreyk },
115fefcb31aSreyk { GROUP_MODP, 16, 4096,
116fefcb31aSreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
117fefcb31aSreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
118fefcb31aSreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
119fefcb31aSreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
120fefcb31aSreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
121fefcb31aSreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
122fefcb31aSreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
123fefcb31aSreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
124fefcb31aSreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
125fefcb31aSreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
126fefcb31aSreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
127fefcb31aSreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
128fefcb31aSreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
129fefcb31aSreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
130fefcb31aSreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
131fefcb31aSreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
132fefcb31aSreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
133fefcb31aSreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
134fefcb31aSreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
135fefcb31aSreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
136fefcb31aSreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
137fefcb31aSreyk "FFFFFFFFFFFFFFFF",
138fefcb31aSreyk "02"
139fefcb31aSreyk },
140fefcb31aSreyk { GROUP_MODP, 17, 6144,
141fefcb31aSreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
142fefcb31aSreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
143fefcb31aSreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
144fefcb31aSreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
145fefcb31aSreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
146fefcb31aSreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
147fefcb31aSreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
148fefcb31aSreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
149fefcb31aSreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
150fefcb31aSreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
151fefcb31aSreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
152fefcb31aSreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
153fefcb31aSreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
154fefcb31aSreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
155fefcb31aSreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
156fefcb31aSreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
157fefcb31aSreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
158fefcb31aSreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
159fefcb31aSreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
160fefcb31aSreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
161fefcb31aSreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
162fefcb31aSreyk "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
163fefcb31aSreyk "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
164fefcb31aSreyk "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
165fefcb31aSreyk "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
166fefcb31aSreyk "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
167fefcb31aSreyk "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
168fefcb31aSreyk "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
169fefcb31aSreyk "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
170fefcb31aSreyk "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
171fefcb31aSreyk "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
172fefcb31aSreyk "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF",
173fefcb31aSreyk "02"
174fefcb31aSreyk },
175fefcb31aSreyk { GROUP_MODP, 18, 8192,
176fefcb31aSreyk "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
177fefcb31aSreyk "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
178fefcb31aSreyk "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
179fefcb31aSreyk "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
180fefcb31aSreyk "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
181fefcb31aSreyk "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
182fefcb31aSreyk "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
183fefcb31aSreyk "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
184fefcb31aSreyk "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
185fefcb31aSreyk "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
186fefcb31aSreyk "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
187fefcb31aSreyk "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
188fefcb31aSreyk "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
189fefcb31aSreyk "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
190fefcb31aSreyk "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
191fefcb31aSreyk "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
192fefcb31aSreyk "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
193fefcb31aSreyk "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
194fefcb31aSreyk "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
195fefcb31aSreyk "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
196fefcb31aSreyk "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
197fefcb31aSreyk "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
198fefcb31aSreyk "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
199fefcb31aSreyk "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
200fefcb31aSreyk "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
201fefcb31aSreyk "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
202fefcb31aSreyk "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
203fefcb31aSreyk "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
204fefcb31aSreyk "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
205fefcb31aSreyk "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
206fefcb31aSreyk "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
207fefcb31aSreyk "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
208fefcb31aSreyk "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
209fefcb31aSreyk "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
210fefcb31aSreyk "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
211fefcb31aSreyk "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
212fefcb31aSreyk "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
213fefcb31aSreyk "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
214fefcb31aSreyk "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
215fefcb31aSreyk "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
216fefcb31aSreyk "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
217fefcb31aSreyk "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
218fefcb31aSreyk "60C980DD98EDD3DFFFFFFFFFFFFFFFFF",
219fefcb31aSreyk "02"
220fefcb31aSreyk },
221fefcb31aSreyk { GROUP_ECP, 19, 256, NULL, NULL, NID_X9_62_prime256v1 },
222fefcb31aSreyk { GROUP_ECP, 20, 384, NULL, NULL, NID_secp384r1 },
223fefcb31aSreyk { GROUP_ECP, 21, 521, NULL, NULL, NID_secp521r1 },
224fefcb31aSreyk { GROUP_ECP, 25, 192, NULL, NULL, NID_X9_62_prime192v1 },
2258978eb1dSreyk { GROUP_ECP, 26, 224, NULL, NULL, NID_secp224r1 },
2268978eb1dSreyk { GROUP_ECP, 27, 224, NULL, NULL, NID_brainpoolP224r1 },
2278978eb1dSreyk { GROUP_ECP, 28, 256, NULL, NULL, NID_brainpoolP256r1 },
2288978eb1dSreyk { GROUP_ECP, 29, 384, NULL, NULL, NID_brainpoolP384r1 },
2298978eb1dSreyk { GROUP_ECP, 30, 512, NULL, NULL, NID_brainpoolP512r1 }
230fefcb31aSreyk };
231fefcb31aSreyk
232fefcb31aSreyk void
group_init(void)233fefcb31aSreyk group_init(void)
234fefcb31aSreyk {
235fefcb31aSreyk /* currently not used */
236fefcb31aSreyk return;
237fefcb31aSreyk }
238fefcb31aSreyk
239fefcb31aSreyk void
group_free(struct group * group)240fefcb31aSreyk group_free(struct group *group)
241fefcb31aSreyk {
242fefcb31aSreyk if (group == NULL)
243fefcb31aSreyk return;
244fefcb31aSreyk if (group->dh != NULL)
245fefcb31aSreyk DH_free(group->dh);
246fefcb31aSreyk if (group->ec != NULL)
247fefcb31aSreyk EC_KEY_free(group->ec);
248fefcb31aSreyk group->spec = NULL;
2498978eb1dSreyk free(group);
250fefcb31aSreyk }
251fefcb31aSreyk
252fefcb31aSreyk struct group *
group_get(u_int32_t id)253fefcb31aSreyk group_get(u_int32_t id)
254fefcb31aSreyk {
255fefcb31aSreyk struct group_id *p = NULL;
256fefcb31aSreyk struct group *group;
257fefcb31aSreyk u_int i, items;
258fefcb31aSreyk
259fefcb31aSreyk items = sizeof(ike_groups) / sizeof(ike_groups[0]);
260fefcb31aSreyk for (i = 0; i < items; i++) {
261fefcb31aSreyk if (id == ike_groups[i].id) {
262fefcb31aSreyk p = &ike_groups[i];
263fefcb31aSreyk break;
264fefcb31aSreyk }
265fefcb31aSreyk }
266fefcb31aSreyk if (p == NULL)
267fefcb31aSreyk return (NULL);
268fefcb31aSreyk
269fefcb31aSreyk if ((group = calloc(1, sizeof(*group))) == NULL)
270fefcb31aSreyk return (NULL);
271fefcb31aSreyk
272fefcb31aSreyk group->id = id;
273fefcb31aSreyk group->spec = p;
274fefcb31aSreyk
275fefcb31aSreyk switch (p->type) {
276fefcb31aSreyk case GROUP_MODP:
277fefcb31aSreyk group->init = modp_init;
278fefcb31aSreyk group->getlen = modp_getlen;
279fefcb31aSreyk group->exchange = modp_create_exchange;
280fefcb31aSreyk group->shared = modp_create_shared;
281fefcb31aSreyk break;
282*f51d8a34Stb #ifndef OPENSSL_NO_EC2M
283fefcb31aSreyk case GROUP_EC2N:
284*f51d8a34Stb #endif
285fefcb31aSreyk case GROUP_ECP:
286fefcb31aSreyk group->init = ec_init;
287fefcb31aSreyk group->getlen = ec_getlen;
288f2c2b5e4Spatrick group->secretlen = ec_secretlen;
289fefcb31aSreyk group->exchange = ec_create_exchange;
290fefcb31aSreyk group->shared = ec_create_shared;
291fefcb31aSreyk break;
292fefcb31aSreyk default:
293fefcb31aSreyk group_free(group);
294fefcb31aSreyk return (NULL);
295fefcb31aSreyk }
296fefcb31aSreyk
297fefcb31aSreyk if (dh_init(group) != 0) {
298fefcb31aSreyk group_free(group);
299fefcb31aSreyk return (NULL);
300fefcb31aSreyk }
301fefcb31aSreyk
302fefcb31aSreyk return (group);
303fefcb31aSreyk }
304fefcb31aSreyk
305fefcb31aSreyk int
dh_init(struct group * group)306fefcb31aSreyk dh_init(struct group *group)
307fefcb31aSreyk {
308fefcb31aSreyk return (group->init(group));
309fefcb31aSreyk }
3102040585eSniklas
3112040585eSniklas int
dh_getlen(struct group * group)3122040585eSniklas dh_getlen(struct group *group)
3132040585eSniklas {
314fefcb31aSreyk return (group->getlen(group));
3152040585eSniklas }
3162040585eSniklas
31704c806a6Sniklas int
dh_secretlen(struct group * group)318f2c2b5e4Spatrick dh_secretlen(struct group *group)
319f2c2b5e4Spatrick {
320f2c2b5e4Spatrick if (group->secretlen)
321f2c2b5e4Spatrick return (group->secretlen(group));
322f2c2b5e4Spatrick else
323f2c2b5e4Spatrick return (group->getlen(group));
324f2c2b5e4Spatrick }
325f2c2b5e4Spatrick
326f2c2b5e4Spatrick int
dh_create_exchange(struct group * group,u_int8_t * buf)3272040585eSniklas dh_create_exchange(struct group *group, u_int8_t *buf)
3282040585eSniklas {
329fefcb31aSreyk return (group->exchange(group, buf));
3302040585eSniklas }
3312040585eSniklas
33204c806a6Sniklas int
dh_create_shared(struct group * group,u_int8_t * secret,u_int8_t * exchange)3332040585eSniklas dh_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
3342040585eSniklas {
335fefcb31aSreyk return (group->shared(group, secret, exchange));
336fefcb31aSreyk }
337fefcb31aSreyk
338fefcb31aSreyk int
modp_init(struct group * group)339fefcb31aSreyk modp_init(struct group *group)
340fefcb31aSreyk {
341fefcb31aSreyk DH *dh;
3426ddd611fStb BIGNUM *p = NULL, *g = NULL;
343fefcb31aSreyk
344fefcb31aSreyk if ((dh = DH_new()) == NULL)
345fefcb31aSreyk return (-1);
346fefcb31aSreyk group->dh = dh;
347fefcb31aSreyk
3486ddd611fStb if (!BN_hex2bn(&p, group->spec->prime) ||
3496ddd611fStb !BN_hex2bn(&g, group->spec->generator)) {
3506ddd611fStb BN_free(p);
3516ddd611fStb BN_free(g);
352fefcb31aSreyk return (-1);
3536ddd611fStb }
3546ddd611fStb
3556ddd611fStb if (!DH_set0_pqg(dh, p, NULL, g)) {
3566ddd611fStb BN_free(p);
3576ddd611fStb BN_free(g);
3586ddd611fStb return (-1);
3596ddd611fStb }
360fefcb31aSreyk
361fefcb31aSreyk return (0);
362fefcb31aSreyk }
363fefcb31aSreyk
364fefcb31aSreyk int
modp_getlen(struct group * group)365fefcb31aSreyk modp_getlen(struct group *group)
366fefcb31aSreyk {
367fefcb31aSreyk if (group->spec == NULL)
368fefcb31aSreyk return (0);
369fefcb31aSreyk return (roundup(group->spec->bits, 8) / 8);
370fefcb31aSreyk }
371fefcb31aSreyk
372fefcb31aSreyk int
modp_create_exchange(struct group * group,u_int8_t * buf)373fefcb31aSreyk modp_create_exchange(struct group *group, u_int8_t *buf)
374fefcb31aSreyk {
375fefcb31aSreyk DH *dh = group->dh;
376390e060eSmikeb int len, ret;
377fefcb31aSreyk
378fefcb31aSreyk if (!DH_generate_key(dh))
379fefcb31aSreyk return (-1);
38066138239Stb ret = BN_bn2bin(DH_get0_pub_key(dh), buf);
381390e060eSmikeb if (!ret)
382fefcb31aSreyk return (-1);
383fefcb31aSreyk
384390e060eSmikeb len = dh_getlen(group);
385390e060eSmikeb
386390e060eSmikeb /* add zero padding */
387390e060eSmikeb if (ret < len) {
388390e060eSmikeb bcopy(buf, buf + (len - ret), ret);
389390e060eSmikeb bzero(buf, len - ret);
390390e060eSmikeb }
391390e060eSmikeb
392fefcb31aSreyk return (0);
393fefcb31aSreyk }
394fefcb31aSreyk
395fefcb31aSreyk int
modp_create_shared(struct group * group,u_int8_t * secret,u_int8_t * exchange)396fefcb31aSreyk modp_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
397fefcb31aSreyk {
398fefcb31aSreyk BIGNUM *ex;
399390e060eSmikeb int len, ret;
400fefcb31aSreyk
401390e060eSmikeb len = dh_getlen(group);
402390e060eSmikeb
403390e060eSmikeb if ((ex = BN_bin2bn(exchange, len, NULL)) == NULL)
404fefcb31aSreyk return (-1);
405fefcb31aSreyk
406fefcb31aSreyk ret = DH_compute_key(secret, ex, group->dh);
407fefcb31aSreyk BN_clear_free(ex);
4082ffa77eaSjsg if (ret <= 0)
409fefcb31aSreyk return (-1);
410fefcb31aSreyk
411390e060eSmikeb /* add zero padding */
412390e060eSmikeb if (ret < len) {
413390e060eSmikeb bcopy(secret, secret + (len - ret), ret);
414390e060eSmikeb bzero(secret, len - ret);
415390e060eSmikeb }
416390e060eSmikeb
417fefcb31aSreyk return (0);
418fefcb31aSreyk }
419fefcb31aSreyk
420fefcb31aSreyk int
ec_init(struct group * group)421fefcb31aSreyk ec_init(struct group *group)
422fefcb31aSreyk {
423fefcb31aSreyk if ((group->ec = EC_KEY_new_by_curve_name(group->spec->nid)) == NULL)
424fefcb31aSreyk return (-1);
425fefcb31aSreyk if (!EC_KEY_generate_key(group->ec))
426fefcb31aSreyk return (-1);
42782291602Stb if (!EC_KEY_check_key(group->ec))
4288978eb1dSreyk return (-1);
429fefcb31aSreyk return (0);
430fefcb31aSreyk }
431fefcb31aSreyk
432fefcb31aSreyk int
ec_getlen(struct group * group)433fefcb31aSreyk ec_getlen(struct group *group)
434fefcb31aSreyk {
435fefcb31aSreyk if (group->spec == NULL)
436fefcb31aSreyk return (0);
43745b72fd1Smikeb /* NB: Return value will always be even */
438fefcb31aSreyk return ((roundup(group->spec->bits, 8) * 2) / 8);
439fefcb31aSreyk }
440fefcb31aSreyk
441f2c2b5e4Spatrick /*
442f2c2b5e4Spatrick * Note that the shared secret only includes the x value:
443f2c2b5e4Spatrick *
444f2c2b5e4Spatrick * See RFC 5903, 7. ECP Key Exchange Data Formats:
445f2c2b5e4Spatrick * The Diffie-Hellman shared secret value consists of the x value of the
446f2c2b5e4Spatrick * Diffie-Hellman common value.
447f2c2b5e4Spatrick * See also RFC 5903, 9. Changes from RFC 4753.
448f2c2b5e4Spatrick */
449f2c2b5e4Spatrick int
ec_secretlen(struct group * group)450f2c2b5e4Spatrick ec_secretlen(struct group *group)
451f2c2b5e4Spatrick {
452f2c2b5e4Spatrick return (ec_getlen(group) / 2);
453f2c2b5e4Spatrick }
454f2c2b5e4Spatrick
455fefcb31aSreyk int
ec_create_exchange(struct group * group,u_int8_t * buf)456fefcb31aSreyk ec_create_exchange(struct group *group, u_int8_t *buf)
457fefcb31aSreyk {
458fefcb31aSreyk size_t len;
459fefcb31aSreyk
460fefcb31aSreyk len = ec_getlen(group);
461fefcb31aSreyk bzero(buf, len);
462fefcb31aSreyk
463fefcb31aSreyk return (ec_point2raw(group, EC_KEY_get0_public_key(group->ec),
464f2c2b5e4Spatrick buf, len, EC_POINT2RAW_FULL));
465fefcb31aSreyk }
466fefcb31aSreyk
467fefcb31aSreyk int
ec_create_shared(struct group * group,u_int8_t * secret,u_int8_t * exchange)468fefcb31aSreyk ec_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange)
469fefcb31aSreyk {
470fefcb31aSreyk const EC_GROUP *ecgroup = NULL;
471fefcb31aSreyk const BIGNUM *privkey;
4728978eb1dSreyk EC_KEY *exkey = NULL;
473fefcb31aSreyk EC_POINT *exchangep = NULL, *secretp = NULL;
474fefcb31aSreyk int ret = -1;
475fefcb31aSreyk
476fefcb31aSreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL ||
477fefcb31aSreyk (privkey = EC_KEY_get0_private_key(group->ec)) == NULL)
478fefcb31aSreyk goto done;
479fefcb31aSreyk
480fefcb31aSreyk if ((exchangep =
481fefcb31aSreyk ec_raw2point(group, exchange, ec_getlen(group))) == NULL)
482fefcb31aSreyk goto done;
483fefcb31aSreyk
4848978eb1dSreyk if ((exkey = EC_KEY_new()) == NULL)
4858978eb1dSreyk goto done;
4868978eb1dSreyk if (!EC_KEY_set_group(exkey, ecgroup))
4878978eb1dSreyk goto done;
4888978eb1dSreyk if (!EC_KEY_set_public_key(exkey, exchangep))
4898978eb1dSreyk goto done;
4908978eb1dSreyk
4918978eb1dSreyk /* validate exchangep */
4928978eb1dSreyk if (!EC_KEY_check_key(exkey))
4938978eb1dSreyk goto done;
4948978eb1dSreyk
495fefcb31aSreyk if ((secretp = EC_POINT_new(ecgroup)) == NULL)
496fefcb31aSreyk goto done;
497fefcb31aSreyk
498fefcb31aSreyk if (!EC_POINT_mul(ecgroup, secretp, NULL, exchangep, privkey, NULL))
499fefcb31aSreyk goto done;
500fefcb31aSreyk
501f2c2b5e4Spatrick ret = ec_point2raw(group, secretp, secret, ec_secretlen(group),
502f2c2b5e4Spatrick EC_POINT2RAW_XONLY);
503fefcb31aSreyk
504fefcb31aSreyk done:
5058978eb1dSreyk if (exkey != NULL)
5068978eb1dSreyk EC_KEY_free(exkey);
507fefcb31aSreyk if (exchangep != NULL)
508fefcb31aSreyk EC_POINT_clear_free(exchangep);
509fefcb31aSreyk if (secretp != NULL)
510fefcb31aSreyk EC_POINT_clear_free(secretp);
511fefcb31aSreyk
512fefcb31aSreyk return (ret);
513fefcb31aSreyk }
514fefcb31aSreyk
515fefcb31aSreyk int
ec_point2raw(struct group * group,const EC_POINT * point,u_int8_t * buf,size_t len,int mode)516fefcb31aSreyk ec_point2raw(struct group *group, const EC_POINT *point,
517f2c2b5e4Spatrick u_int8_t *buf, size_t len, int mode)
518fefcb31aSreyk {
519fefcb31aSreyk const EC_GROUP *ecgroup = NULL;
520fefcb31aSreyk BN_CTX *bnctx = NULL;
521fefcb31aSreyk BIGNUM *x = NULL, *y = NULL;
522fefcb31aSreyk int ret = -1;
52345b72fd1Smikeb size_t eclen, xlen, ylen;
524fefcb31aSreyk off_t xoff, yoff;
525fefcb31aSreyk
526fefcb31aSreyk if ((bnctx = BN_CTX_new()) == NULL)
527fefcb31aSreyk goto done;
528fefcb31aSreyk BN_CTX_start(bnctx);
529fefcb31aSreyk if ((x = BN_CTX_get(bnctx)) == NULL ||
530fefcb31aSreyk (y = BN_CTX_get(bnctx)) == NULL)
531fefcb31aSreyk goto done;
532fefcb31aSreyk
53345b72fd1Smikeb eclen = ec_getlen(group);
534f2c2b5e4Spatrick switch (mode) {
535f2c2b5e4Spatrick case EC_POINT2RAW_XONLY:
536f2c2b5e4Spatrick xlen = eclen / 2;
537f2c2b5e4Spatrick ylen = 0;
538f2c2b5e4Spatrick break;
539f2c2b5e4Spatrick case EC_POINT2RAW_FULL:
54045b72fd1Smikeb xlen = ylen = eclen / 2;
541f2c2b5e4Spatrick break;
542f2c2b5e4Spatrick default:
543f2c2b5e4Spatrick goto done;
544f2c2b5e4Spatrick }
545f2c2b5e4Spatrick if (len < xlen + ylen)
546f2c2b5e4Spatrick goto done;
54745b72fd1Smikeb
548fefcb31aSreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
549fefcb31aSreyk goto done;
550fefcb31aSreyk
551cc86847bStb if (!EC_POINT_get_affine_coordinates(ecgroup, point, x, y, bnctx))
552fefcb31aSreyk goto done;
553fefcb31aSreyk
554fefcb31aSreyk xoff = xlen - BN_num_bytes(x);
55545b72fd1Smikeb bzero(buf, xoff);
556fefcb31aSreyk if (!BN_bn2bin(x, buf + xoff))
557fefcb31aSreyk goto done;
558fefcb31aSreyk
559f2c2b5e4Spatrick if (ylen > 0) {
560fefcb31aSreyk yoff = (ylen - BN_num_bytes(y)) + xlen;
56145b72fd1Smikeb bzero(buf + xlen, yoff - xlen);
562fefcb31aSreyk if (!BN_bn2bin(y, buf + yoff))
563fefcb31aSreyk goto done;
564f2c2b5e4Spatrick }
565fefcb31aSreyk
566fefcb31aSreyk ret = 0;
567fefcb31aSreyk done:
5688978eb1dSreyk /* Make sure to erase sensitive data */
5698978eb1dSreyk if (x != NULL)
5708978eb1dSreyk BN_clear(x);
5718978eb1dSreyk if (y != NULL)
5728978eb1dSreyk BN_clear(y);
573fefcb31aSreyk BN_CTX_end(bnctx);
574fefcb31aSreyk BN_CTX_free(bnctx);
575fefcb31aSreyk
576fefcb31aSreyk return (ret);
577fefcb31aSreyk }
578fefcb31aSreyk
579fefcb31aSreyk EC_POINT *
ec_raw2point(struct group * group,u_int8_t * buf,size_t len)580fefcb31aSreyk ec_raw2point(struct group *group, u_int8_t *buf, size_t len)
581fefcb31aSreyk {
582fefcb31aSreyk const EC_GROUP *ecgroup = NULL;
583fefcb31aSreyk EC_POINT *point = NULL;
584fefcb31aSreyk BN_CTX *bnctx = NULL;
585fefcb31aSreyk BIGNUM *x = NULL, *y = NULL;
586fefcb31aSreyk int ret = -1;
587fefcb31aSreyk size_t eclen;
588fefcb31aSreyk size_t xlen, ylen;
589fefcb31aSreyk
590fefcb31aSreyk if ((bnctx = BN_CTX_new()) == NULL)
591fefcb31aSreyk goto done;
592fefcb31aSreyk BN_CTX_start(bnctx);
593fefcb31aSreyk if ((x = BN_CTX_get(bnctx)) == NULL ||
594fefcb31aSreyk (y = BN_CTX_get(bnctx)) == NULL)
595fefcb31aSreyk goto done;
596fefcb31aSreyk
597fefcb31aSreyk eclen = ec_getlen(group);
598fefcb31aSreyk if (len < eclen)
599fefcb31aSreyk goto done;
600fefcb31aSreyk xlen = ylen = eclen / 2;
601fefcb31aSreyk if ((x = BN_bin2bn(buf, xlen, x)) == NULL ||
602fefcb31aSreyk (y = BN_bin2bn(buf + xlen, ylen, y)) == NULL)
603fefcb31aSreyk goto done;
604fefcb31aSreyk
605fefcb31aSreyk if ((ecgroup = EC_KEY_get0_group(group->ec)) == NULL)
606fefcb31aSreyk goto done;
607fefcb31aSreyk
608fefcb31aSreyk if ((point = EC_POINT_new(ecgroup)) == NULL)
609fefcb31aSreyk goto done;
610fefcb31aSreyk
611cc86847bStb if (!EC_POINT_set_affine_coordinates(ecgroup, point, x, y, bnctx))
612fefcb31aSreyk goto done;
613fefcb31aSreyk
614fefcb31aSreyk ret = 0;
615fefcb31aSreyk done:
616fefcb31aSreyk if (ret != 0 && point != NULL)
617fefcb31aSreyk EC_POINT_clear_free(point);
6188978eb1dSreyk /* Make sure to erase sensitive data */
6198978eb1dSreyk if (x != NULL)
6208978eb1dSreyk BN_clear(x);
6218978eb1dSreyk if (y != NULL)
6228978eb1dSreyk BN_clear(y);
623fefcb31aSreyk BN_CTX_end(bnctx);
624fefcb31aSreyk BN_CTX_free(bnctx);
625fefcb31aSreyk
626fefcb31aSreyk return (point);
6272040585eSniklas }
628