Coverage Report

Created: 2024-06-20 06:28

/src/gnutls/lib/algorithms/ecc.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2011-2012 Free Software Foundation, 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 SYSTEM_CONFIG_OR_CONST gnutls_ecc_curve_entry_st ecc_curves[] = {
34
#ifdef ENABLE_NON_SUITEB_CURVES
35
  {
36
    .name = "SECP192R1",
37
    .oid = "1.2.840.10045.3.1.1",
38
    .id = GNUTLS_ECC_CURVE_SECP192R1,
39
    .group = GNUTLS_GROUP_SECP192R1,
40
    .pk = GNUTLS_PK_ECDSA,
41
    .size = 24,
42
    .supported = 1,
43
  },
44
  {
45
    .name = "SECP224R1",
46
    .oid = "1.3.132.0.33",
47
    .id = GNUTLS_ECC_CURVE_SECP224R1,
48
    .group = GNUTLS_GROUP_SECP224R1,
49
    .pk = GNUTLS_PK_ECDSA,
50
    .size = 28,
51
    .supported = 1,
52
  },
53
#endif
54
  {
55
    .name = "SECP256R1",
56
    .oid = "1.2.840.10045.3.1.7",
57
    .id = GNUTLS_ECC_CURVE_SECP256R1,
58
    .group = GNUTLS_GROUP_SECP256R1,
59
    .pk = GNUTLS_PK_ECDSA,
60
    .size = 32,
61
    .supported = 1,
62
  },
63
  {
64
    .name = "SECP384R1",
65
    .oid = "1.3.132.0.34",
66
    .id = GNUTLS_ECC_CURVE_SECP384R1,
67
    .group = GNUTLS_GROUP_SECP384R1,
68
    .pk = GNUTLS_PK_ECDSA,
69
    .size = 48,
70
    .supported = 1,
71
  },
72
  {
73
    .name = "SECP521R1",
74
    .oid = "1.3.132.0.35",
75
    .id = GNUTLS_ECC_CURVE_SECP521R1,
76
    .group = GNUTLS_GROUP_SECP521R1,
77
    .pk = GNUTLS_PK_ECDSA,
78
    .size = 66,
79
    .supported = 1,
80
  },
81
  {
82
    .name = "X25519",
83
    .oid = ECDH_X25519_OID,
84
    .id = GNUTLS_ECC_CURVE_X25519,
85
    .group = GNUTLS_GROUP_X25519,
86
    .pk = GNUTLS_PK_ECDH_X25519,
87
    .size = 32,
88
    .supported = 1,
89
  },
90
  {
91
    .name = "Ed25519",
92
    .oid = SIG_EDDSA_SHA512_OID,
93
    .id = GNUTLS_ECC_CURVE_ED25519,
94
    .pk = GNUTLS_PK_EDDSA_ED25519,
95
    .size = 32,
96
    .sig_size = 64,
97
    .supported = 1,
98
  },
99
  {
100
    .name = "X448",
101
    .oid = ECDH_X448_OID,
102
    .id = GNUTLS_ECC_CURVE_X448,
103
    .pk = GNUTLS_PK_ECDH_X448,
104
    .size = 56,
105
    .supported = 1,
106
  },
107
  {
108
    .name = "Ed448",
109
    .oid = SIG_ED448_OID,
110
    .id = GNUTLS_ECC_CURVE_ED448,
111
    .pk = GNUTLS_PK_EDDSA_ED448,
112
    .size = 57,
113
    .sig_size = 114,
114
    .supported = 1,
115
  },
116
#if ENABLE_GOST
117
  /* Curves for usage in GOST digital signature algorithm (GOST R
118
   * 34.10-2001/-2012) and key agreement (VKO GOST R 34.10-2001/-2012).
119
   *
120
   * Historically CryptoPro has defined three 256-bit curves for use with
121
   * digital signature algorithm (CryptoPro-A, -B, -C).
122
   *
123
   * Also it has reissues two of them with different OIDs for key
124
   * exchange (CryptoPro-XchA = CryptoPro-A and CryptoPro-XchB =
125
   * CryptoPro-C).
126
   *
127
   * Then TC26 (Standard committee working on cryptographic standards) has
128
   * defined one 256-bit curve (TC26-256-A) and three 512-bit curves
129
   * (TC26-512-A, -B, -C).
130
   *
131
   * And finally TC26 has reissues original CryptoPro curves under their
132
   * own OID namespace (TC26-256-B = CryptoPro-A, TC26-256-C =
133
   * CryptoPro-B and TC26-256-D = CryptoPro-C).
134
   *
135
   * CryptoPro OIDs are usable for both GOST R 34.10-2001 and
136
   * GOST R 34.10-2012 keys (thus they have GNUTLS_PK_UNKNOWN in this
137
   * table).
138
   * TC26 OIDs are usable only for GOST R 34.10-2012 keys.
139
   */
140
  {
141
    .name = "CryptoPro-A",
142
    .oid = "1.2.643.2.2.35.1",
143
    .id = GNUTLS_ECC_CURVE_GOST256CPA,
144
    .group = GNUTLS_GROUP_GC256B,
145
    .pk = GNUTLS_PK_UNKNOWN,
146
    .size = 32,
147
    .gost_curve = 1,
148
    .supported = 1,
149
  },
150
  {
151
    .name = "CryptoPro-B",
152
    .oid = "1.2.643.2.2.35.2",
153
    .id = GNUTLS_ECC_CURVE_GOST256CPB,
154
    .group = GNUTLS_GROUP_GC256C,
155
    .pk = GNUTLS_PK_UNKNOWN,
156
    .size = 32,
157
    .gost_curve = 1,
158
    .supported = 1,
159
  },
160
  {
161
    .name = "CryptoPro-C",
162
    .oid = "1.2.643.2.2.35.3",
163
    .id = GNUTLS_ECC_CURVE_GOST256CPC,
164
    .group = GNUTLS_GROUP_GC256D,
165
    .pk = GNUTLS_PK_UNKNOWN,
166
    .size = 32,
167
    .gost_curve = 1,
168
    .supported = 1,
169
  },
170
  {
171
    .name = "CryptoPro-XchA",
172
    .oid = "1.2.643.2.2.36.0",
173
    .id = GNUTLS_ECC_CURVE_GOST256CPXA,
174
    .group = GNUTLS_GROUP_GC256B,
175
    .pk = GNUTLS_PK_UNKNOWN,
176
    .size = 32,
177
    .gost_curve = 1,
178
    .supported = 1,
179
  },
180
  {
181
    .name = "CryptoPro-XchB",
182
    .oid = "1.2.643.2.2.36.1",
183
    .id = GNUTLS_ECC_CURVE_GOST256CPXB,
184
    .group = GNUTLS_GROUP_GC256D,
185
    .pk = GNUTLS_PK_UNKNOWN,
186
    .size = 32,
187
    .gost_curve = 1,
188
    .supported = 1,
189
  },
190
  {
191
    .name = "TC26-256-A",
192
    .oid = "1.2.643.7.1.2.1.1.1",
193
    .id = GNUTLS_ECC_CURVE_GOST256A,
194
    .group = GNUTLS_GROUP_GC256A,
195
    .pk = GNUTLS_PK_GOST_12_256,
196
    .size = 32,
197
    .gost_curve = 1,
198
    .supported = 1,
199
  },
200
  {
201
    .name = "TC26-256-B",
202
    .oid = "1.2.643.7.1.2.1.1.2",
203
    .id = GNUTLS_ECC_CURVE_GOST256B,
204
    .group = GNUTLS_GROUP_GC256B,
205
    .pk = GNUTLS_PK_GOST_12_256,
206
    .size = 32,
207
    .gost_curve = 1,
208
    .supported = 1,
209
  },
210
  {
211
    .name = "TC26-256-C",
212
    .oid = "1.2.643.7.1.2.1.1.3",
213
    .id = GNUTLS_ECC_CURVE_GOST256C,
214
    .group = GNUTLS_GROUP_GC256C,
215
    .pk = GNUTLS_PK_GOST_12_256,
216
    .size = 32,
217
    .gost_curve = 1,
218
    .supported = 1,
219
  },
220
  {
221
    .name = "TC26-256-D",
222
    .oid = "1.2.643.7.1.2.1.1.4",
223
    .id = GNUTLS_ECC_CURVE_GOST256D,
224
    .group = GNUTLS_GROUP_GC256D,
225
    .pk = GNUTLS_PK_GOST_12_256,
226
    .size = 32,
227
    .gost_curve = 1,
228
    .supported = 1,
229
  },
230
  {
231
    .name = "TC26-512-A",
232
    .oid = "1.2.643.7.1.2.1.2.1",
233
    .id = GNUTLS_ECC_CURVE_GOST512A,
234
    .group = GNUTLS_GROUP_GC512A,
235
    .pk = GNUTLS_PK_GOST_12_512,
236
    .size = 64,
237
    .gost_curve = 1,
238
    .supported = 1,
239
  },
240
  {
241
    .name = "TC26-512-B",
242
    .oid = "1.2.643.7.1.2.1.2.2",
243
    .id = GNUTLS_ECC_CURVE_GOST512B,
244
    .group = GNUTLS_GROUP_GC512B,
245
    .pk = GNUTLS_PK_GOST_12_512,
246
    .size = 64,
247
    .gost_curve = 1,
248
    .supported = 1,
249
  },
250
  {
251
    .name = "TC26-512-C",
252
    .oid = "1.2.643.7.1.2.1.2.3",
253
    .id = GNUTLS_ECC_CURVE_GOST512C,
254
    .group = GNUTLS_GROUP_GC512C,
255
    .pk = GNUTLS_PK_GOST_12_512,
256
    .size = 64,
257
    .gost_curve = 1,
258
    .supported = 1,
259
  },
260
#endif
261
  { 0, 0, 0 }
262
};
263
264
#define GNUTLS_ECC_CURVE_LOOP(b)                             \
265
0
  {                                                    \
266
0
    const gnutls_ecc_curve_entry_st *p;          \
267
0
    for (p = ecc_curves; p->name != NULL; p++) { \
268
0
      b;                                   \
269
0
    }                                            \
270
0
  }
