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