strongswan/src/libstrongswan/plugins/plugin_feature.c

636 lines
16 KiB
C

/*
* Copyright (C) 2012-2015 Tobias Brunner
* Copyright (C) 2016-2019 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2011 Martin Willi
* Copyright (C) 2011 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program 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 General Public License
* for more details.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include "plugin_feature.h"
#include <utils/debug.h>
ENUM(plugin_feature_names, FEATURE_NONE, FEATURE_CUSTOM,
"NONE",
"CRYPTER",
"AEAD",
"SIGNER",
"HASHER",
"PRF",
"XOF",
"DRBG",
"DH",
"RNG",
"NONCE_GEN",
"PRIVKEY",
"PRIVKEY_GEN",
"PRIVKEY_SIGN",
"PRIVKEY_DECRYPT",
"PUBKEY",
"PUBKEY_VERIFY",
"PUBKEY_ENCRYPT",
"CERT_DECODE",
"CERT_ENCODE",
"CONTAINER_DECODE",
"CONTAINER_ENCODE",
"EAP_SERVER",
"EAP_CLIENT",
"XAUTH_SERVER",
"XAUTH_CLIENT",
"DATABASE",
"FETCHER",
"RESOLVER",
"CUSTOM",
);
/**
* See header.
*/
uint32_t plugin_feature_hash(plugin_feature_t *feature)
{
chunk_t data = chunk_empty;
switch (feature->type)
{
case FEATURE_NONE:
case FEATURE_RNG:
case FEATURE_NONCE_GEN:
case FEATURE_DATABASE:
case FEATURE_FETCHER:
case FEATURE_RESOLVER:
/* put these special cases in their (type-specific) buckets */
data = chunk_empty;
break;
case FEATURE_CRYPTER:
data = chunk_from_thing(feature->arg.crypter);
break;
case FEATURE_AEAD:
data = chunk_from_thing(feature->arg.aead);
break;
case FEATURE_SIGNER:
data = chunk_from_thing(feature->arg.signer);
break;
case FEATURE_HASHER:
data = chunk_from_thing(feature->arg.hasher);
break;
case FEATURE_PRF:
data = chunk_from_thing(feature->arg.prf);
break;
case FEATURE_XOF:
data = chunk_from_thing(feature->arg.xof);
break;
case FEATURE_DRBG:
data = chunk_from_thing(feature->arg.drbg);
break;
case FEATURE_DH:
data = chunk_from_thing(feature->arg.dh_group);
break;
case FEATURE_PRIVKEY:
data = chunk_from_thing(feature->arg.privkey);
break;
case FEATURE_PRIVKEY_GEN:
data = chunk_from_thing(feature->arg.privkey_gen);
break;
case FEATURE_PUBKEY:
data = chunk_from_thing(feature->arg.pubkey);
break;
case FEATURE_PRIVKEY_SIGN:
data = chunk_from_thing(feature->arg.privkey_sign);
break;
case FEATURE_PUBKEY_VERIFY:
data = chunk_from_thing(feature->arg.pubkey_verify);
break;
case FEATURE_PRIVKEY_DECRYPT:
data = chunk_from_thing(feature->arg.privkey_decrypt);
break;
case FEATURE_PUBKEY_ENCRYPT:
data = chunk_from_thing(feature->arg.pubkey_encrypt);
break;
case FEATURE_CERT_DECODE:
case FEATURE_CERT_ENCODE:
data = chunk_from_thing(feature->arg.cert);
break;
case FEATURE_CONTAINER_DECODE:
case FEATURE_CONTAINER_ENCODE:
data = chunk_from_thing(feature->arg.container);
break;
case FEATURE_EAP_SERVER:
case FEATURE_EAP_PEER:
data = chunk_from_thing(feature->arg.eap);
break;
case FEATURE_CUSTOM:
data = chunk_create(feature->arg.custom,
strlen(feature->arg.custom));
break;
case FEATURE_XAUTH_SERVER:
case FEATURE_XAUTH_PEER:
data = chunk_create(feature->arg.xauth,
strlen(feature->arg.xauth));
break;
}
return chunk_hash_inc(chunk_from_thing(feature->type),
chunk_hash(data));
}
/**
* See header.
*/
bool plugin_feature_matches(plugin_feature_t *a, plugin_feature_t *b)
{
if (a->type == b->type)
{
switch (a->type)
{
case FEATURE_NONE:
return FALSE;
case FEATURE_CRYPTER:
return a->arg.crypter.alg == b->arg.crypter.alg &&
a->arg.crypter.key_size == b->arg.crypter.key_size;
case FEATURE_AEAD:
return a->arg.aead.alg == b->arg.aead.alg &&
a->arg.aead.key_size == b->arg.aead.key_size;
case FEATURE_SIGNER:
return a->arg.signer == b->arg.signer;
case FEATURE_HASHER:
return a->arg.hasher == b->arg.hasher;
case FEATURE_PRF:
return a->arg.prf == b->arg.prf;
case FEATURE_XOF:
return a->arg.xof == b->arg.xof;
case FEATURE_DRBG:
return a->arg.drbg == b->arg.drbg;
case FEATURE_DH:
return a->arg.dh_group == b->arg.dh_group;
case FEATURE_RNG:
return a->arg.rng_quality <= b->arg.rng_quality;
case FEATURE_NONCE_GEN:
case FEATURE_RESOLVER:
return TRUE;
case FEATURE_PRIVKEY:
case FEATURE_PRIVKEY_GEN:
case FEATURE_PUBKEY:
return a->arg.privkey == b->arg.privkey;
case FEATURE_PRIVKEY_SIGN:
case FEATURE_PUBKEY_VERIFY:
return a->arg.privkey_sign == b->arg.privkey_sign;
case FEATURE_PRIVKEY_DECRYPT:
case FEATURE_PUBKEY_ENCRYPT:
return a->arg.privkey_decrypt == b->arg.privkey_decrypt;
case FEATURE_CERT_DECODE:
case FEATURE_CERT_ENCODE:
return a->arg.cert == b->arg.cert;
case FEATURE_CONTAINER_DECODE:
case FEATURE_CONTAINER_ENCODE:
return a->arg.container == b->arg.container;
case FEATURE_EAP_SERVER:
case FEATURE_EAP_PEER:
return a->arg.eap.vendor == b->arg.eap.vendor &&
a->arg.eap.type == b->arg.eap.type;
case FEATURE_DATABASE:
return a->arg.database == DB_ANY ||
a->arg.database == b->arg.database;
case FEATURE_FETCHER:
return a->arg.fetcher == NULL ||
streq(a->arg.fetcher, b->arg.fetcher);
case FEATURE_CUSTOM:
return streq(a->arg.custom, b->arg.custom);
case FEATURE_XAUTH_SERVER:
case FEATURE_XAUTH_PEER:
return streq(a->arg.xauth, b->arg.xauth);
}
}
return FALSE;
}
/**
* See header.
*/
bool plugin_feature_equals(plugin_feature_t *a, plugin_feature_t *b)
{
if (a->type == b->type)
{
switch (a->type)
{
case FEATURE_NONE:
case FEATURE_CRYPTER:
case FEATURE_AEAD:
case FEATURE_SIGNER:
case FEATURE_HASHER:
case FEATURE_PRF:
case FEATURE_XOF:
case FEATURE_DRBG:
case FEATURE_DH:
case FEATURE_NONCE_GEN:
case FEATURE_RESOLVER:
case FEATURE_PRIVKEY:
case FEATURE_PRIVKEY_GEN:
case FEATURE_PUBKEY:
case FEATURE_PRIVKEY_SIGN:
case FEATURE_PUBKEY_VERIFY:
case FEATURE_PRIVKEY_DECRYPT:
case FEATURE_PUBKEY_ENCRYPT:
case FEATURE_CERT_DECODE:
case FEATURE_CERT_ENCODE:
case FEATURE_CONTAINER_DECODE:
case FEATURE_CONTAINER_ENCODE:
case FEATURE_EAP_SERVER:
case FEATURE_EAP_PEER:
case FEATURE_CUSTOM:
case FEATURE_XAUTH_SERVER:
case FEATURE_XAUTH_PEER:
return plugin_feature_matches(a, b);
case FEATURE_RNG:
return a->arg.rng_quality == b->arg.rng_quality;
case FEATURE_DATABASE:
return a->arg.database == b->arg.database;
case FEATURE_FETCHER:
if (a->arg.fetcher && b->arg.fetcher)
{
return streq(a->arg.fetcher, b->arg.fetcher);
}
return !a->arg.fetcher && !b->arg.fetcher;
}
}
return FALSE;
}
/**
* See header.
*/
char* plugin_feature_get_string(plugin_feature_t *feature)
{
char *str = NULL;
if (feature->kind == FEATURE_REGISTER)
{
return strdup("(register function)");
}
switch (feature->type)
{
case FEATURE_NONE:
return strdup("NONE");
case FEATURE_CRYPTER:
if (asprintf(&str, "%N:%N-%d", plugin_feature_names, feature->type,
encryption_algorithm_names, feature->arg.crypter.alg,
feature->arg.crypter.key_size) > 0)
{
return str;
}
break;
case FEATURE_AEAD:
if (asprintf(&str, "%N:%N-%d", plugin_feature_names, feature->type,
encryption_algorithm_names, feature->arg.aead.alg,
feature->arg.aead.key_size) > 0)
{
return str;
}
break;
case FEATURE_SIGNER:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
integrity_algorithm_names, feature->arg.signer) > 0)
{
return str;
}
break;
case FEATURE_HASHER:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
hash_algorithm_names, feature->arg.hasher) > 0)
{
return str;
}
break;
case FEATURE_PRF:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
pseudo_random_function_names, feature->arg.prf) > 0)
{
return str;
}
break;
case FEATURE_XOF:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
ext_out_function_names, feature->arg.xof) > 0)
{
return str;
}
break;
case FEATURE_DRBG:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
drbg_type_names, feature->arg.drbg) > 0)
{
return str;
}
break;
case FEATURE_DH:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
diffie_hellman_group_names, feature->arg.dh_group) > 0)
{
return str;
}
break;
case FEATURE_RNG:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
rng_quality_names, feature->arg.rng_quality) > 0)
{
return str;
}
break;
case FEATURE_NONCE_GEN:
case FEATURE_RESOLVER:
if (asprintf(&str, "%N", plugin_feature_names, feature->type) > 0)
{
return str;
}
break;
case FEATURE_PRIVKEY:
case FEATURE_PRIVKEY_GEN:
case FEATURE_PUBKEY:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
key_type_names, feature->arg.privkey) > 0)
{
return str;
}
break;
case FEATURE_PRIVKEY_SIGN:
case FEATURE_PUBKEY_VERIFY:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
signature_scheme_names, feature->arg.privkey_sign) > 0)
{
return str;
}
break;
case FEATURE_PRIVKEY_DECRYPT:
case FEATURE_PUBKEY_ENCRYPT:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
encryption_scheme_names, feature->arg.privkey_decrypt) > 0)
{
return str;
}
break;
case FEATURE_CERT_DECODE:
case FEATURE_CERT_ENCODE:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
certificate_type_names, feature->arg.cert) > 0)
{
return str;
}
break;
case FEATURE_CONTAINER_DECODE:
case FEATURE_CONTAINER_ENCODE:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
container_type_names, feature->arg.container) > 0)
{
return str;
}
break;
case FEATURE_EAP_SERVER:
case FEATURE_EAP_PEER:
if (feature->arg.eap.vendor &&
asprintf(&str, "%N:%d-%d", plugin_feature_names, feature->type,
feature->arg.eap.type, feature->arg.eap.vendor) > 0)
{
return str;
}
else if (!feature->arg.eap.vendor &&
asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
eap_type_short_names, feature->arg.eap.type) > 0)
{
return str;
}
break;
case FEATURE_DATABASE:
if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type,
db_driver_names, feature->arg.database) > 0)
{
return str;
}
break;
case FEATURE_FETCHER:
if (asprintf(&str, "%N:%s", plugin_feature_names, feature->type,
feature->arg.fetcher) > 0)
{
return str;
}
break;
case FEATURE_CUSTOM:
if (asprintf(&str, "%N:%s", plugin_feature_names, feature->type,
feature->arg.custom) > 0)
{
return str;
}
break;
case FEATURE_XAUTH_SERVER:
case FEATURE_XAUTH_PEER:
if (asprintf(&str, "%N:%s", plugin_feature_names, feature->type,
feature->arg.xauth) > 0)
{
return str;
}
break;
}
if (!str)
{
str = strdup("(invalid)");
}
return str;
}
/**
* See header.
*/
bool plugin_feature_load(plugin_t *plugin, plugin_feature_t *feature,
plugin_feature_t *reg)
{
char *name;
if (!reg)
{ /* noting to do for this feature */
return TRUE;
}
if (reg->kind == FEATURE_CALLBACK)
{
if (!reg->arg.cb.f ||
reg->arg.cb.f(plugin, feature, TRUE, reg->arg.cb.data))
{
return TRUE;
}
return FALSE;
}
name = plugin->get_name(plugin);
switch (feature->type)
{
case FEATURE_CRYPTER:
lib->crypto->add_crypter(lib->crypto, feature->arg.crypter.alg,
feature->arg.crypter.key_size,
name, reg->arg.reg.f);
break;
case FEATURE_AEAD:
lib->crypto->add_aead(lib->crypto, feature->arg.aead.alg,
feature->arg.aead.key_size,
name, reg->arg.reg.f);
break;
case FEATURE_SIGNER:
lib->crypto->add_signer(lib->crypto, feature->arg.signer,
name, reg->arg.reg.f);
break;
case FEATURE_HASHER:
lib->crypto->add_hasher(lib->crypto, feature->arg.hasher,
name, reg->arg.reg.f);
break;
case FEATURE_PRF:
lib->crypto->add_prf(lib->crypto, feature->arg.prf,
name, reg->arg.reg.f);
break;
case FEATURE_XOF:
lib->crypto->add_xof(lib->crypto, feature->arg.xof,
name, reg->arg.reg.f);
break;
case FEATURE_DRBG:
lib->crypto->add_drbg(lib->crypto, feature->arg.drbg,
name, reg->arg.reg.f);
break;
case FEATURE_DH:
lib->crypto->add_dh(lib->crypto, feature->arg.dh_group,
name, reg->arg.reg.f);
break;
case FEATURE_RNG:
lib->crypto->add_rng(lib->crypto, feature->arg.rng_quality,
name, reg->arg.reg.f);
break;
case FEATURE_NONCE_GEN:
lib->crypto->add_nonce_gen(lib->crypto,
name, reg->arg.reg.f);
break;
case FEATURE_PRIVKEY:
case FEATURE_PRIVKEY_GEN:
lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY,
feature->arg.privkey, reg->arg.reg.final,
name, reg->arg.reg.f);
break;
case FEATURE_PUBKEY:
lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY,
feature->arg.pubkey, reg->arg.reg.final,
name, reg->arg.reg.f);
break;
case FEATURE_CERT_DECODE:
case FEATURE_CERT_ENCODE:
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE,
feature->arg.cert, reg->arg.reg.final,
name, reg->arg.reg.f);
break;
case FEATURE_CONTAINER_DECODE:
case FEATURE_CONTAINER_ENCODE:
lib->creds->add_builder(lib->creds, CRED_CONTAINER,
feature->arg.container, reg->arg.reg.final,
name, reg->arg.reg.f);
break;
case FEATURE_DATABASE:
lib->db->add_database(lib->db, reg->arg.reg.f);
break;
case FEATURE_FETCHER:
lib->fetcher->add_fetcher(lib->fetcher, reg->arg.reg.f,
feature->arg.fetcher);
break;
case FEATURE_RESOLVER:
lib->resolver->add_resolver(lib->resolver, reg->arg.reg.f);
break;
default:
break;
}
return TRUE;
}
/**
* See header.
*/
bool plugin_feature_unload(plugin_t *plugin, plugin_feature_t *feature,
plugin_feature_t *reg)
{
if (!reg)
{ /* noting to do for this feature */
return TRUE;
}
if (reg->kind == FEATURE_CALLBACK)
{
if (!reg->arg.cb.f ||
reg->arg.cb.f(plugin, feature, FALSE, reg->arg.cb.data))
{
return TRUE;
}
return FALSE;
}
switch (feature->type)
{
case FEATURE_CRYPTER:
lib->crypto->remove_crypter(lib->crypto, reg->arg.reg.f);
break;
case FEATURE_AEAD:
lib->crypto->remove_aead(lib->crypto, reg->arg.reg.f);
break;
case FEATURE_SIGNER:
lib->crypto->remove_signer(lib->crypto, reg->arg.reg.f);
break;
case FEATURE_HASHER:
lib->crypto->remove_hasher(lib->crypto, reg->arg.reg.f);
break;
case FEATURE_PRF:
lib->crypto->remove_prf(lib->crypto, reg->arg.reg.f);
break;
case FEATURE_XOF:
lib->crypto->remove_xof(lib->crypto, reg->arg.reg.f);
break;
case FEATURE_DRBG:
lib->crypto->remove_drbg(lib->crypto, reg->arg.reg.f);
break;
case FEATURE_DH:
lib->crypto->remove_dh(lib->crypto, reg->arg.reg.f);
break;
case FEATURE_RNG:
lib->crypto->remove_rng(lib->crypto, reg->arg.reg.f);
break;
case FEATURE_NONCE_GEN:
lib->crypto->remove_nonce_gen(lib->crypto, reg->arg.reg.f);
break;
case FEATURE_PRIVKEY:
case FEATURE_PRIVKEY_GEN:
lib->creds->remove_builder(lib->creds, reg->arg.reg.f);
break;
case FEATURE_PUBKEY:
lib->creds->remove_builder(lib->creds, reg->arg.reg.f);
break;
case FEATURE_CERT_DECODE:
case FEATURE_CERT_ENCODE:
lib->creds->remove_builder(lib->creds, reg->arg.reg.f);
break;
case FEATURE_CONTAINER_DECODE:
case FEATURE_CONTAINER_ENCODE:
lib->creds->remove_builder(lib->creds, reg->arg.reg.f);
break;
case FEATURE_DATABASE:
lib->db->remove_database(lib->db, reg->arg.reg.f);
break;
case FEATURE_FETCHER:
lib->fetcher->remove_fetcher(lib->fetcher, reg->arg.reg.f);
break;
case FEATURE_RESOLVER:
lib->resolver->remove_resolver(lib->resolver, reg->arg.reg.f);
break;
default:
break;
}
return TRUE;
}