Tizen 2.0 Release
[external/libgnutls26.git] / lib / crypto.c
1 /*
2  * Copyright (C) 2008, 2010 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
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21  * USA
22  *
23  */
24
25 #include <gnutls_errors.h>
26 #include <gnutls_int.h>
27 #include <gnutls/crypto.h>
28 #include <crypto.h>
29 #include <gnutls_mpi.h>
30 #include <gnutls_pk.h>
31 #include <random.h>
32 #include <gnutls_cipher_int.h>
33
34 /* default values for priorities */
35 int crypto_mac_prio = INT_MAX;
36 int crypto_digest_prio = INT_MAX;
37 int crypto_cipher_prio = INT_MAX;
38
39 typedef struct algo_list
40 {
41   int algorithm;
42   int priority;
43   const void *alg_data;
44   struct algo_list *next;
45 } algo_list;
46
47 #define cipher_list algo_list
48 #define mac_list algo_list
49 #define digest_list algo_list
50
51 static int
52 _algo_register (algo_list * al, int algorithm, int priority, const void *s)
53 {
54   algo_list *cl;
55   algo_list *last_cl = al;
56
57   /* look if there is any cipher with lowest priority. In that case do not add.
58    */
59   cl = al;
60   while (cl && cl->alg_data)
61     {
62       if (cl->algorithm == algorithm)
63         {
64           if (cl->priority < priority)
65             {
66               gnutls_assert ();
67               return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
68             }
69           else
70             {
71               /* the current has higher priority -> overwrite */
72               cl->algorithm = algorithm;
73               cl->priority = priority;
74               cl->alg_data = s;
75               return 0;
76             }
77         }
78       cl = cl->next;
79       if (cl)
80         last_cl = cl;
81     }
82
83   cl = gnutls_calloc (1, sizeof (cipher_list));
84
85   if (cl == NULL)
86     {
87       gnutls_assert ();
88       return GNUTLS_E_MEMORY_ERROR;
89     }
90
91   last_cl->algorithm = algorithm;
92   last_cl->priority = priority;
93   last_cl->alg_data = s;
94   last_cl->next = cl;
95
96   return 0;
97
98 }
99
100 static const void *
101 _get_algo (algo_list * al, int algo)
102 {
103   cipher_list *cl;
104
105   /* look if there is any cipher with lowest priority. In that case do not add.
106    */
107   cl = al;
108   while (cl && cl->alg_data)
109     {
110       if (cl->algorithm == algo)
111         {
112           return cl->alg_data;
113         }
114       cl = cl->next;
115     }
116
117   return NULL;
118 }
119
120 static cipher_list glob_cl = { GNUTLS_CIPHER_NULL, 0, NULL, NULL };
121 static mac_list glob_ml = { GNUTLS_MAC_NULL, 0, NULL, NULL };
122 static digest_list glob_dl = { GNUTLS_MAC_NULL, 0, NULL, NULL };
123
124 static void
125 _deregister (algo_list * cl)
126 {
127   algo_list *next;
128
129   next = cl->next;
130   cl->next = NULL;
131   cl = next;
132
133   while (cl)
134     {
135       next = cl->next;
136       gnutls_free (cl);
137       cl = next;
138     }
139 }
140
141 void
142 _gnutls_crypto_deregister (void)
143 {
144   _deregister (&glob_cl);
145   _deregister (&glob_ml);
146   _deregister (&glob_dl);
147 }
148
149 /**
150  * gnutls_crypto_single_cipher_register2:
151  * @algorithm: is the gnutls algorithm identifier
152  * @priority: is the priority of the algorithm
153  * @version: should be set to %GNUTLS_CRYPTO_API_VERSION
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.  The algorithm with the lowest priority will be
160  * used by gnutls.
161  *
162  * This function should be called before gnutls_global_init().
163  *
164  * For simplicity you can use the convenience
165  * gnutls_crypto_single_cipher_register() macro.
166  *
167  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
168  *
169  * Since: 2.6.0
170  **/
171 int
172 gnutls_crypto_single_cipher_register2 (gnutls_cipher_algorithm_t algorithm,
173                                        int priority, int version,
174                                        const gnutls_crypto_cipher_st * s)
175 {
176   if (version != GNUTLS_CRYPTO_API_VERSION)
177     {
178       gnutls_assert ();
179       return GNUTLS_E_UNIMPLEMENTED_FEATURE;
180     }
181
182   return _algo_register (&glob_cl, algorithm, priority, s);
183 }
184
185 const gnutls_crypto_cipher_st *
186 _gnutls_get_crypto_cipher (gnutls_cipher_algorithm_t algo)
187 {
188   return _get_algo (&glob_cl, algo);
189 }
190
191 /**
192  * gnutls_crypto_rnd_register2:
193  * @priority: is the priority of the generator
194  * @version: should be set to %GNUTLS_CRYPTO_API_VERSION
195  * @s: is a structure holding new generator's data
196  *
197  * This function will register a random generator to be used by
198  * gnutls.  Any generator registered will override the included
199  * generator and by convention kernel implemented generators have
200  * priority of 90.  The generator with the lowest priority will be
201  * used by gnutls.
202  *
203  * This function should be called before gnutls_global_init().
204  *
205  * For simplicity you can use the convenience
206  * gnutls_crypto_rnd_register() macro.
207  *
208  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
209  *
210  * Since: 2.6.0
211  **/
212 int
213 gnutls_crypto_rnd_register2 (int priority, int version,
214                              const gnutls_crypto_rnd_st * s)
215 {
216   if (version != GNUTLS_CRYPTO_API_VERSION)
217     {
218       gnutls_assert ();
219       return GNUTLS_E_UNIMPLEMENTED_FEATURE;
220     }
221
222   if (crypto_rnd_prio > priority)
223     {
224       memcpy (&_gnutls_rnd_ops, s, sizeof (*s));
225       crypto_rnd_prio = priority;
226       return 0;
227     }
228
229   return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
230 }
231
232 /**
233  * gnutls_crypto_single_mac_register2:
234  * @algorithm: is the gnutls algorithm identifier
235  * @priority: is the priority of the algorithm
236  * @version: should be set to %GNUTLS_CRYPTO_API_VERSION
237  * @s: is a structure holding new algorithms's data
238  *
239  * This function will register a MAC algorithm to be used by gnutls.
240  * Any algorithm registered will override the included algorithms and
241  * by convention kernel implemented algorithms have priority of 90.
242  * The algorithm with the lowest priority will be used by gnutls.
243  *
244  * This function should be called before gnutls_global_init().
245  *
246  * For simplicity you can use the convenience
247  * gnutls_crypto_single_mac_register() macro.
248  *
249  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
250  *
251  * Since: 2.6.0
252  **/
253 int
254 gnutls_crypto_single_mac_register2 (gnutls_mac_algorithm_t algorithm,
255                                     int priority, int version,
256                                     const gnutls_crypto_mac_st * s)
257 {
258   if (version != GNUTLS_CRYPTO_API_VERSION)
259     {
260       gnutls_assert ();
261       return GNUTLS_E_UNIMPLEMENTED_FEATURE;
262     }
263
264   return _algo_register (&glob_ml, algorithm, priority, s);
265 }
266
267 const gnutls_crypto_mac_st *
268 _gnutls_get_crypto_mac (gnutls_mac_algorithm_t algo)
269 {
270   return _get_algo (&glob_ml, algo);
271 }
272
273 /**
274  * gnutls_crypto_single_digest_register2:
275  * @algorithm: is the gnutls algorithm identifier
276  * @priority: is the priority of the algorithm
277  * @version: should be set to %GNUTLS_CRYPTO_API_VERSION
278  * @s: is a structure holding new algorithms's data
279  *
280  * This function will register a digest (hash) algorithm to be used by
281  * gnutls.  Any algorithm registered will override the included
282  * algorithms and by convention kernel implemented algorithms have
283  * priority of 90.  The algorithm with the lowest priority will be
284  * used by gnutls.
285  *
286  * This function should be called before gnutls_global_init().
287  *
288  * For simplicity you can use the convenience
289  * gnutls_crypto_single_digest_register() macro.
290  *
291  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
292  *
293  * Since: 2.6.0
294  **/
295 int
296 gnutls_crypto_single_digest_register2 (gnutls_digest_algorithm_t algorithm,
297                                        int priority, int version,
298                                        const gnutls_crypto_digest_st * s)
299 {
300   if (version != GNUTLS_CRYPTO_API_VERSION)
301     {
302       gnutls_assert ();
303       return GNUTLS_E_UNIMPLEMENTED_FEATURE;
304     }
305
306   return _algo_register (&glob_dl, algorithm, priority, s);
307 }
308
309 const gnutls_crypto_digest_st *
310 _gnutls_get_crypto_digest (gnutls_digest_algorithm_t algo)
311 {
312   return _get_algo (&glob_dl, algo);
313 }
314
315 /**
316  * gnutls_crypto_bigint_register2:
317  * @priority: is the priority of the interface
318  * @version: should be set to %GNUTLS_CRYPTO_API_VERSION
319  * @s: is a structure holding new interface's data
320  *
321  * This function will register an interface for gnutls to operate
322  * on big integers. Any interface registered will override
323  * the included interface. The interface with the lowest
324  * priority will be used by gnutls.
325  *
326  * Note that the bigint interface must interoperate with the public
327  * key interface. Thus if this interface is updated the
328  * gnutls_crypto_pk_register() should also be used.
329  *
330  * This function should be called before gnutls_global_init().
331  *
332  * For simplicity you can use the convenience gnutls_crypto_bigint_register()
333  * macro.
334  *
335  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
336  *
337  * Since: 2.6.0
338  **/
339 int
340 gnutls_crypto_bigint_register2 (int priority, int version,
341                                 const gnutls_crypto_bigint_st * s)
342 {
343   if (version != GNUTLS_CRYPTO_API_VERSION)
344     {
345       gnutls_assert ();
346       return GNUTLS_E_UNIMPLEMENTED_FEATURE;
347     }
348
349   if (crypto_bigint_prio > priority)
350     {
351       memcpy (&_gnutls_mpi_ops, s, sizeof (*s));
352       crypto_bigint_prio = priority;
353       return 0;
354     }
355
356   return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
357 }
358
359 /**
360  * gnutls_crypto_pk_register2:
361  * @priority: is the priority of the interface
362  * @version: should be set to %GNUTLS_CRYPTO_API_VERSION
363  * @s: is a structure holding new interface's data
364  *
365  * This function will register an interface for gnutls to operate
366  * on public key operations. Any interface registered will override
367  * the included interface. The interface with the lowest
368  * priority will be used by gnutls.
369  *
370  * Note that the bigint interface must interoperate with the bigint
371  * interface. Thus if this interface is updated the
372  * gnutls_crypto_bigint_register() should also be used.
373  *
374  * This function should be called before gnutls_global_init().
375  *
376  * For simplicity you can use the convenience gnutls_crypto_pk_register()
377  * macro.
378  *
379  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
380  *
381  * Since: 2.6.0
382  **/
383 int
384 gnutls_crypto_pk_register2 (int priority, int version,
385                             const gnutls_crypto_pk_st * s)
386 {
387   if (version != GNUTLS_CRYPTO_API_VERSION)
388     {
389       gnutls_assert ();
390       return GNUTLS_E_UNIMPLEMENTED_FEATURE;
391     }
392
393   if (crypto_pk_prio > priority)
394     {
395       memcpy (&_gnutls_pk_ops, s, sizeof (*s));
396       crypto_pk_prio = priority;
397       return 0;
398     }
399
400   return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
401 }
402
403 /**
404  * gnutls_crypto_cipher_register2:
405  * @priority: is the priority of the cipher interface
406  * @version: should be set to %GNUTLS_CRYPTO_API_VERSION
407  * @s: is a structure holding new interface's data
408  *
409  * This function will register a cipher interface to be used by
410  * gnutls. Any interface registered will override the included engine
411  * and by convention kernel implemented interfaces should have
412  * priority of 90. The interface with the lowest priority will be used
413  * by gnutls.
414  *
415  * This function should be called before gnutls_global_init().
416  *
417  * For simplicity you can use the convenience
418  * gnutls_crypto_cipher_register() macro.
419  *
420  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
421  *
422  * Since: 2.6.0
423  **/
424 int
425 gnutls_crypto_cipher_register2 (int priority, int version,
426                                 const gnutls_crypto_cipher_st * s)
427 {
428   if (version != GNUTLS_CRYPTO_API_VERSION)
429     {
430       gnutls_assert ();
431       return GNUTLS_E_UNIMPLEMENTED_FEATURE;
432     }
433
434   if (crypto_cipher_prio > priority)
435     {
436       memcpy (&_gnutls_cipher_ops, s, sizeof (*s));
437       crypto_cipher_prio = priority;
438       return 0;
439     }
440
441   return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
442 }
443
444 /**
445  * gnutls_crypto_mac_register2:
446  * @priority: is the priority of the mac interface
447  * @version: should be set to %GNUTLS_CRYPTO_API_VERSION
448  * @s: is a structure holding new interface's data
449  *
450  * This function will register a mac interface to be used by
451  * gnutls. Any interface registered will override the included engine
452  * and by convention kernel implemented interfaces should have
453  * priority of 90. The interface with the lowest priority will be used
454  * by gnutls.
455  *
456  * This function should be called before gnutls_global_init().
457  *
458  * For simplicity you can use the convenience
459  * gnutls_crypto_digest_register() macro.
460  *
461  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
462  *
463  * Since: 2.6.0
464  **/
465 int
466 gnutls_crypto_mac_register2 (int priority, int version,
467                              const gnutls_crypto_mac_st * s)
468 {
469   if (version != GNUTLS_CRYPTO_API_VERSION)
470     {
471       gnutls_assert ();
472       return GNUTLS_E_UNIMPLEMENTED_FEATURE;
473     }
474
475   if (crypto_mac_prio > priority)
476     {
477       memcpy (&_gnutls_mac_ops, s, sizeof (*s));
478       crypto_mac_prio = priority;
479       return 0;
480     }
481
482   return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
483 }
484
485 /**
486  * gnutls_crypto_digest_register2:
487  * @priority: is the priority of the digest interface
488  * @version: should be set to %GNUTLS_CRYPTO_API_VERSION
489  * @s: is a structure holding new interface's data
490  *
491  * This function will register a digest interface to be used by
492  * gnutls. Any interface registered will override the included engine
493  * and by convention kernel implemented interfaces should have
494  * priority of 90. The interface with the lowest priority will be used
495  * by gnutls.
496  *
497  * This function should be called before gnutls_global_init().
498  *
499  * For simplicity you can use the convenience
500  * gnutls_crypto_digest_register() macro.
501  *
502  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
503  *
504  * Since: 2.6.0
505  **/
506 int
507 gnutls_crypto_digest_register2 (int priority, int version,
508                                 const gnutls_crypto_digest_st * s)
509 {
510   if (version != GNUTLS_CRYPTO_API_VERSION)
511     {
512       gnutls_assert ();
513       return GNUTLS_E_UNIMPLEMENTED_FEATURE;
514     }
515
516   if (crypto_digest_prio > priority)
517     {
518       memcpy (&_gnutls_digest_ops, s, sizeof (*s));
519       crypto_digest_prio = priority;
520       return 0;
521     }
522
523   return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
524 }