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