1 /*
2  * Copyright (C) 2008-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 "errors.h"
24 #include "gnutls_int.h"
25 #include <gnutls/crypto.h>
26 #include <crypto-backend.h>
27 #include <crypto.h>
28 #include <mpi.h>
29 #include <pk.h>
30 #include <random.h>
31 #include <cipher_int.h>
32 
33 /* default values for priorities */
34 int crypto_mac_prio = INT_MAX;
35 int crypto_digest_prio = INT_MAX;
36 int crypto_cipher_prio = INT_MAX;
37 
38 typedef struct algo_list {
39 	int algorithm;
40 	int priority;
41 	void *alg_data;
42 	int free_alg_data;
43 	struct algo_list *next;
44 } algo_list;
45 
46 #define cipher_list algo_list
47 #define mac_list algo_list
48 #define digest_list algo_list
49 
50 static int
_algo_register(algo_list * al,int algorithm,int priority,void * s,int free_s)51 _algo_register(algo_list * al, int algorithm, int priority, void *s, int free_s)
52 {
53 	algo_list *cl;
54 	algo_list *last_cl = al;
55 	int ret;
56 
57 	if (al == NULL) {
58 		ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
59 		goto cleanup;
60 	}
61 
62 	/* look if there is any cipher with lowest priority. In that case do not add.
63 	 */
64 	cl = al;
65 	while (cl && cl->alg_data) {
66 		if (cl->algorithm == algorithm) {
67 			if (cl->priority < priority) {
68 				gnutls_assert();
69 				ret = GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
70 				goto cleanup;
71 			} else {
72 				/* the current has higher priority -> overwrite */
73 				cl->algorithm = algorithm;
74 				cl->priority = priority;
75 				cl->alg_data = s;
76 				cl->free_alg_data = free_s;
77 				return 0;
78 			}
79 		}
80 		cl = cl->next;
81 		if (cl)
82 			last_cl = cl;
83 	}
84 
85 	cl = gnutls_calloc(1, sizeof(cipher_list));
86 
87 	if (cl == NULL) {
88 		gnutls_assert();
89 		ret = GNUTLS_E_MEMORY_ERROR;
90 		goto cleanup;
91 	}
92 
93 	last_cl->algorithm = algorithm;
94 	last_cl->priority = priority;
95 	last_cl->alg_data = s;
96 	last_cl->free_alg_data = free_s;
97 	last_cl->next = cl;
98 
99 	return 0;
100  cleanup:
101 	if (free_s) gnutls_free(s);
102 	return ret;
103 }
104 
_get_algo(algo_list * al,int algo)105 static const void *_get_algo(algo_list * al, int algo)
106 {
107 	cipher_list *cl;
108 
109 	/* look if there is any cipher with lowest priority. In that case do not add.
110 	 */
111 	cl = al;
112 	while (cl && cl->alg_data) {
113 		if (cl->algorithm == algo) {
114 			return cl->alg_data;
115 		}
116 		cl = cl->next;
117 	}
118 
119 	return NULL;
120 }
121 
122 static cipher_list glob_cl = { GNUTLS_CIPHER_NULL, 0, NULL, 0, NULL };
123 static mac_list glob_ml = { GNUTLS_MAC_NULL, 0, NULL, 0, NULL };
124 static digest_list glob_dl = { GNUTLS_MAC_NULL, 0, NULL, 0, NULL };
125 
_deregister(algo_list * cl)126 static void _deregister(algo_list * cl)
127 {
128 	algo_list *next;
129 
130 	next = cl->next;
131 	cl->next = NULL;
132 	cl = next;
133 
134 	while (cl) {
135 		next = cl->next;
136 		if (cl->free_alg_data)
137 			gnutls_free(cl->alg_data);
138 		gnutls_free(cl);
139 		cl = next;
140 	}
141 }
142 
_gnutls_crypto_deregister(void)143 void _gnutls_crypto_deregister(void)
144 {
145 	_deregister(&glob_cl);
146 	_deregister(&glob_ml);
147 	_deregister(&glob_dl);
148 }
149 
150 /*-
151  * gnutls_crypto_single_cipher_register:
152  * @algorithm: is the gnutls algorithm identifier
153  * @priority: is the priority of the algorithm
154  * @s: is a structure holding new cipher's data
155  *
156  * This function will register a cipher algorithm to be used by
157  * gnutls.  Any algorithm registered will override the included
158  * algorithms and by convention kernel implemented algorithms have
159  * priority of 90 and CPU-assisted of 80.  The algorithm with the lowest priority will be
160  * used by gnutls.
161  *
162  * In the case the registered init or setkey functions return %GNUTLS_E_NEED_FALLBACK,
163  * GnuTLS will attempt to use the next in priority registered cipher.
164  *
165  * This function should be called before gnutls_global_init().
166  *
167  * For simplicity you can use the convenience
168  * gnutls_crypto_single_cipher_register() macro.
169  *
170  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
171  *
172  * Since: 2.6.0
173  -*/
174 int
gnutls_crypto_single_cipher_register(gnutls_cipher_algorithm_t algorithm,int priority,const gnutls_crypto_cipher_st * s,int free_s)175 gnutls_crypto_single_cipher_register(gnutls_cipher_algorithm_t algorithm,
176 				     int priority,
177 				     const gnutls_crypto_cipher_st * s,
178 				     int free_s)
179 {
180 	/* we override const in case free_s is set */
181 	return _algo_register(&glob_cl, algorithm, priority, (void*)s, free_s);
182 }
183 
184 const gnutls_crypto_cipher_st
_gnutls_get_crypto_cipher(gnutls_cipher_algorithm_t algo)185     *_gnutls_get_crypto_cipher(gnutls_cipher_algorithm_t algo)
186 {
187 	return _get_algo(&glob_cl, algo);
188 }
189 
190 /**
191  * gnutls_crypto_register_cipher:
192  * @algorithm: is the gnutls algorithm identifier
193  * @priority: is the priority of the algorithm
194  * @init: A function which initializes the cipher
195  * @setkey: A function which sets the key of the cipher
196  * @setiv: A function which sets the nonce/IV of the cipher (non-AEAD)
197  * @encrypt: A function which performs encryption (non-AEAD)
198  * @decrypt: A function which performs decryption (non-AEAD)
199  * @deinit: A function which deinitializes the cipher
200  *
201  * This function will register a cipher algorithm to be used by
202  * gnutls.  Any algorithm registered will override the included
203  * algorithms and by convention kernel implemented algorithms have
204  * priority of 90 and CPU-assisted of 80.  The algorithm with the lowest priority will be
205  * used by gnutls.
206  *
207  * In the case the registered init or setkey functions return %GNUTLS_E_NEED_FALLBACK,
208  * GnuTLS will attempt to use the next in priority registered cipher.
209  *
210  * The functions which are marked as non-AEAD they are not required when
211  * registering a cipher to be used with the new AEAD API introduced in
212  * GnuTLS 3.4.0. Internally GnuTLS uses the new AEAD API.
213  *
214  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
215  *
216  * Since: 3.4.0
217  **/
218 int
gnutls_crypto_register_cipher(gnutls_cipher_algorithm_t algorithm,int priority,gnutls_cipher_init_func init,gnutls_cipher_setkey_func setkey,gnutls_cipher_setiv_func setiv,gnutls_cipher_encrypt_func encrypt,gnutls_cipher_decrypt_func decrypt,gnutls_cipher_deinit_func deinit)219 gnutls_crypto_register_cipher(gnutls_cipher_algorithm_t algorithm,
220 			      int priority,
221 			      gnutls_cipher_init_func init,
222 			      gnutls_cipher_setkey_func setkey,
223 			      gnutls_cipher_setiv_func setiv,
224 			      gnutls_cipher_encrypt_func encrypt,
225 			      gnutls_cipher_decrypt_func decrypt,
226 			      gnutls_cipher_deinit_func deinit)
227 {
228 	gnutls_crypto_cipher_st *s = gnutls_calloc(1, sizeof(gnutls_crypto_cipher_st));
229 	if (s == NULL)
230 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
231 
232 	s->init = init;
233 	s->setkey = setkey;
234 	s->setiv = setiv;
235 	s->encrypt = encrypt;
236 	s->decrypt = decrypt;
237 	s->deinit = deinit;
238 
239 	return gnutls_crypto_single_cipher_register(algorithm, priority, s, 1);
240 }
241 
242 /**
243  * gnutls_crypto_register_aead_cipher:
244  * @algorithm: is the gnutls AEAD cipher identifier
245  * @priority: is the priority of the algorithm
246  * @init: A function which initializes the cipher
247  * @setkey: A function which sets the key of the cipher
248  * @aead_encrypt: Perform the AEAD encryption
249  * @aead_decrypt: Perform the AEAD decryption
250  * @deinit: A function which deinitializes the cipher
251  *
252  * This function will register a cipher algorithm to be used by
253  * gnutls.  Any algorithm registered will override the included
254  * algorithms and by convention kernel implemented algorithms have
255  * priority of 90 and CPU-assisted of 80.  The algorithm with the lowest priority will be
256  * used by gnutls.
257  *
258  * In the case the registered init or setkey functions return %GNUTLS_E_NEED_FALLBACK,
259  * GnuTLS will attempt to use the next in priority registered cipher.
260  *
261  * The functions registered will be used with the new AEAD API introduced in
262  * GnuTLS 3.4.0. Internally GnuTLS uses the new AEAD API.
263  *
264  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
265  *
266  * Since: 3.4.0
267  **/
268 int
gnutls_crypto_register_aead_cipher(gnutls_cipher_algorithm_t algorithm,int priority,gnutls_cipher_init_func init,gnutls_cipher_setkey_func setkey,gnutls_cipher_aead_encrypt_func aead_encrypt,gnutls_cipher_aead_decrypt_func aead_decrypt,gnutls_cipher_deinit_func deinit)269 gnutls_crypto_register_aead_cipher(gnutls_cipher_algorithm_t algorithm,
270 			      int priority,
271 			      gnutls_cipher_init_func init,
272 			      gnutls_cipher_setkey_func setkey,
273 			      gnutls_cipher_aead_encrypt_func aead_encrypt,
274 			      gnutls_cipher_aead_decrypt_func aead_decrypt,
275 			      gnutls_cipher_deinit_func deinit)
276 {
277 	gnutls_crypto_cipher_st *s = gnutls_calloc(1, sizeof(gnutls_crypto_cipher_st));
278 	if (s == NULL)
279 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
280 
281 	s->init = init;
282 	s->setkey = setkey;
283 	s->aead_encrypt = aead_encrypt;
284 	s->aead_decrypt = aead_decrypt;
285 	s->deinit = deinit;
286 
287 	return gnutls_crypto_single_cipher_register(algorithm, priority, s, 1);
288 }
289 
290 /*-
291  * gnutls_crypto_rnd_register:
292  * @priority: is the priority of the generator
293  * @s: is a structure holding new generator's data
294  *
295  * This function will register a random generator to be used by
296  * gnutls.  Any generator registered will override the included
297  * generator and by convention kernel implemented generators have
298  * priority of 90 and CPU-assisted of 80. The generator with the lowest priority will be
299  * used by gnutls.
300  *
301  * This function should be called before gnutls_global_init().
302  *
303  * For simplicity you can use the convenience
304  * gnutls_crypto_rnd_register() macro.
305  *
306  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
307  *
308  * Since: 2.6.0
309  -*/
310 int
gnutls_crypto_rnd_register(int priority,const gnutls_crypto_rnd_st * s)311 gnutls_crypto_rnd_register(int priority, const gnutls_crypto_rnd_st * s)
312 {
313 	if (crypto_rnd_prio >= priority) {
314 		memcpy(&_gnutls_rnd_ops, s, sizeof(*s));
315 		crypto_rnd_prio = priority;
316 		return 0;
317 	}
318 
319 	return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
320 }
321 
322 /*-
323  * gnutls_crypto_single_mac_register:
324  * @algorithm: is the gnutls algorithm identifier
325  * @priority: is the priority of the algorithm
326  * @s: is a structure holding new algorithms's data
327  *
328  * This function will register a MAC algorithm to be used by gnutls.
329  * Any algorithm registered will override the included algorithms and
330  * by convention kernel implemented algorithms have priority of 90
331  *  and CPU-assisted of 80.
332  * The algorithm with the lowest priority will be used by gnutls.
333  *
334  * This function should be called before gnutls_global_init().
335  *
336  * For simplicity you can use the convenience
337  * gnutls_crypto_single_mac_register() macro.
338  *
339  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
340  *
341  * Since: 2.6.0
342  -*/
343 int
gnutls_crypto_single_mac_register(gnutls_mac_algorithm_t algorithm,int priority,const gnutls_crypto_mac_st * s,int free_s)344 gnutls_crypto_single_mac_register(gnutls_mac_algorithm_t algorithm,
345 				  int priority,
346 				  const gnutls_crypto_mac_st * s,
347 				  int free_s)
348 {
349 	return _algo_register(&glob_ml, algorithm, priority, (void*)s, free_s);
350 }
351 
_gnutls_get_crypto_mac(gnutls_mac_algorithm_t algo)352 const gnutls_crypto_mac_st *_gnutls_get_crypto_mac(gnutls_mac_algorithm_t
353 						   algo)
354 {
355 	return _get_algo(&glob_ml, algo);
356 }
357 
358 /*-
359  * gnutls_crypto_single_digest_register:
360  * @algorithm: is the gnutls algorithm identifier
361  * @priority: is the priority of the algorithm
362  * @s: is a structure holding new algorithms's data
363  *
364  * This function will register a digest (hash) algorithm to be used by
365  * gnutls.  Any algorithm registered will override the included
366  * algorithms and by convention kernel implemented algorithms have
367  * priority of 90  and CPU-assisted of 80.  The algorithm with the lowest priority will be
368  * used by gnutls.
369  *
370  * This function should be called before gnutls_global_init().
371  *
372  * For simplicity you can use the convenience
373  * gnutls_crypto_single_digest_register() macro.
374  *
375  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
376  *
377  * Since: 2.6.0
378  -*/
379 int
gnutls_crypto_single_digest_register(gnutls_digest_algorithm_t algorithm,int priority,const gnutls_crypto_digest_st * s,int free_s)380 gnutls_crypto_single_digest_register(gnutls_digest_algorithm_t algorithm,
381 				     int priority,
382 				     const gnutls_crypto_digest_st * s,
383 				     int free_s)
384 {
385 	return _algo_register(&glob_dl, algorithm, priority, (void*)s, free_s);
386 }
387 
388 const gnutls_crypto_digest_st
_gnutls_get_crypto_digest(gnutls_digest_algorithm_t algo)389     *_gnutls_get_crypto_digest(gnutls_digest_algorithm_t algo)
390 {
391 	return _get_algo(&glob_dl, algo);
392 }
393 
394 /**
395  * gnutls_crypto_register_mac:
396  * @algorithm: is the gnutls MAC identifier
397  * @priority: is the priority of the algorithm
398  * @init: A function which initializes the MAC
399  * @setkey: A function which sets the key of the MAC
400  * @setnonce: A function which sets the nonce for the mac (may be %NULL for common MAC algorithms)
401  * @hash: Perform the hash operation
402  * @output: Provide the output of the MAC
403  * @deinit: A function which deinitializes the MAC
404  * @hash_fast: Perform the MAC operation in one go
405  *
406  * This function will register a MAC algorithm to be used by gnutls.
407  * Any algorithm registered will override the included algorithms and
408  * by convention kernel implemented algorithms have priority of 90
409  *  and CPU-assisted of 80.
410  * The algorithm with the lowest priority will be used by gnutls.
411  *
412  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
413  *
414  * Since: 3.4.0
415  **/
416 int
gnutls_crypto_register_mac(gnutls_mac_algorithm_t algorithm,int priority,gnutls_mac_init_func init,gnutls_mac_setkey_func setkey,gnutls_mac_setnonce_func setnonce,gnutls_mac_hash_func hash,gnutls_mac_output_func output,gnutls_mac_deinit_func deinit,gnutls_mac_fast_func hash_fast)417 gnutls_crypto_register_mac(gnutls_mac_algorithm_t algorithm,
418 			   int priority,
419 			   gnutls_mac_init_func init,
420 			   gnutls_mac_setkey_func setkey,
421 			   gnutls_mac_setnonce_func setnonce,
422 			   gnutls_mac_hash_func hash,
423 			   gnutls_mac_output_func output,
424 			   gnutls_mac_deinit_func deinit,
425 			   gnutls_mac_fast_func hash_fast)
426 {
427 	gnutls_crypto_mac_st *s = gnutls_calloc(1, sizeof(gnutls_crypto_mac_st));
428 	if (s == NULL)
429 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
430 
431 	s->init = init;
432 	s->setkey = setkey;
433 	s->setnonce = setnonce;
434 	s->hash = hash;
435 	s->output = output;
436 	s->fast = hash_fast;
437 	s->deinit = deinit;
438 
439 	return gnutls_crypto_single_mac_register(algorithm, priority, s, 1);
440 }
441 
442 /**
443  * gnutls_crypto_register_digest:
444  * @algorithm: is the gnutls digest identifier
445  * @priority: is the priority of the algorithm
446  * @init: A function which initializes the digest
447  * @hash: Perform the hash operation
448  * @output: Provide the output of the digest
449  * @deinit: A function which deinitializes the digest
450  * @hash_fast: Perform the digest operation in one go
451  *
452  * This function will register a digest algorithm to be used by gnutls.
453  * Any algorithm registered will override the included algorithms and
454  * by convention kernel implemented algorithms have priority of 90
455  *  and CPU-assisted of 80.
456  * The algorithm with the lowest priority will be used by gnutls.
457  *
458  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
459  *
460  * Since: 3.4.0
461  **/
462 int
gnutls_crypto_register_digest(gnutls_digest_algorithm_t algorithm,int priority,gnutls_digest_init_func init,gnutls_digest_hash_func hash,gnutls_digest_output_func output,gnutls_digest_deinit_func deinit,gnutls_digest_fast_func hash_fast)463 gnutls_crypto_register_digest(gnutls_digest_algorithm_t algorithm,
464 			   int priority,
465 			   gnutls_digest_init_func init,
466 			   gnutls_digest_hash_func hash,
467 			   gnutls_digest_output_func output,
468 			   gnutls_digest_deinit_func deinit,
469 			   gnutls_digest_fast_func hash_fast)
470 {
471 	gnutls_crypto_digest_st *s = gnutls_calloc(1, sizeof(gnutls_crypto_digest_st));
472 	if (s == NULL)
473 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
474 
475 	s->init = init;
476 	s->hash = hash;
477 	s->output = output;
478 	s->fast = hash_fast;
479 	s->deinit = deinit;
480 
481 	return gnutls_crypto_single_digest_register(algorithm, priority, s, 1);
482 }
483