271
272
/**
273
 * gnutls_ecc_curve_list:
274
 *
275
 * Get the list of supported elliptic curves.
276
 *
277
 * This function is not thread safe.
278
 *
279
 * Returns: Return a (0)-terminated list of #gnutls_ecc_curve_t
280
 *   integers indicating the available curves.
281
 **/
282
const gnutls_ecc_curve_t *gnutls_ecc_curve_list(void)
283
0
{
284
0
  static gnutls_ecc_curve_t supported_curves[MAX_ALGOS] = { 0 };
285
286
0
  if (supported_curves[0] == 0) {
287
0
    int i = 0;
288
289
0
    GNUTLS_ECC_CURVE_LOOP(
290
0
      if (p->supported && _gnutls_pk_curve_exists(p->id))
291
0
        supported_curves[i++] = p->id;);
292
0
    supported_curves[i++] = 0;
293
0
  }
294
295
0
  return supported_curves;
296
0
}
297
298
unsigned _gnutls_ecc_curve_is_supported(gnutls_ecc_curve_t curve)
299
0
{
300
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve && p->supported &&
301
0
          _gnutls_pk_curve_exists(p->id)) return 1;);
302
0
  return 0;
303
0
}
304
305
/**
306
 * gnutls_oid_to_ecc_curve:
307
 * @oid: is a curve's OID
308
 *
309
 * Returns: return a #gnutls_ecc_curve_t value corresponding to
310
 *   the specified OID, or %GNUTLS_ECC_CURVE_INVALID on error.
311
 *
312
 * Since: 3.4.3
313
 **/
