/*
* Copyright (C) 2008-2012 Free Software Foundation, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GnuTLS.
*
* The GnuTLS is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* default values for priorities */
int crypto_mac_prio = INT_MAX;
int crypto_digest_prio = INT_MAX;
int crypto_cipher_prio = INT_MAX;
typedef struct algo_list
{
int algorithm;
int priority;
const void *alg_data;
struct algo_list *next;
} algo_list;
#define cipher_list algo_list
#define mac_list algo_list
#define digest_list algo_list
static int
_algo_register (algo_list * al, int algorithm, int priority, const void *s)
{
algo_list *cl;
algo_list *last_cl = al;
if (al == NULL)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
/* look if there is any cipher with lowest priority. In that case do not add.
*/
cl = al;
while (cl && cl->alg_data)
{
if (cl->algorithm == algorithm)
{
if (cl->priority < priority)
{
gnutls_assert ();
return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
}
else
{
/* the current has higher priority -> overwrite */
cl->algorithm = algorithm;
cl->priority = priority;
cl->alg_data = s;
return 0;
}
}
cl = cl->next;
if (cl)
last_cl = cl;
}
cl = gnutls_calloc (1, sizeof (cipher_list));
if (cl == NULL)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
last_cl->algorithm = algorithm;
last_cl->priority = priority;
last_cl->alg_data = s;
last_cl->next = cl;
return 0;
}
static const void *
_get_algo (algo_list * al, int algo)
{
cipher_list *cl;
/* look if there is any cipher with lowest priority. In that case do not add.
*/
cl = al;
while (cl && cl->alg_data)
{
if (cl->algorithm == algo)
{
return cl->alg_data;
}
cl = cl->next;
}
return NULL;
}
static cipher_list glob_cl = { GNUTLS_CIPHER_NULL, 0, NULL, NULL };
static mac_list glob_ml = { GNUTLS_MAC_NULL, 0, NULL, NULL };
static digest_list glob_dl = { GNUTLS_MAC_NULL, 0, NULL, NULL };
static void
_deregister (algo_list * cl)
{
algo_list *next;
next = cl->next;
cl->next = NULL;
cl = next;
while (cl)
{
next = cl->next;
gnutls_free (cl);
cl = next;
}
}
void
_gnutls_crypto_deregister (void)
{
_deregister (&glob_cl);
_deregister (&glob_ml);
_deregister (&glob_dl);
}
/*-
* gnutls_crypto_single_cipher_register:
* @algorithm: is the gnutls algorithm identifier
* @priority: is the priority of the algorithm
* @s: is a structure holding new cipher's data
*
* This function will register a cipher algorithm to be used by
* gnutls. Any algorithm registered will override the included
* algorithms and by convention kernel implemented algorithms have
* priority of 90 and CPU-assisted of 80. The algorithm with the lowest priority will be
* used by gnutls.
*
* This function should be called before gnutls_global_init().
*
* For simplicity you can use the convenience
* gnutls_crypto_single_cipher_register() macro.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
* Since: 2.6.0
-*/
int
gnutls_crypto_single_cipher_register (gnutls_cipher_algorithm_t algorithm,
int priority,
const gnutls_crypto_cipher_st * s)
{
return _algo_register (&glob_cl, algorithm, priority, s);
}
const gnutls_crypto_cipher_st *
_gnutls_get_crypto_cipher (gnutls_cipher_algorithm_t algo)
{
return _get_algo (&glob_cl, algo);
}
/*-
* gnutls_crypto_rnd_register:
* @priority: is the priority of the generator
* @s: is a structure holding new generator's data
*
* This function will register a random generator to be used by
* gnutls. Any generator registered will override the included
* generator and by convention kernel implemented generators have
* priority of 90 and CPU-assisted of 80. The generator with the lowest priority will be
* used by gnutls.
*
* This function should be called before gnutls_global_init().
*
* For simplicity you can use the convenience
* gnutls_crypto_rnd_register() macro.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
* Since: 2.6.0
-*/
int
gnutls_crypto_rnd_register (int priority,
const gnutls_crypto_rnd_st * s)
{
if (crypto_rnd_prio > priority)
{
memcpy (&_gnutls_rnd_ops, s, sizeof (*s));
crypto_rnd_prio = priority;
return 0;
}
return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
}
/*-
* gnutls_crypto_single_mac_register:
* @algorithm: is the gnutls algorithm identifier
* @priority: is the priority of the algorithm
* @s: is a structure holding new algorithms's data
*
* This function will register a MAC algorithm to be used by gnutls.
* Any algorithm registered will override the included algorithms and
* by convention kernel implemented algorithms have priority of 90
* and CPU-assisted of 80.
* The algorithm with the lowest priority will be used by gnutls.
*
* This function should be called before gnutls_global_init().
*
* For simplicity you can use the convenience
* gnutls_crypto_single_mac_register() macro.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
* Since: 2.6.0
-*/
int
gnutls_crypto_single_mac_register (gnutls_mac_algorithm_t algorithm,
int priority,
const gnutls_crypto_mac_st * s)
{
return _algo_register (&glob_ml, algorithm, priority, s);
}
const gnutls_crypto_mac_st *
_gnutls_get_crypto_mac (gnutls_mac_algorithm_t algo)
{
return _get_algo (&glob_ml, algo);
}
/*-
* gnutls_crypto_single_digest_register:
* @algorithm: is the gnutls algorithm identifier
* @priority: is the priority of the algorithm
* @s: is a structure holding new algorithms's data
*
* This function will register a digest (hash) algorithm to be used by
* gnutls. Any algorithm registered will override the included
* algorithms and by convention kernel implemented algorithms have
* priority of 90 and CPU-assisted of 80. The algorithm with the lowest priority will be
* used by gnutls.
*
* This function should be called before gnutls_global_init().
*
* For simplicity you can use the convenience
* gnutls_crypto_single_digest_register() macro.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
* Since: 2.6.0
-*/
int
gnutls_crypto_single_digest_register (gnutls_digest_algorithm_t algorithm,
int priority,
const gnutls_crypto_digest_st * s)
{
return _algo_register (&glob_dl, algorithm, priority, s);
}
const gnutls_crypto_digest_st *
_gnutls_get_crypto_digest (gnutls_digest_algorithm_t algo)
{
return _get_algo (&glob_dl, algo);
}
/*-
* gnutls_crypto_bigint_register:
* @priority: is the priority of the interface
* @s: is a structure holding new interface's data
*
* This function will register an interface for gnutls to operate
* on big integers. Any interface registered will override
* the included interface. The interface with the lowest
* priority will be used by gnutls.
*
* Note that the bigint interface must interoperate with the public
* key interface. Thus if this interface is updated the
* gnutls_crypto_pk_register() should also be used.
*
* This function should be called before gnutls_global_init().
*
* For simplicity you can use the convenience gnutls_crypto_bigint_register()
* macro.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
* Since: 2.6.0
-*/
int
gnutls_crypto_bigint_register (int priority,
const gnutls_crypto_bigint_st * s)
{
if (crypto_bigint_prio > priority)
{
memcpy (&_gnutls_mpi_ops, s, sizeof (*s));
crypto_bigint_prio = priority;
return 0;
}
return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
}
/*-
* gnutls_crypto_pk_register:
* @priority: is the priority of the interface
* @s: is a structure holding new interface's data
*
* This function will register an interface for gnutls to operate
* on public key operations. Any interface registered will override
* the included interface. The interface with the lowest
* priority will be used by gnutls.
*
* Note that the bigint interface must interoperate with the bigint
* interface. Thus if this interface is updated the
* gnutls_crypto_bigint_register() should also be used.
*
* This function should be called before gnutls_global_init().
*
* For simplicity you can use the convenience gnutls_crypto_pk_register()
* macro.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
* Since: 2.6.0
-*/
int
gnutls_crypto_pk_register (int priority,
const gnutls_crypto_pk_st * s)
{
if (crypto_pk_prio > priority)
{
memcpy (&_gnutls_pk_ops, s, sizeof (*s));
crypto_pk_prio = priority;
return 0;
}
return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
}
/*-
* gnutls_crypto_cipher_register:
* @priority: is the priority of the cipher interface
* @s: is a structure holding new interface's data
*
* This function will register a cipher interface to be used by
* gnutls. Any interface registered will override the included engine
* and by convention kernel implemented interfaces should have
* priority of 90 and CPU-assisted of 80. The interface with the lowest priority will be used
* by gnutls.
*
* This function should be called before gnutls_global_init().
*
* For simplicity you can use the convenience
* gnutls_crypto_cipher_register() macro.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
* Since: 2.6.0
-*/
int
gnutls_crypto_cipher_register (int priority,
const gnutls_crypto_cipher_st * s)
{
if (crypto_cipher_prio > priority)
{
memcpy (&_gnutls_cipher_ops, s, sizeof (*s));
crypto_cipher_prio = priority;
return 0;
}
return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
}
/*-
* gnutls_crypto_mac_register:
* @priority: is the priority of the mac interface
* @s: is a structure holding new interface's data
*
* This function will register a mac interface to be used by
* gnutls. Any interface registered will override the included engine
* and by convention kernel implemented interfaces should have
* priority of 90 and CPU-assisted of 80. The interface with the lowest priority will be used
* by gnutls.
*
* This function should be called before gnutls_global_init().
*
* For simplicity you can use the convenience
* gnutls_crypto_digest_register() macro.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
* Since: 2.6.0
-*/
int
gnutls_crypto_mac_register (int priority,
const gnutls_crypto_mac_st * s)
{
if (crypto_mac_prio > priority)
{
memcpy (&_gnutls_mac_ops, s, sizeof (*s));
crypto_mac_prio = priority;
return 0;
}
return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
}
/*-
* gnutls_crypto_digest_register:
* @priority: is the priority of the digest interface
* @s: is a structure holding new interface's data
*
* This function will register a digest interface to be used by
* gnutls. Any interface registered will override the included engine
* and by convention kernel implemented interfaces should have
* priority of 90 and CPU-assisted of 80. The interface with the lowest priority will be used
* by gnutls.
*
* This function should be called before gnutls_global_init().
*
* For simplicity you can use the convenience
* gnutls_crypto_digest_register() macro.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
* Since: 2.6.0
-*/
int
gnutls_crypto_digest_register (int priority,
const gnutls_crypto_digest_st * s)
{
if (crypto_digest_prio > priority)
{
memcpy (&_gnutls_digest_ops, s, sizeof (*s));
crypto_digest_prio = priority;
return 0;
}
return GNUTLS_E_CRYPTO_ALREADY_REGISTERED;
}