#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "alloc.h"
#include "crypto_kernel.h"
#include "cipher_types.h"
srtp_debug_module_t srtp_mod_crypto_kernel = {
0,
"crypto kernel"
};
srtp_crypto_kernel_t crypto_kernel = {
srtp_crypto_kernel_state_insecure,
NULL,
NULL,
NULL
};
#define MAX_RNG_TRIALS 25
srtp_err_status_t srtp_crypto_kernel_init()
{
srtp_err_status_t status;
if (crypto_kernel.state == srtp_crypto_kernel_state_secure) {
return srtp_crypto_kernel_status();
}
status = srtp_err_reporting_init();
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_crypto_kernel);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_auth);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_cipher);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_stat);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_alloc);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_cipher_type(&srtp_null_cipher,
SRTP_NULL_CIPHER);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_cipher_type(&srtp_aes_icm_128,
SRTP_AES_ICM_128);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_cipher_type(&srtp_aes_icm_256,
SRTP_AES_ICM_256);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_aes_icm);
if (status) {
return status;
}
#ifdef GCM
status = srtp_crypto_kernel_load_cipher_type(&srtp_aes_icm_192,
SRTP_AES_ICM_192);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_cipher_type(&srtp_aes_gcm_128,
SRTP_AES_GCM_128);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_cipher_type(&srtp_aes_gcm_256,
SRTP_AES_GCM_256);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_aes_gcm);
if (status) {
return status;
}
#endif
status = srtp_crypto_kernel_load_auth_type(&srtp_null_auth, SRTP_NULL_AUTH);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_auth_type(&srtp_hmac, SRTP_HMAC_SHA1);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_hmac);
if (status) {
return status;
}
crypto_kernel.state = srtp_crypto_kernel_state_secure;
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_status()
{
srtp_err_status_t status;
srtp_kernel_cipher_type_t *ctype = crypto_kernel.cipher_type_list;
srtp_kernel_auth_type_t *atype = crypto_kernel.auth_type_list;
while (ctype != NULL) {
srtp_err_report(srtp_err_level_info, "cipher: %s\n",
ctype->cipher_type->description);
srtp_err_report(srtp_err_level_info, " self-test: ");
status = srtp_cipher_type_self_test(ctype->cipher_type);
if (status) {
srtp_err_report(srtp_err_level_error, "failed with error code %d\n",
status);
exit(status);
}
srtp_err_report(srtp_err_level_info, "passed\n");
ctype = ctype->next;
}
while (atype != NULL) {
srtp_err_report(srtp_err_level_info, "auth func: %s\n",
atype->auth_type->description);
srtp_err_report(srtp_err_level_info, " self-test: ");
status = srtp_auth_type_self_test(atype->auth_type);
if (status) {
srtp_err_report(srtp_err_level_error, "failed with error code %d\n",
status);
exit(status);
}
srtp_err_report(srtp_err_level_info, "passed\n");
atype = atype->next;
}
srtp_crypto_kernel_list_debug_modules();
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_list_debug_modules()
{
srtp_kernel_debug_module_t *dm = crypto_kernel.debug_module_list;
srtp_err_report(srtp_err_level_info, "debug modules loaded:\n");
while (dm != NULL) {
srtp_err_report(srtp_err_level_info, " %s ", dm->mod->name);
if (dm->mod->on) {
srtp_err_report(srtp_err_level_info, "(on)\n");
} else {
srtp_err_report(srtp_err_level_info, "(off)\n");
}
dm = dm->next;
}
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_shutdown()
{
while (crypto_kernel.cipher_type_list != NULL) {
srtp_kernel_cipher_type_t *ctype = crypto_kernel.cipher_type_list;
crypto_kernel.cipher_type_list = ctype->next;
debug_print(srtp_mod_crypto_kernel, "freeing memory for cipher %s",
ctype->cipher_type->description);
srtp_crypto_free(ctype);
}
while (crypto_kernel.auth_type_list != NULL) {
srtp_kernel_auth_type_t *atype = crypto_kernel.auth_type_list;
crypto_kernel.auth_type_list = atype->next;
debug_print(srtp_mod_crypto_kernel,
"freeing memory for authentication %s",
atype->auth_type->description);
srtp_crypto_free(atype);
}
while (crypto_kernel.debug_module_list != NULL) {
srtp_kernel_debug_module_t *kdm = crypto_kernel.debug_module_list;
crypto_kernel.debug_module_list = kdm->next;
debug_print(srtp_mod_crypto_kernel,
"freeing memory for debug module %s", kdm->mod->name);
srtp_crypto_free(kdm);
}
crypto_kernel.state = srtp_crypto_kernel_state_insecure;
return srtp_err_status_ok;
}
static inline srtp_err_status_t srtp_crypto_kernel_do_load_cipher_type(
const srtp_cipher_type_t *new_ct,
srtp_cipher_type_id_t id,
int replace)
{
srtp_kernel_cipher_type_t *ctype, *new_ctype;
srtp_err_status_t status;
if (new_ct == NULL) {
return srtp_err_status_bad_param;
}
if (new_ct->id != id) {
return srtp_err_status_bad_param;
}
status = srtp_cipher_type_self_test(new_ct);
if (status) {
return status;
}
ctype = crypto_kernel.cipher_type_list;
while (ctype != NULL) {
if (id == ctype->id) {
if (!replace) {
return srtp_err_status_bad_param;
}
status =
srtp_cipher_type_test(new_ct, ctype->cipher_type->test_data);
if (status) {
return status;
}
new_ctype = ctype;
break;
} else if (new_ct == ctype->cipher_type) {
return srtp_err_status_bad_param;
}
ctype = ctype->next;
}
if (ctype == NULL) {
new_ctype = (srtp_kernel_cipher_type_t *)srtp_crypto_alloc(
sizeof(srtp_kernel_cipher_type_t));
if (new_ctype == NULL) {
return srtp_err_status_alloc_fail;
}
new_ctype->next = crypto_kernel.cipher_type_list;
crypto_kernel.cipher_type_list = new_ctype;
}
new_ctype->cipher_type = new_ct;
new_ctype->id = id;
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_load_cipher_type(
const srtp_cipher_type_t *new_ct,
srtp_cipher_type_id_t id)
{
return srtp_crypto_kernel_do_load_cipher_type(new_ct, id, 0);
}
srtp_err_status_t srtp_replace_cipher_type(const srtp_cipher_type_t *new_ct,
srtp_cipher_type_id_t id)
{
return srtp_crypto_kernel_do_load_cipher_type(new_ct, id, 1);
}
srtp_err_status_t srtp_crypto_kernel_do_load_auth_type(
const srtp_auth_type_t *new_at,
srtp_auth_type_id_t id,
int replace)
{
srtp_kernel_auth_type_t *atype, *new_atype;
srtp_err_status_t status;
if (new_at == NULL) {
return srtp_err_status_bad_param;
}
if (new_at->id != id) {
return srtp_err_status_bad_param;
}
status = srtp_auth_type_self_test(new_at);
if (status) {
return status;
}
atype = crypto_kernel.auth_type_list;
while (atype != NULL) {
if (id == atype->id) {
if (!replace) {
return srtp_err_status_bad_param;
}
status = srtp_auth_type_test(new_at, atype->auth_type->test_data);
if (status) {
return status;
}
new_atype = atype;
break;
} else if (new_at == atype->auth_type) {
return srtp_err_status_bad_param;
}
atype = atype->next;
}
if (atype == NULL) {
new_atype = (srtp_kernel_auth_type_t *)srtp_crypto_alloc(
sizeof(srtp_kernel_auth_type_t));
if (new_atype == NULL) {
return srtp_err_status_alloc_fail;
}
new_atype->next = crypto_kernel.auth_type_list;
crypto_kernel.auth_type_list = new_atype;
}
new_atype->auth_type = new_at;
new_atype->id = id;
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_load_auth_type(
const srtp_auth_type_t *new_at,
srtp_auth_type_id_t id)
{
return srtp_crypto_kernel_do_load_auth_type(new_at, id, 0);
}
srtp_err_status_t srtp_replace_auth_type(const srtp_auth_type_t *new_at,
srtp_auth_type_id_t id)
{
return srtp_crypto_kernel_do_load_auth_type(new_at, id, 1);
}
const srtp_cipher_type_t *srtp_crypto_kernel_get_cipher_type(
srtp_cipher_type_id_t id)
{
srtp_kernel_cipher_type_t *ctype;
ctype = crypto_kernel.cipher_type_list;
while (ctype != NULL) {
if (id == ctype->id) {
return ctype->cipher_type;
}
ctype = ctype->next;
}
return NULL;
}
srtp_err_status_t srtp_crypto_kernel_alloc_cipher(srtp_cipher_type_id_t id,
srtp_cipher_pointer_t *cp,
int key_len,
int tag_len)
{
const srtp_cipher_type_t *ct;
if (crypto_kernel.state != srtp_crypto_kernel_state_secure) {
return srtp_err_status_init_fail;
}
ct = srtp_crypto_kernel_get_cipher_type(id);
if (!ct) {
return srtp_err_status_fail;
}
return ((ct)->alloc(cp, key_len, tag_len));
}
const srtp_auth_type_t *srtp_crypto_kernel_get_auth_type(srtp_auth_type_id_t id)
{
srtp_kernel_auth_type_t *atype;
atype = crypto_kernel.auth_type_list;
while (atype != NULL) {
if (id == atype->id) {
return atype->auth_type;
}
atype = atype->next;
}
return NULL;
}
srtp_err_status_t srtp_crypto_kernel_alloc_auth(srtp_auth_type_id_t id,
srtp_auth_pointer_t *ap,
int key_len,
int tag_len)
{
const srtp_auth_type_t *at;
if (crypto_kernel.state != srtp_crypto_kernel_state_secure) {
return srtp_err_status_init_fail;
}
at = srtp_crypto_kernel_get_auth_type(id);
if (!at) {
return srtp_err_status_fail;
}
return ((at)->alloc(ap, key_len, tag_len));
}
srtp_err_status_t srtp_crypto_kernel_load_debug_module(
srtp_debug_module_t *new_dm)
{
srtp_kernel_debug_module_t *kdm, *new;
if (new_dm == NULL || new_dm->name == NULL) {
return srtp_err_status_bad_param;
}
kdm = crypto_kernel.debug_module_list;
while (kdm != NULL) {
if (strncmp(new_dm->name, kdm->mod->name, 64) == 0) {
return srtp_err_status_bad_param;
}
kdm = kdm->next;
}
new = (srtp_kernel_debug_module_t *)srtp_crypto_alloc(
sizeof(srtp_kernel_debug_module_t));
if (new == NULL) {
return srtp_err_status_alloc_fail;
}
new->mod = new_dm;
new->next = crypto_kernel.debug_module_list;
crypto_kernel.debug_module_list = new;
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_set_debug_module(const char *name, int on)
{
srtp_kernel_debug_module_t *kdm;
kdm = crypto_kernel.debug_module_list;
while (kdm != NULL) {
if (strncmp(name, kdm->mod->name, 64) == 0) {
kdm->mod->on = on;
return srtp_err_status_ok;
}
kdm = kdm->next;
}
return srtp_err_status_fail;
}