Coverage Report

Created: 2023-03-26 08:33

/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
  { const gnutls_ecc_curve_entry_st *p; \
266
0
    for(p = ecc_curves; p->name != NULL; p++) { b ; } }
267
268
/**
269
 * gnutls_ecc_curve_list:
270
 *
271
 * Get the list of supported elliptic curves.
272
 *
273
 * This function is not thread safe.
274
 *
275
 * Returns: Return a (0)-terminated list of #gnutls_ecc_curve_t
276
 *   integers indicating the available curves.
277
 **/
278
const gnutls_ecc_curve_t *gnutls_ecc_curve_list(void)
279
0
{
280
0
  static gnutls_ecc_curve_t supported_curves[MAX_ALGOS] = { 0 };
281
282
0
  if (supported_curves[0] == 0) {
283
0
    int i = 0;
284
285
0
    GNUTLS_ECC_CURVE_LOOP(if
286
0
              (p->supported
287
0
               && _gnutls_pk_curve_exists(p->id))
288
0
              supported_curves[i++] = p->id;) ;
289
0
    supported_curves[i++] = 0;
290
0
  }
291
292
0
  return supported_curves;
293
0
}
294
295
unsigned _gnutls_ecc_curve_is_supported(gnutls_ecc_curve_t curve)
296
0
{
297
0
  GNUTLS_ECC_CURVE_LOOP(if
298
0
            (p->id == curve && p->supported
299
0
             && _gnutls_pk_curve_exists(p->id))
300
0
            return 1;) ;
301
0
  return 0;
302
0
}
303
304
/**
305
 * gnutls_oid_to_ecc_curve:
306
 * @oid: is a curve's OID
307
 *
308
 * Returns: return a #gnutls_ecc_curve_t value corresponding to
309
 *   the specified OID, or %GNUTLS_ECC_CURVE_INVALID on error.
310
 *
311
 * Since: 3.4.3
312
 **/
313
gnutls_ecc_curve_t gnutls_oid_to_ecc_curve(const char *oid)
314
0
{
315
0
  gnutls_ecc_curve_t ret = GNUTLS_ECC_CURVE_INVALID;
316
317
0
  GNUTLS_ECC_CURVE_LOOP(if
318
0
            (p->oid != NULL && c_strcasecmp(p->oid, oid) == 0
319
0
             && p->supported
320
0
             && _gnutls_pk_curve_exists(p->id)) {
321
0
            ret = p->id; break;}
322
0
  ) ;
323
324
0
  return ret;
325
0
}
326
327
/**
328
 * gnutls_ecc_curve_get_id:
329
 * @name: is a curve name
330
 *
331
 * The names are compared in a case insensitive way.
332
 *
333
 * Returns: return a #gnutls_ecc_curve_t value corresponding to
334
 *   the specified curve, or %GNUTLS_ECC_CURVE_INVALID on error.
335
 *
336
 * Since: 3.4.3
337
 **/
338
gnutls_ecc_curve_t gnutls_ecc_curve_get_id(const char *name)
339
0
{
340
0
  gnutls_ecc_curve_t ret = GNUTLS_ECC_CURVE_INVALID;
341
342
0
  GNUTLS_ECC_CURVE_LOOP(if
343
0
            (c_strcasecmp(p->name, name) == 0 && p->supported
344
0
             && _gnutls_pk_curve_exists(p->id)) {
345
0
            ret = p->id; break;}
346
0
  ) ;
347
348
0
  return ret;
349
0
}
350
351
/* This is only called by cfg_apply in priority.c, in blocklisting mode. */
352
int _gnutls_ecc_curve_mark_disabled(gnutls_ecc_curve_t curve)
353
0
{
354
0
  gnutls_ecc_curve_entry_st *p;
355
356
0
  for (p = ecc_curves; p->name != NULL; p++) {
357
0
    if (p->id == curve) {
358
0
      p->supported = false;
359
0
      return 0;
360
0
    }
361
0
  }
362
363
0
  return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
364
0
}
365
366
/* This is only called by cfg_apply in priority.c, in allowlisting mode. */
367
void _gnutls_ecc_curve_mark_disabled_all(void)
368
0
{
369
0
  gnutls_ecc_curve_entry_st *p;
370
371
0
  for (p = ecc_curves; p->name != NULL; p++) {
372
0
    p->supported = false;
373
0
    p->supported_revertible = true;
374
0
  }
375
0
}
376
377
int
378
_gnutls_ecc_curve_set_enabled(gnutls_ecc_curve_t curve, unsigned int enabled)
379
0
{
380
0
  gnutls_ecc_curve_entry_st *p;
381
382
0
  for (p = ecc_curves; p->name != NULL; p++) {
383
0
    if (p->id == curve) {
384
0
      if (!p->supported_revertible) {
385
0
        return
386
0
            gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
387
0
      }
388
0
      p->supported = enabled;
389
0
      return 0;
390
0
    }
391
0
  }
392
393
0
  return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
394
0
}
395
396
static int _gnutls_ecc_pk_compatible(const gnutls_ecc_curve_entry_st * p,
397
             gnutls_pk_algorithm_t pk)