314
gnutls_ecc_curve_t gnutls_oid_to_ecc_curve(const char *oid)
315
0
{
316
0
  gnutls_ecc_curve_t ret = GNUTLS_ECC_CURVE_INVALID;
317
318
0
  GNUTLS_ECC_CURVE_LOOP(
319
0
    if (p->oid != NULL && c_strcasecmp(p->oid, oid) == 0 &&
320
0
        p->supported && _gnutls_pk_curve_exists(p->id)) {
321
0
      ret = p->id;
322
0
      break;
323
0
    });
324
325
0
  return ret;
326
0
}
327
328
/**
329
 * gnutls_ecc_curve_get_id:
330
 * @name: is a curve name
331
 *
332
 * The names are compared in a case insensitive way.
333
 *
334
 * Returns: return a #gnutls_ecc_curve_t value corresponding to
335
 *   the specified curve, or %GNUTLS_ECC_CURVE_INVALID on error.
336
 *
337
 * Since: 3.4.3
338
 **/
339
gnutls_ecc_curve_t gnutls_ecc_curve_get_id(const char *name)
340
0
{
341
0
  gnutls_ecc_curve_t ret = GNUTLS_ECC_CURVE_INVALID;
342
343
0
  GNUTLS_ECC_CURVE_LOOP(if (c_strcasecmp(p->name, name) == 0 &&
344
0
          p->supported &&
345
0
          _gnutls_pk_curve_exists(p->id)) {
346
0
    ret = p->id;
347
0
    break;
348
0
  });
349
350
0
  return ret;
351
0
}
352
353
/* This is only called by cfg_apply in priority.c, in blocklisting mode. */
354
int _gnutls_ecc_curve_mark_disabled(gnutls_ecc_curve_t curve)
355
0
{
356
0
  gnutls_ecc_curve_entry_st *p;
357
358
0
  for (p = ecc_curves; p->name != NULL; p++) {
359
0
    if (p->id == curve) {
360
0
      p->supported = false;
361
0
      return 0;
362
0
    }
363
0
  }
364
365
0
  return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
366
0
}
367
368
/* This is only called by cfg_apply in priority.c, in allowlisting mode. */
369
void _gnutls_ecc_curve_mark_disabled_all(void)
370
0
{
371
0
  gnutls_ecc_curve_entry_st *p;
372
373
0
  for (p = ecc_curves; p->name != NULL; p++) {
374
0
    p->supported = false;
375
0
    p->supported_revertible = true;
376
0
  }
377
0
}
378
379
int _gnutls_ecc_curve_set_enabled(gnutls_ecc_curve_t curve,
380
          unsigned int enabled)
