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