Line data Source code
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
51 94653 : _algo_register(algo_list * al, int algorithm, int priority, void *s, int free_s)
52 : {
53 94653 : algo_list *cl;
54 94653 : algo_list *last_cl = al;
55 94653 : int ret;
56 :
57 94653 : if (al == NULL) {
58 0 : ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
59 0 : 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 436027 : while (cl && cl->alg_data) {
66 361673 : if (cl->algorithm == algorithm) {
67 20299 : if (cl->priority < priority) {
68 9 : gnutls_assert();
69 9 : ret = GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
70 9 : goto cleanup;
71 : } else {
72 : /* the current has higher priority -> overwrite */
73 20290 : cl->algorithm = algorithm;
74 20290 : cl->priority = priority;
75 20290 : cl->alg_data = s;
76 20290 : cl->free_alg_data = free_s;
77 20290 : return 0;
78 : }
79 : }
80 341374 : cl = cl->next;
81 341374 : if (cl)
82 341359 : last_cl = cl;
83 : }
84 :
85 74354 : cl = gnutls_calloc(1, sizeof(cipher_list));
86 :
87 74354 : if (cl == NULL) {
88 0 : gnutls_assert();
89 0 : ret = GNUTLS_E_MEMORY_ERROR;
90 0 : goto cleanup;
91 : }
92 :
93 74354 : last_cl->algorithm = algorithm;
94 74354 : last_cl->priority = priority;
95 74354 : last_cl->alg_data = s;
96 74354 : last_cl->free_alg_data = free_s;
97 74354 : last_cl->next = cl;
98 :
99 74354 : return 0;
100 9 : cleanup:
101 9 : if (free_s) gnutls_free(s);
102 : return ret;
103 : }
104 :
105 1115250 : static const void *_get_algo(algo_list * al, int algo)
106 : {
107 1115250 : cipher_list *cl;
108 :
109 : /* look if there is any cipher with lowest priority. In that case do not add.
110 : */
111 1115250 : cl = al;
112 2425000 : while (cl && cl->alg_data) {
113 2345050 : if (cl->algorithm == algo) {
114 : return cl->alg_data;
115 : }
116 1309750 : 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 :
126 6564 : static void _deregister(algo_list * cl)
127 : {
128 6564 : algo_list *next;
129 :
130 6564 : next = cl->next;
131 6564 : cl->next = NULL;
132 6564 : cl = next;
133 :
134 54452 : while (cl) {
135 47888 : next = cl->next;
136 47888 : if (cl->free_alg_data)
137 5 : gnutls_free(cl->alg_data);
138 47888 : gnutls_free(cl);
139 47888 : cl = next;
140 : }
141 6564 : }
142 :
143 2188 : void _gnutls_crypto_deregister(void)
144 : {
145 2188 : _deregister(&glob_cl);
146 2188 : _deregister(&glob_ml);
147 2188 : _deregister(&glob_dl);
148 2188 : }
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
175 60849 : 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 60849 : return _algo_register(&glob_cl, algorithm, priority, (void*)s, free_s);
182 : }
183 :
184 : const gnutls_crypto_cipher_st
185 92197 : *_gnutls_get_crypto_cipher(gnutls_cipher_algorithm_t algo)
186 : {
187 92197 : 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
219 6 : 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 6 : gnutls_crypto_cipher_st *s = gnutls_calloc(1, sizeof(gnutls_crypto_cipher_st));
229 6 : if (s == NULL)
230 0 : return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
231 :
232 6 : s->init = init;
233 6 : s->setkey = setkey;
234 6 : s->setiv = setiv;
235 6 : s->encrypt = encrypt;
236 6 : s->decrypt = decrypt;
237 6 : s->deinit = deinit;
238 :
239 6 : 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
269 3 : 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 3 : gnutls_crypto_cipher_st *s = gnutls_calloc(1, sizeof(gnutls_crypto_cipher_st));
278 3 : if (s == NULL)
279 0 : return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
280 :
281 3 : s->init = init;
282 3 : s->setkey = setkey;
283 3 : s->aead_encrypt = aead_encrypt;
284 3 : s->aead_decrypt = aead_decrypt;
285 3 : s->deinit = deinit;
286 :
287 3 : 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
311 0 : gnutls_crypto_rnd_register(int priority, const gnutls_crypto_rnd_st * s)
312 : {
313 0 : if (crypto_rnd_prio >= priority) {
314 0 : memcpy(&_gnutls_rnd_ops, s, sizeof(*s));
315 0 : crypto_rnd_prio = priority;
316 0 : 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
344 16902 : 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 16902 : return _algo_register(&glob_ml, algorithm, priority, (void*)s, free_s);
350 : }
351 :
352 53115 : const gnutls_crypto_mac_st *_gnutls_get_crypto_mac(gnutls_mac_algorithm_t
353 : algo)
354 : {
355 53115 : 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
380 16902 : 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 16902 : return _algo_register(&glob_dl, algorithm, priority, (void*)s, free_s);
386 : }
387 :
388 : const gnutls_crypto_digest_st
389 969936 : *_gnutls_get_crypto_digest(gnutls_digest_algorithm_t algo)
390 : {
391 969936 : 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
417 2 : 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 2 : gnutls_crypto_mac_st *s = gnutls_calloc(1, sizeof(gnutls_crypto_mac_st));
428 2 : if (s == NULL)
429 0 : return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
430 :
431 2 : s->init = init;
432 2 : s->setkey = setkey;
433 2 : s->setnonce = setnonce;
434 2 : s->hash = hash;
435 2 : s->output = output;
436 2 : s->fast = hash_fast;
437 2 : s->deinit = deinit;
438 :
439 2 : 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
463 2 : 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 2 : gnutls_crypto_digest_st *s = gnutls_calloc(1, sizeof(gnutls_crypto_digest_st));
472 2 : if (s == NULL)
473 0 : return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
474 :
475 2 : s->init = init;
476 2 : s->hash = hash;
477 2 : s->output = output;
478 2 : s->fast = hash_fast;
479 2 : s->deinit = deinit;
480 :
481 2 : return gnutls_crypto_single_digest_register(algorithm, priority, s, 1);
482 : }
|