381
0
{
382
0
  gnutls_ecc_curve_entry_st *p;
383
384
0
  for (p = ecc_curves; p->name != NULL; p++) {
385
0
    if (p->id == curve) {
386
0
      if (!p->supported_revertible) {
387
0
        return gnutls_assert_val(
388
0
          GNUTLS_E_INVALID_REQUEST);
389
0
      }
390
0
      p->supported = enabled;
391
0
      return 0;
392
0
    }
393
0
  }
394
395
0
  return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
396
0
}
397
398
static int _gnutls_ecc_pk_compatible(const gnutls_ecc_curve_entry_st *p,
399
             gnutls_pk_algorithm_t pk)
400
0
{
401
0
  if (!p->supported || !_gnutls_pk_curve_exists(p->id))
402
0
    return 0;
403
404
0
  if (pk == GNUTLS_PK_GOST_01 || pk == GNUTLS_PK_GOST_12_256)
405
0
    return p->gost_curve && p->size == 32;
406
407
0
  return pk == p->pk;
408
0
}
409
410
/*-
411
 * _gnutls_ecc_bits_to_curve:
412
 * @bits: is a security parameter in bits
413
 *
414
 * Returns: return a #gnutls_ecc_curve_t value corresponding to
415
 *   the specified bit length, or %GNUTLS_ECC_CURVE_INVALID on error.
416
 -*/
417
gnutls_ecc_curve_t _gnutls_ecc_bits_to_curve(gnutls_pk_algorithm_t pk, int bits)
418
0
{
419
0
  gnutls_ecc_curve_t ret;
420
421
0
  if (pk == GNUTLS_PK_ECDSA)
422
0
    ret = GNUTLS_ECC_CURVE_SECP256R1;
423
0
  else if (pk == GNUTLS_PK_GOST_01 || pk == GNUTLS_PK_GOST_12_256)
424
0
    ret = GNUTLS_ECC_CURVE_GOST256CPA;
425
0
  else if (pk == GNUTLS_PK_GOST_12_512)
426
0
    ret = GNUTLS_ECC_CURVE_GOST512A;
427
0
  else
428
0
    ret = GNUTLS_ECC_CURVE_ED25519;
429
430
0
  GNUTLS_ECC_CURVE_LOOP(if (_gnutls_ecc_pk_compatible(p, pk) &&
431
0
          8 * p->size >= (unsigned)bits) {
432
0
    ret = p->id;
433
0
    break;
434
0
  });
435
436
0
  return ret;
437
0
}
438
439
/**
440
 * gnutls_ecc_curve_get_name:
441
 * @curve: is an ECC curve
442
 *
443
 * Convert a #gnutls_ecc_curve_t value to a string.
444
 *
445
 * Returns: a string that contains the name of the specified
446
 *   curve or %NULL.
447
 *
448
 * Since: 3.0
449
 **/
