/src/gnutls/lib/algorithms/groups.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2017 Red Hat, Inc. |
3 | | * |
4 | | * Author: Nikos Mavrogiannopoulos |
5 | | * |
6 | | * This file is part of GnuTLS. |
7 | | * |
8 | | * The GnuTLS is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Lesser General Public License |
10 | | * as published by the Free Software Foundation; either version 2.1 of |
11 | | * the License, or (at your option) any later version. |
12 | | * |
13 | | * This library is distributed in the hope that it will be useful, but |
14 | | * WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public License |
19 | | * along with this program. If not, see <https://www.gnu.org/licenses/> |
20 | | * |
21 | | */ |
22 | | |
23 | | #include "gnutls_int.h" |
24 | | #include "algorithms.h" |
25 | | #include "errors.h" |
26 | | #include "x509/common.h" |
27 | | #include "pk.h" |
28 | | #include "c-strcase.h" |
29 | | |
30 | | /* Supported ECC curves |
31 | | */ |
32 | | |
33 | | static const gnutls_group_entry_st supported_groups[] = { |
34 | | { |
35 | | .name = "SECP192R1", |
36 | | .id = GNUTLS_GROUP_SECP192R1, |
37 | | .curve = GNUTLS_ECC_CURVE_SECP192R1, |
38 | | .tls_id = 19, |
39 | | .pk = GNUTLS_PK_ECDSA, |
40 | | }, |
41 | | { |
42 | | .name = "SECP224R1", |
43 | | .id = GNUTLS_GROUP_SECP224R1, |
44 | | .curve = GNUTLS_ECC_CURVE_SECP224R1, |
45 | | .tls_id = 21, |
46 | | .pk = GNUTLS_PK_ECDSA, |
47 | | }, |
48 | | { |
49 | | .name = "SECP256R1", |
50 | | .id = GNUTLS_GROUP_SECP256R1, |
51 | | .curve = GNUTLS_ECC_CURVE_SECP256R1, |
52 | | .tls_id = 23, |
53 | | .pk = GNUTLS_PK_ECDSA, |
54 | | }, |
55 | | { |
56 | | .name = "SECP384R1", |
57 | | .id = GNUTLS_GROUP_SECP384R1, |
58 | | .curve = GNUTLS_ECC_CURVE_SECP384R1, |
59 | | .tls_id = 24, |
60 | | .pk = GNUTLS_PK_ECDSA, |
61 | | }, |
62 | | { |
63 | | .name = "SECP521R1", |
64 | | .id = GNUTLS_GROUP_SECP521R1, |
65 | | .curve = GNUTLS_ECC_CURVE_SECP521R1, |
66 | | .tls_id = 25, |
67 | | .pk = GNUTLS_PK_ECDSA, |
68 | | }, |
69 | | { |
70 | | .name = "X25519", |
71 | | .id = GNUTLS_GROUP_X25519, |
72 | | .curve = GNUTLS_ECC_CURVE_X25519, |
73 | | .tls_id = 29, |
74 | | .pk = GNUTLS_PK_ECDH_X25519, |
75 | | }, |
76 | | #ifdef ENABLE_GOST |
77 | | /* draft-smyshlyaev-tls12-gost-suites-06, Section 6 */ |
78 | | { |
79 | | .name = "GC256A", |
80 | | .id = GNUTLS_GROUP_GC256A, |
81 | | .curve = GNUTLS_ECC_CURVE_GOST256A, |
82 | | .pk = GNUTLS_PK_GOST_12_256, |
83 | | .tls_id = 34, |
84 | | }, |
85 | | { |
86 | | .name = "GC256B", |
87 | | .id = GNUTLS_GROUP_GC256B, |
88 | | .curve = GNUTLS_ECC_CURVE_GOST256B, |
89 | | .pk = GNUTLS_PK_GOST_12_256, |
90 | | .tls_id = 35, |
91 | | }, |
92 | | { |
93 | | .name = "GC256C", |
94 | | .id = GNUTLS_GROUP_GC256C, |
95 | | .curve = GNUTLS_ECC_CURVE_GOST256C, |
96 | | .pk = GNUTLS_PK_GOST_12_256, |
97 | | .tls_id = 36, |
98 | | }, |
99 | | { |
100 | | .name = "GC256D", |
101 | | .id = GNUTLS_GROUP_GC256D, |
102 | | .curve = GNUTLS_ECC_CURVE_GOST256D, |
103 | | .pk = GNUTLS_PK_GOST_12_256, |
104 | | .tls_id = 37, |
105 | | }, |
106 | | { |
107 | | .name = "GC512A", |
108 | | .id = GNUTLS_GROUP_GC512A, |
109 | | .curve = GNUTLS_ECC_CURVE_GOST512A, |
110 | | .pk = GNUTLS_PK_GOST_12_512, |
111 | | .tls_id = 38, |
112 | | }, |
113 | | { |
114 | | .name = "GC512B", |
115 | | .id = GNUTLS_GROUP_GC512B, |
116 | | .curve = GNUTLS_ECC_CURVE_GOST512B, |
117 | | .pk = GNUTLS_PK_GOST_12_512, |
118 | | .tls_id = 39, |
119 | | }, |
120 | | { |
121 | | .name = "GC512C", |
122 | | .id = GNUTLS_GROUP_GC512C, |
123 | | .curve = GNUTLS_ECC_CURVE_GOST512C, |
124 | | .pk = GNUTLS_PK_GOST_12_512, |
125 | | .tls_id = 40, |
126 | | }, |
127 | | #endif |
128 | | { .name = "X448", |
129 | | .id = GNUTLS_GROUP_X448, |
130 | | .curve = GNUTLS_ECC_CURVE_X448, |
131 | | .tls_id = 30, |
132 | | .pk = GNUTLS_PK_ECDH_X448 }, |
133 | | #ifdef ENABLE_DHE |
134 | | { .name = "FFDHE2048", |
135 | | .id = GNUTLS_GROUP_FFDHE2048, |
136 | | .generator = &gnutls_ffdhe_2048_group_generator, |
137 | | .prime = &gnutls_ffdhe_2048_group_prime, |
138 | | .q = &gnutls_ffdhe_2048_group_q, |
139 | | .q_bits = &gnutls_ffdhe_2048_key_bits, |
140 | | .pk = GNUTLS_PK_DH, |
141 | | .tls_id = 0x100 }, |
142 | | { .name = "FFDHE3072", |
143 | | .id = GNUTLS_GROUP_FFDHE3072, |
144 | | .generator = &gnutls_ffdhe_3072_group_generator, |
145 | | .prime = &gnutls_ffdhe_3072_group_prime, |
146 | | .q = &gnutls_ffdhe_3072_group_q, |
147 | | .q_bits = &gnutls_ffdhe_3072_key_bits, |
148 | | .pk = GNUTLS_PK_DH, |
149 | | .tls_id = 0x101 }, |
150 | | { .name = "FFDHE4096", |
151 | | .id = GNUTLS_GROUP_FFDHE4096, |
152 | | .generator = &gnutls_ffdhe_4096_group_generator, |
153 | | .prime = &gnutls_ffdhe_4096_group_prime, |
154 | | .q = &gnutls_ffdhe_4096_group_q, |
155 | | .q_bits = &gnutls_ffdhe_4096_key_bits, |
156 | | .pk = GNUTLS_PK_DH, |
157 | | .tls_id = 0x102 }, |
158 | | { .name = "FFDHE6144", |
159 | | .id = GNUTLS_GROUP_FFDHE6144, |
160 | | .generator = &gnutls_ffdhe_6144_group_generator, |
161 | | .prime = &gnutls_ffdhe_6144_group_prime, |
162 | | .q = &gnutls_ffdhe_6144_group_q, |
163 | | .q_bits = &gnutls_ffdhe_6144_key_bits, |
164 | | .pk = GNUTLS_PK_DH, |
165 | | .tls_id = 0x103 }, |
166 | | { .name = "FFDHE8192", |
167 | | .id = GNUTLS_GROUP_FFDHE8192, |
168 | | .generator = &gnutls_ffdhe_8192_group_generator, |
169 | | .prime = &gnutls_ffdhe_8192_group_prime, |
170 | | .q = &gnutls_ffdhe_8192_group_q, |
171 | | .q_bits = &gnutls_ffdhe_8192_key_bits, |
172 | | .pk = GNUTLS_PK_DH, |
173 | | .tls_id = 0x104 }, |
174 | | #endif |
175 | | #if defined(HAVE_LIBOQS) || defined(HAVE_LEANCRYPTO) |
176 | | { |
177 | | .name = "MLKEM768", |
178 | | .id = GNUTLS_GROUP_EXP_MLKEM768, |
179 | | .pk = GNUTLS_PK_MLKEM768, |
180 | | .pubkey_size = MLKEM768_PUBKEY_SIZE, |
181 | | .ciphertext_size = MLKEM768_CIPHERTEXT_SIZE, |
182 | | /* absense of .tls_id means that this group alone cannot be used in TLS */ |
183 | | }, |
184 | | { |
185 | | .name = "MLKEM1024", |
186 | | .id = GNUTLS_GROUP_EXP_MLKEM1024, |
187 | | .pk = GNUTLS_PK_MLKEM1024, |
188 | | .pubkey_size = MLKEM1024_PUBKEY_SIZE, |
189 | | .ciphertext_size = MLKEM1024_CIPHERTEXT_SIZE, |
190 | | /* absense of .tls_id means that this group alone cannot be used in TLS */ |
191 | | }, |
192 | | #endif |
193 | | #ifdef HAVE_LIBOQS |
194 | | { |
195 | | .name = "KYBER768", |
196 | | .id = GNUTLS_GROUP_EXP_KYBER768, |
197 | | .pk = GNUTLS_PK_EXP_KYBER768, |
198 | | .pubkey_size = MLKEM768_PUBKEY_SIZE, |
199 | | .ciphertext_size = MLKEM768_CIPHERTEXT_SIZE, |
200 | | /* absense of .tls_id means that this group alone cannot be used in TLS */ |
201 | | }, |
202 | | #endif |
203 | | #if defined(HAVE_LIBOQS) || defined(HAVE_LEANCRYPTO) |
204 | | { .name = "SECP256R1-MLKEM768", |
205 | | .id = GNUTLS_GROUP_EXP_SECP256R1_MLKEM768, |
206 | | .ids = { GNUTLS_GROUP_SECP256R1, GNUTLS_GROUP_EXP_MLKEM768, |
207 | | GNUTLS_GROUP_INVALID }, |
208 | | .tls_id = 0x11EB }, |
209 | | { .name = "SECP384R1-MLKEM1024", |
210 | | .id = GNUTLS_GROUP_EXP_SECP384R1_MLKEM1024, |
211 | | .ids = { GNUTLS_GROUP_SECP384R1, GNUTLS_GROUP_EXP_MLKEM1024, |
212 | | GNUTLS_GROUP_INVALID }, |
213 | | .tls_id = 0x11ED }, |
214 | | { .name = "X25519-MLKEM768", |
215 | | .id = GNUTLS_GROUP_EXP_X25519_MLKEM768, |
216 | | .ids = { GNUTLS_GROUP_EXP_MLKEM768, GNUTLS_GROUP_X25519, |
217 | | GNUTLS_GROUP_INVALID }, |
218 | | .tls_id = 0x11EC }, |
219 | | #endif |
220 | | #ifdef HAVE_LIBOQS |
221 | | { .name = "X25519-KYBER768", |
222 | | .id = GNUTLS_GROUP_EXP_X25519_KYBER768, |
223 | | .ids = { GNUTLS_GROUP_X25519, GNUTLS_GROUP_EXP_KYBER768, |
224 | | GNUTLS_GROUP_INVALID }, |
225 | | .tls_id = 0x6399 }, |
226 | | #endif |
227 | | { 0, 0, 0 } |
228 | | }; |
229 | | |
230 | | #define GNUTLS_GROUP_LOOP(b) \ |
231 | 0 | { \ |
232 | 0 | const gnutls_group_entry_st *p; \ |
233 | 0 | for (p = supported_groups; p->name != NULL; p++) { \ |
234 | 0 | b; \ |
235 | 0 | } \ |
236 | 0 | } |
237 | | |
238 | | static inline const gnutls_group_entry_st *group_to_entry(gnutls_group_t group) |
239 | 0 | { |
240 | 0 | if (group == 0) |
241 | 0 | return NULL; |
242 | | |
243 | 0 | GNUTLS_GROUP_LOOP(if (p->id == group) { return p; }); |
244 | |
|
245 | 0 | return NULL; |
246 | 0 | } |
247 | | |
248 | | static inline bool |
249 | | group_is_supported_standalone(const gnutls_group_entry_st *group) |
250 | 0 | { |
251 | 0 | return group->pk != 0 && _gnutls_pk_exists(group->pk) && |
252 | 0 | (group->curve == 0 || |
253 | 0 | _gnutls_ecc_curve_is_supported(group->curve)); |
254 | 0 | } |
255 | | |
256 | | static inline bool group_is_supported(const gnutls_group_entry_st *group) |
257 | 0 | { |
258 | 0 | if (!IS_GROUP_HYBRID(group)) |
259 | 0 | return group_is_supported_standalone(group); |
260 | | |
261 | 0 | for (size_t i = 0; |
262 | 0 | i < MAX_HYBRID_GROUPS && group->ids[i] != GNUTLS_GROUP_INVALID; |
263 | 0 | i++) { |
264 | 0 | const gnutls_group_entry_st *p = group_to_entry(group->ids[i]); |
265 | 0 | if (!p || !group_is_supported_standalone(p)) |
266 | 0 | return false; |
267 | 0 | } |
268 | | |
269 | 0 | return true; |
270 | 0 | } |
271 | | |
272 | | /* Returns the TLS id of the given curve |
273 | | */ |
274 | | const gnutls_group_entry_st *_gnutls_tls_id_to_group(unsigned num) |
275 | 0 | { |
276 | 0 | GNUTLS_GROUP_LOOP( |
277 | 0 | if (p->tls_id == num && group_is_supported(p)) { return p; }); |
278 | |
|
279 | 0 | return NULL; |
280 | 0 | } |
281 | | |
282 | | const gnutls_group_entry_st *_gnutls_id_to_group(unsigned id) |
283 | 0 | { |
284 | 0 | if (id == 0) |
285 | 0 | return NULL; |
286 | | |
287 | 0 | GNUTLS_GROUP_LOOP( |
288 | 0 | if (p->id == id && group_is_supported(p)) { return p; }); |
289 | |
|
290 | 0 | return NULL; |
291 | 0 | } |
292 | | |
293 | | /** |
294 | | * gnutls_group_list: |
295 | | * |
296 | | * Get the list of supported elliptic curves. |
297 | | * |
298 | | * This function is not thread safe. |
299 | | * |
300 | | * Returns: Return a (0)-terminated list of #gnutls_group_t |
301 | | * integers indicating the available groups. |
302 | | * |
303 | | * Since: 3.6.0 |
304 | | **/ |
305 | | const gnutls_group_t *gnutls_group_list(void) |
306 | 0 | { |
307 | 0 | static gnutls_group_t groups[MAX_ALGOS + 1] = { 0 }; |
308 | |
|
309 | 0 | if (groups[0] == 0) { |
310 | 0 | size_t i = 0; |
311 | |
|
312 | 0 | for (const gnutls_group_entry_st *p = supported_groups; |
313 | 0 | p->name != NULL; p++) { |
314 | 0 | if (group_is_supported(p)) |
315 | 0 | groups[i++] = p->id; |
316 | 0 | } |
317 | 0 | groups[i++] = GNUTLS_GROUP_INVALID; |
318 | 0 | } |
319 | |
|
320 | 0 | return groups; |
321 | 0 | } |
322 | | |
323 | | /** |
324 | | * gnutls_group_get_id: |
325 | | * @name: is a group name |
326 | | * |
327 | | * The names are compared in a case insensitive way. |
328 | | * |
329 | | * Returns: return a #gnutls_group_t value corresponding to |
330 | | * the specified group, or %GNUTLS_GROUP_INVALID on error. |
331 | | * |
332 | | * Since: 3.6.0 |
333 | | **/ |
334 | | gnutls_group_t gnutls_group_get_id(const char *name) |
335 | 0 | { |
336 | 0 | gnutls_group_t ret = GNUTLS_GROUP_INVALID; |
337 | |
|
338 | 0 | GNUTLS_GROUP_LOOP(if (c_strcasecmp(p->name, name) == 0 && |
339 | 0 | (p->curve == 0 || |
340 | 0 | _gnutls_ecc_curve_is_supported(p->curve))) { |
341 | 0 | ret = p->id; |
342 | 0 | break; |
343 | 0 | }); |
344 | |
|
345 | 0 | return ret; |
346 | 0 | } |
347 | | |
348 | | /* Similar to gnutls_group_get_id, except that it does not check if |
349 | | * the curve is supported. |
350 | | */ |
351 | | gnutls_group_t _gnutls_group_get_id(const char *name) |
352 | 0 | { |
353 | 0 | gnutls_group_t ret = GNUTLS_GROUP_INVALID; |
354 | |
|
355 | 0 | GNUTLS_GROUP_LOOP(if (c_strcasecmp(p->name, name) == 0) { |
356 | 0 | ret = p->id; |
357 | 0 | break; |
358 | 0 | }); |
359 | |
|
360 | 0 | return ret; |
361 | 0 | } |
362 | | |
363 | | /** |
364 | | * gnutls_group_get_name: |
365 | | * @group: is an element from %gnutls_group_t |
366 | | * |
367 | | * Convert a #gnutls_group_t value to a string. |
368 | | * |
369 | | * Returns: a string that contains the name of the specified |
370 | | * group or %NULL. |
371 | | * |
372 | | * Since: 3.6.0 |
373 | | **/ |
374 | | const char *gnutls_group_get_name(gnutls_group_t group) |
375 | 0 | { |
376 | 0 | GNUTLS_GROUP_LOOP(if (p->id == group) { return p->name; }); |
377 | |
|
378 | 0 | return NULL; |
379 | 0 | } |
380 | | |
381 | | /* Expand GROUP into hybrid SUBGROUPS if any, otherwise an array |
382 | | * containing the GROUP itself. The result will be written to |
383 | | * SUBGROUPS, which will be NUL-terminated. |
384 | | */ |
385 | | int _gnutls_group_expand( |
386 | | const gnutls_group_entry_st *group, |
387 | | const gnutls_group_entry_st *subgroups[MAX_HYBRID_GROUPS + 1]) |
388 | 0 | { |
389 | 0 | size_t pos = 0; |
390 | |
|
391 | 0 | if (IS_GROUP_HYBRID(group)) { |
392 | 0 | for (size_t i = 0; i < MAX_HYBRID_GROUPS && |
393 | 0 | group->ids[i] != GNUTLS_GROUP_INVALID; |
394 | 0 | i++) { |
395 | 0 | const gnutls_group_entry_st *p = |
396 | 0 | group_to_entry(group->ids[i]); |
397 | | /* This shouldn't happen, as GROUP is assumed |
398 | | * to be supported before calling this |
399 | | * function. */ |
400 | 0 | if (unlikely(!p)) |
401 | 0 | return gnutls_assert_val( |
402 | 0 | GNUTLS_E_INTERNAL_ERROR); |
403 | 0 | subgroups[pos++] = p; |
404 | 0 | } |
405 | 0 | } else { |
406 | 0 | subgroups[pos++] = group; |
407 | 0 | } |
408 | 0 | subgroups[pos] = NULL; |
409 | 0 | return 0; |
410 | 0 | } |