398
0
{
399
0
  if (!p->supported || !_gnutls_pk_curve_exists(p->id))
400
0
    return 0;
401
402
0
  if (pk == GNUTLS_PK_GOST_01 || pk == GNUTLS_PK_GOST_12_256)
403
0
    return p->gost_curve && p->size == 32;
404
405
0
  return pk == p->pk;
406
0
}
407
408
/*-
409
 * _gnutls_ecc_bits_to_curve:
410
 * @bits: is a security parameter in bits
411
 *
412
 * Returns: return a #gnutls_ecc_curve_t value corresponding to
413
 *   the specified bit length, or %GNUTLS_ECC_CURVE_INVALID on error.
414
 -*/
415
gnutls_ecc_curve_t _gnutls_ecc_bits_to_curve(gnutls_pk_algorithm_t pk, int bits)
416
0
{
417
0
  gnutls_ecc_curve_t ret;
418
419
0
  if (pk == GNUTLS_PK_ECDSA)
420
0
    ret = GNUTLS_ECC_CURVE_SECP256R1;
421
0
  else if (pk == GNUTLS_PK_GOST_01 || pk == GNUTLS_PK_GOST_12_256)
422
0
    ret = GNUTLS_ECC_CURVE_GOST256CPA;
423
0
  else if (pk == GNUTLS_PK_GOST_12_512)
424
0
    ret = GNUTLS_ECC_CURVE_GOST512A;
425
0
  else
426
0
    ret = GNUTLS_ECC_CURVE_ED25519;
427
428
0
  GNUTLS_ECC_CURVE_LOOP(if (_gnutls_ecc_pk_compatible(p, pk)
429
0
          && 8 * p->size >= (unsigned)bits) {
430
0
            ret = p->id; break;}
431
0
  ) ;
432
433
0
  return ret;
434
0
}
435
436
/**
437
 * gnutls_ecc_curve_get_name:
438
 * @curve: is an ECC curve
439
 *
440
 * Convert a #gnutls_ecc_curve_t value to a string.
441
 *
442
 * Returns: a string that contains the name of the specified
443
 *   curve or %NULL.
444
 *
445
 * Since: 3.0
446
 **/
447
const char *gnutls_ecc_curve_get_name(gnutls_ecc_curve_t curve)
448
0
{
449
0
  const char *ret = NULL;
450
451
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve) {
452
0
            ret = p->name; break;}
453
0
  ) ;
454
455
0
  return ret;
456
0
}
457
458
/**
459
 * gnutls_ecc_curve_get_oid:
460
 * @curve: is an ECC curve
461
 *
462
 * Convert a #gnutls_ecc_curve_t value to its object identifier.
463
 *
464
 * Returns: a string that contains the OID of the specified
465
 *   curve or %NULL.
466
 *
467
 * Since: 3.4.3
468
 **/
469
const char *gnutls_ecc_curve_get_oid(gnutls_ecc_curve_t curve)
470
0
{
471
0
  const char *ret = NULL;
472
473
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve) {
474
0
            ret = p->oid; break;}
475
0
  ) ;
476
477
0
  return ret;
478
0
}
479
480
/*-
481
 * _gnutls_ecc_curve_get_params:
482
 * @curve: is an ECC curve
483
 *
484
 * Returns the information on a curve.
485
 *
486
 * Returns: a pointer to #gnutls_ecc_curve_entry_st or %NULL.
487
 -*/
488
const gnutls_ecc_curve_entry_st
489
    * _gnutls_ecc_curve_get_params(gnutls_ecc_curve_t curve)
490
0
{
491
0
  const gnutls_ecc_curve_entry_st *ret = NULL;
492
493
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve) {
494
0
            ret = p; break;}
495
0
  ) ;
496
497
0
  return ret;
498
0
}
499
500
/**
501
 * gnutls_ecc_curve_get_size:
502
 * @curve: is an ECC curve
503
 *
504
 * Returns: the size in bytes of the curve or 0 on failure.
505
 *
506
 * Since: 3.0
507
 **/
508
int gnutls_ecc_curve_get_size(gnutls_ecc_curve_t curve)
509
0
{
510
0
  int ret = 0;
511
512
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve) {
513
0
            ret = p->size; break;}
514
0
  ) ;
515
516
0
  return ret;
517
0
}
518
519
/**
520
 * gnutls_ecc_curve_get_pk:
521
 * @curve: is an ECC curve
522
 *
523
 * Returns: the public key algorithm associated with the named curve or %GNUTLS_PK_UNKNOWN.
524
 *
525
 * Since: 3.5.0
526
 **/
527
gnutls_pk_algorithm_t gnutls_ecc_curve_get_pk(gnutls_ecc_curve_t curve)
528
0
{
529
0
  int ret = GNUTLS_PK_UNKNOWN;
530
531
0
  GNUTLS_ECC_CURVE_LOOP(if (p->id == curve && p->supported) {
532
0
            ret = p->pk; break;}
533
0
  ) ;
534
535
0
  return ret;
536
0
}
537
538
/**
539
 * _gnutls_ecc_curve_get_group:
540
 * @curve: is an ECC curve
541
 *
542
 * Returns: the group associated with the named curve or %GNUTLS_GROUP_INVALID.
543
 *
544
 * Since: 3.6.11
545
 */
546
gnutls_group_t _gnutls_ecc_curve_get_group(gnutls_ecc_curve_t curve)
547
0
{
548
0
  gnutls_group_t ret = GNUTLS_GROUP_INVALID;
549
550
0
  GNUTLS_ECC_CURVE_LOOP(if
551
0
            (p->id == curve && p->supported
552
0
             && _gnutls_pk_curve_exists(p->id)) {
553
0
            ret = p->group; break;}
554
0
  ) ;
555
556
0
  return ret;
557
0
}