450
const char *gnutls_ecc_curve_get_name(gnutls_ecc_curve_t curve)
451
0
{
452
0
  const char *ret = NULL;
453
454
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve) {
455
0
    ret = p->name;
456
0
    break;
457
0
  });
458
459
0
  return ret;
460
0
}
461
462
/**
463
 * gnutls_ecc_curve_get_oid:
464
 * @curve: is an ECC curve
465
 *
466
 * Convert a #gnutls_ecc_curve_t value to its object identifier.
467
 *
468
 * Returns: a string that contains the OID of the specified
469
 *   curve or %NULL.
470
 *
471
 * Since: 3.4.3
472
 **/
473
const char *gnutls_ecc_curve_get_oid(gnutls_ecc_curve_t curve)
474
0
{
475
0
  const char *ret = NULL;
476
477
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve) {
478
0
    ret = p->oid;
479
0
    break;
480
0
  });
481
482
0
  return ret;
483
0
}
484
485
/*-
486
 * _gnutls_ecc_curve_get_params:
487
 * @curve: is an ECC curve
488
 *
489
 * Returns the information on a curve.
490
 *
491
 * Returns: a pointer to #gnutls_ecc_curve_entry_st or %NULL.
492
 -*/
493
const gnutls_ecc_curve_entry_st *
494
_gnutls_ecc_curve_get_params(gnutls_ecc_curve_t curve)
495
0
{
496
0
  const gnutls_ecc_curve_entry_st *ret = NULL;
497
498
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve) {
499
0
    ret = p;
500
0
    break;
501
0
  });
502
503
0
  return ret;
504
0
}
505
506
/**
507
 * gnutls_ecc_curve_get_size:
508
 * @curve: is an ECC curve
509
 *
510
 * Returns: the size in bytes of the curve or 0 on failure.
511
 *
512
 * Since: 3.0
513
 **/
514
int gnutls_ecc_curve_get_size(gnutls_ecc_curve_t curve)
515
0
{
516
0
  int ret = 0;
517
518
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve) {
519
0
    ret = p->size;
520
0
    break;
521
0
  });
522
523
0
  return ret;
524
0
}
525
526
/**
527
 * gnutls_ecc_curve_get_pk:
528
 * @curve: is an ECC curve
529
 *
530
 * Returns: the public key algorithm associated with the named curve or %GNUTLS_PK_UNKNOWN.
531
 *
532
 * Since: 3.5.0
533
 **/
534
gnutls_pk_algorithm_t gnutls_ecc_curve_get_pk(gnutls_ecc_curve_t curve)
535
0
{
536
0
  int ret = GNUTLS_PK_UNKNOWN;
537
538
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve && p->supported) {
539
0
    ret = p->pk;
540
0
    break;
541
0
  });
542
543
0
  return ret;
544
0
}
545
546
/**
547
 * _gnutls_ecc_curve_get_group:
548
 * @curve: is an ECC curve
549
 *
550
 * Returns: the group associated with the named curve or %GNUTLS_GROUP_INVALID.
551
 *
552
 * Since: 3.6.11
553
 */
554
gnutls_group_t _gnutls_ecc_curve_get_group(gnutls_ecc_curve_t curve)
555
0
{
556
0
  gnutls_group_t ret = GNUTLS_GROUP_INVALID;
557
558
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve && p->supported &&
559
0
          _gnutls_pk_curve_exists(p->id)) {
560
0
    ret = p->group;
561
0
    break;
562
0
  });
563
564
0
  return ret;
565
0
}