Coverage Report

Created: 2025-03-18 06:55

/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
}