diff options
Diffstat (limited to 'src')
35 files changed, 2658 insertions, 3 deletions
diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 3c1b6aa5e..bc25dcf21 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -212,6 +212,13 @@ if MONOLITHIC endif endif +if USE_IPSECKEY + SUBDIRS += plugins/ipseckey +if MONOLITHIC + libcharon_la_LIBADD += plugins/ipseckey/libstrongswan-ipseckey.la +endif +endif + if USE_UPDOWN SUBDIRS += plugins/updown if MONOLITHIC diff --git a/src/libcharon/plugins/ipseckey/Makefile.am b/src/libcharon/plugins/ipseckey/Makefile.am new file mode 100644 index 000000000..0614017a0 --- /dev/null +++ b/src/libcharon/plugins/ipseckey/Makefile.am @@ -0,0 +1,18 @@ + +INCLUDES = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-ipseckey.la +else +plugin_LTLIBRARIES = libstrongswan-ipseckey.la +endif + +libstrongswan_ipseckey_la_SOURCES = \ + ipseckey_plugin.h ipseckey_plugin.c \ + ipseckey_cred.h ipseckey_cred.c \ + ipseckey.h ipseckey.c + +libstrongswan_ipseckey_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/ipseckey/ipseckey.c b/src/libcharon/plugins/ipseckey/ipseckey.c new file mode 100644 index 000000000..78ae2cc2a --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +#include "ipseckey.h" + +#include <library.h> +#include <utils/debug.h> +#include <bio/bio_reader.h> + +typedef struct private_ipseckey_t private_ipseckey_t; + +/** +* private data of the ipseckey +*/ +struct private_ipseckey_t { + + /** + * public functions + */ + ipseckey_t public; + + /** + * Precedence + */ + u_int8_t precedence; + + /** + * Gateway type + */ + u_int8_t gateway_type; + + /** + * Algorithm + */ + u_int8_t algorithm; + + /** + * Gateway + */ + chunk_t gateway; + + /** + * Public key + */ + chunk_t public_key; +}; + +METHOD(ipseckey_t, get_precedence, u_int8_t, + private_ipseckey_t *this) +{ + return this->precedence; +} + +METHOD(ipseckey_t, get_gateway_type, ipseckey_gw_type_t, + private_ipseckey_t *this) +{ + return this->gateway_type; +} + +METHOD(ipseckey_t, get_algorithm, ipseckey_algorithm_t, + private_ipseckey_t *this) +{ + return this->algorithm; +} + +METHOD(ipseckey_t, get_gateway, chunk_t, + private_ipseckey_t *this) +{ + return this->gateway; +} + +METHOD(ipseckey_t, get_public_key, chunk_t, + private_ipseckey_t *this) +{ + return this->public_key; +} + +METHOD(ipseckey_t, destroy, void, + private_ipseckey_t *this) +{ + chunk_free(&this->gateway); + chunk_free(&this->public_key); + free(this); +} + +/* + * See header + */ +ipseckey_t *ipseckey_create_frm_rr(rr_t *rr) +{ + private_ipseckey_t *this; + bio_reader_t *reader = NULL; + u_int8_t label; + chunk_t tmp; + + INIT(this, + .public = { + .get_precedence = _get_precedence, + .get_gateway_type = _get_gateway_type, + .get_algorithm = _get_algorithm, + .get_gateway = _get_gateway, + .get_public_key = _get_public_key, + .destroy = _destroy, + }, + ); + + if (rr->get_type(rr) != RR_TYPE_IPSECKEY) + { + DBG1(DBG_CFG, "unable to create an ipseckey out of an RR " + "whose type is not IPSECKEY"); + free(this); + return NULL; + } + + /** Parse the content (RDATA field) of the RR */ + reader = bio_reader_create(rr->get_rdata(rr)); + if (!reader->read_uint8(reader, &this->precedence) || + !reader->read_uint8(reader, &this->gateway_type) || + !reader->read_uint8(reader, &this->algorithm)) + { + DBG1(DBG_CFG, "ipseckey RR has a wrong format"); + reader->destroy(reader); + free(this); + } + + switch (this->gateway_type) + { + case IPSECKEY_GW_TP_NOT_PRESENT: + break; + + case IPSECKEY_GW_TP_IPV4: + if (!reader->read_data(reader, 4, &this->gateway)) + { + DBG1(DBG_CFG, "ipseckey gateway field does not contain an " + "IPv4 address as expected"); + reader->destroy(reader); + free(this); + return NULL; + } + this->gateway = chunk_clone(this->gateway); + break; + + case IPSECKEY_GW_TP_IPV6: + if (!reader->read_data(reader, 16, &this->gateway)) + { + DBG1(DBG_CFG, "ipseckey gateway field does not contain an " + "IPv6 address as expected"); + reader->destroy(reader); + free(this); + return NULL; + } + this->gateway = chunk_clone(this->gateway); + break; + + case IPSECKEY_GW_TP_WR_ENC_DNAME: + /** + * Uncompressed domain name as defined in RFC 1035 chapter 3. + * + * TODO: Currently we ignore wire encoded domain names. + * + */ + while (reader->read_uint8(reader, &label) && + label != 0 && label < 192) + { + if (!reader->read_data(reader, label, &tmp)) + { + DBG1(DBG_CFG, "wrong wire encoded domain name format " + "in ipseckey gateway field"); + reader->destroy(reader); + free(this); + return NULL; + } + } + break; + + default: + DBG1(DBG_CFG, "unable to parse ipseckey gateway field"); + reader->destroy(reader); + free(this); + return NULL; + } + + if (!reader->read_data(reader, reader->remaining(reader), + &this->public_key)) + { + DBG1(DBG_CFG, "failed to read ipseckey public key field"); + reader->destroy(reader); + chunk_free(&this->gateway); + free(this); + return NULL; + } + this->public_key = chunk_clone(this->public_key); + reader->destroy(reader); + return &this->public; +} + diff --git a/src/libcharon/plugins/ipseckey/ipseckey.h b/src/libcharon/plugins/ipseckey/ipseckey.h new file mode 100644 index 000000000..0afc067a5 --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup ipseckey_cred_i ipseckey + * @{ @ingroup ipseckey + */ + +#ifndef IPSECKEY_H_ +#define IPSECKEY_H_ + +typedef struct ipseckey_t ipseckey_t; +typedef enum ipseckey_algorithm_t ipseckey_algorithm_t; +typedef enum ipseckey_gw_type_t ipseckey_gw_type_t; + +#include <library.h> + +/** + * IPSECKEY gateway types as defined in RFC 4025. + */ +enum ipseckey_gw_type_t { + /** No gateway is present */ + IPSECKEY_GW_TP_NOT_PRESENT = 0, + /** A 4-byte IPv4 address is present */ + IPSECKEY_GW_TP_IPV4 = 1, + /** A 16-byte IPv6 address is present */ + IPSECKEY_GW_TP_IPV6 = 2, + /** A wire-encoded domain name is present */ + IPSECKEY_GW_TP_WR_ENC_DNAME = 3, +}; + +/** + * IPSECKEY algorithms as defined in RFC 4025. + */ +enum ipseckey_algorithm_t { + /** No key present */ + IPSECKEY_ALGORITHM_NONE = 0, + /** DSA key */ + IPSECKEY_ALGORITHM_DSA = 1, + /** RSA key */ + IPSECKEY_ALGORITHM_RSA = 2, +}; + +/** + * An IPSECKEY. + * + * Represents an IPSECKEY as defined in RFC 4025: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | precedence | gateway type | algorithm | gateway | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------+ + + * ~ gateway ~ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | / + * / public key / + * / / + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-| + * + * + * Note: RFC 4025 defines that the algorithm field has a length of 7 bits. + * We use 8 bits instead, because the use of 7 bits is very uncommon + * in internet protocols and might be an error in RFC 4025 + * (also the BIND DNS server uses 8 bits for the algorithm field of the + * IPSECKEY resource records). + * + */ +struct ipseckey_t { + + /** + * Get the precedence of the IPSECKEY. + * + * @return precedence + */ + u_int8_t (*get_precedence)(ipseckey_t *this); + + /** + * Get the type of the gateway. + * + * The "gateway type" determines the format of the gateway field + * of the IPSECKEY. + * + * @return gateway type + */ + ipseckey_gw_type_t (*get_gateway_type)(ipseckey_t *this); + + /** + * Get the algorithm. + * + * The "algorithm" determines the format of the public key field + * of the IPSECKEY. + * + * @return algorithm + */ + ipseckey_algorithm_t (*get_algorithm)(ipseckey_t *this); + + /** + * Get the content of the gateway field as chunk. + * + * The content is in network byte order and its format depends on the + * gateway type. + * + * The data pointed by the chunk is still owned by the IPSECKEY. + * Clone it if necessary. + * + * @return gateway field as chunk + */ + chunk_t (*get_gateway)(ipseckey_t *this); + + /** + * Get the content of the public key field as chunk. + * + * The format of the public key depends on the algorithm type. + * + * The data pointed by the chunk is still owned by the IPSECKEY. + * Clone it if necessary. + * + * @return public key field as chunk + */ + chunk_t (*get_public_key)(ipseckey_t *this); + + /** + * Destroy the IPSECKEY. + */ + void (*destroy) (ipseckey_t *this); +}; + +/** + * Create an ipseckey instance out of a resource record. + * + * @param rr resource record which contains an IPSECKEY + * @return ipseckey, NULL on failure + */ +ipseckey_t *ipseckey_create_frm_rr(rr_t *rr); + +#endif /** IPSECKEY_H_ @}*/ diff --git a/src/libcharon/plugins/ipseckey/ipseckey_cred.c b/src/libcharon/plugins/ipseckey/ipseckey_cred.c new file mode 100644 index 000000000..e8722f12c --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey_cred.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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 <string.h> + +#include "ipseckey_cred.h" +#include "ipseckey.h" + +#include <bio/bio_reader.h> +#include <daemon.h> + +typedef struct private_ipseckey_cred_t private_ipseckey_cred_t; + +/** + * Private data of an ipseckey_cred_t object + */ +struct private_ipseckey_cred_t { + + /** + * Public part + */ + ipseckey_cred_t public; + + /** + * DNS resolver + */ + resolver_t *res; +}; + +/** + * enumerator over certificates + */ +typedef struct { + /** implements enumerator interface */ + enumerator_t public; + /** inner enumerator (enumerates IPSECKEY resource records) */ + enumerator_t *inner; + /** response of the DNS resolver which contains the IPSECKEYs */ + resolver_response_t *response; + /* IPSECKEYs are not valid before this point in time */ + time_t notBefore; + /* IPSECKEYs are not valid after this point in time */ + time_t notAfter; + /* identity to which the IPSECKEY belongs */ + identification_t *identity; +} cert_enumerator_t; + +METHOD(enumerator_t, cert_enumerator_enumerate, bool, + cert_enumerator_t *this, certificate_t **cert) +{ + rr_t *cur_rr = NULL; + ipseckey_t *cur_ipseckey = NULL; + chunk_t pub_key; + public_key_t * key = NULL; + bool supported_ipseckey_found = FALSE; + + /* Get the next supported IPSECKEY using the inner enumerator. */ + while (this->inner->enumerate(this->inner, &cur_rr) && + !supported_ipseckey_found) + { + supported_ipseckey_found = TRUE; + + cur_ipseckey = ipseckey_create_frm_rr(cur_rr); + + if (!cur_ipseckey) + { + DBG1(DBG_CFG, "failed to parse ipseckey - skipping this key"); + supported_ipseckey_found = FALSE; + } + + if (cur_ipseckey && + cur_ipseckey->get_algorithm(cur_ipseckey) != IPSECKEY_ALGORITHM_RSA) + { + DBG1(DBG_CFG, "unsupported ipseckey algorithm -skipping this key"); + cur_ipseckey->destroy(cur_ipseckey); + supported_ipseckey_found = FALSE; + } + } + + if (supported_ipseckey_found) + { + /* + * Wrap the key of the IPSECKEY in a certificate and return this + * certificate. + */ + pub_key = cur_ipseckey->get_public_key(cur_ipseckey); + + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + BUILD_BLOB_DNSKEY, pub_key, + BUILD_END); + + if (!key) + { + DBG1(DBG_CFG, "failed to create public key from ipseckey"); + cur_ipseckey->destroy(cur_ipseckey); + return FALSE; + } + + *cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, + CERT_TRUSTED_PUBKEY, + BUILD_PUBLIC_KEY, key, + BUILD_SUBJECT, this->identity, + BUILD_NOT_BEFORE_TIME, this->notBefore, + BUILD_NOT_AFTER_TIME, this->notAfter, + BUILD_END); + return TRUE; + } + + return FALSE; +} + +METHOD(enumerator_t, cert_enumerator_destroy, void, + cert_enumerator_t *this) +{ + this->inner->destroy(this->inner); + this->response->destroy(this->response); + free(this); +} + +METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, + private_ipseckey_cred_t *this, certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + char *fqdn = NULL; + resolver_response_t *response = NULL; + rr_set_t *rrset = NULL; + enumerator_t *rrsig_enum = NULL; + rr_t *rrsig = NULL; + bio_reader_t *reader = NULL; + chunk_t ignore; + u_int32_t nBefore, nAfter; + cert_enumerator_t *e; + + if (id && id->get_type(id) == ID_FQDN) + { + /** Query the DNS for the required IPSECKEY RRs */ + + if (0 >= asprintf(&fqdn, "%Y", id)) + { + DBG1(DBG_CFG, "empty FQDN string"); + return enumerator_create_empty(); + } + + DBG1(DBG_CFG, "performing a DNS query for IPSECKEY RRs of '%s'", + fqdn); + response = this->res->query(this->res, fqdn, RR_CLASS_IN, + RR_TYPE_IPSECKEY); + if (!response) + { + DBG1(DBG_CFG, " query for IPSECKEY RRs failed"); + free(fqdn); + return enumerator_create_empty(); + } + + if (!response->has_data(response) || + !response->query_name_exist(response)) + { + DBG1(DBG_CFG, " unable to retrieve IPSECKEY RRs from the DNS"); + response->destroy(response); + free(fqdn); + return enumerator_create_empty(); + } + + if (!(response->get_security_state(response) == SECURE)) + { + DBG1(DBG_CFG, " DNSSEC state of IPSECKEY RRs is not secure"); + response->destroy(response); + free(fqdn); + return enumerator_create_empty(); + } + + free(fqdn); + + /** Determine the validity period of the retrieved IPSECKEYs + * + * We use the "Signature Inception" and "Signature Expiration" field + * of the first RRSIG RR to determine the validity period of the + * IPSECKEY RRs. TODO: Take multiple RRSIGs into account. + */ + rrset = response->get_rr_set(response); + rrsig_enum = rrset->create_rrsig_enumerator(rrset); + if (!rrsig_enum || !rrsig_enum->enumerate(rrsig_enum, &rrsig)) + { + DBG1(DBG_CFG, " unable to determine the validity period of " + "IPSECKEY RRs because no RRSIGs are present"); + DESTROY_IF(rrsig_enum); + response->destroy(response); + return enumerator_create_empty(); + } + + /** + * Parse the RRSIG for its validity period (RFC 4034) + */ + reader = bio_reader_create(rrsig->get_rdata(rrsig)); + reader->read_data(reader, 8, &ignore); + reader->read_uint32(reader, &nAfter); + reader->read_uint32(reader, &nBefore); + reader->destroy(reader); + + /*Create and return an iterator over the retrieved IPSECKEYs */ + INIT(e, + .public = { + .enumerate = (void*)_cert_enumerator_enumerate, + .destroy = _cert_enumerator_destroy, + }, + .inner = response->get_rr_set(response)->create_rr_enumerator( + response->get_rr_set(response)), + .response = response, + .notBefore = nBefore, + .notAfter = nAfter, + .identity = id, + ); + + return &e->public; + } + + + return enumerator_create_empty(); +} + +METHOD(ipseckey_cred_t, destroy, void, + private_ipseckey_cred_t *this) +{ + this->res->destroy(this->res); + free(this); +} + +/** + * Described in header. + */ +ipseckey_cred_t *ipseckey_cred_create(resolver_t *res) +{ + private_ipseckey_cred_t *this; + + INIT(this, + .public = { + .set = { + .create_private_enumerator = (void*)return_null, + .create_cert_enumerator = _create_cert_enumerator, + .create_shared_enumerator = (void*)return_null, + .create_cdp_enumerator = (void*)return_null, + .cache_cert = (void*)nop, + }, + .destroy = _destroy, + }, + .res = res, + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/ipseckey/ipseckey_cred.h b/src/libcharon/plugins/ipseckey/ipseckey_cred.h new file mode 100644 index 000000000..440020f5d --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey_cred.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup ipseckey_cred_i ipseckey_cred + * @{ @ingroup ipseckey + */ + +#ifndef IPSECKEY_CRED_H_ +#define IPSECKEY_CRED_H_ + +#include <credentials/credential_set.h> +#include <resolver/resolver.h> + +typedef struct ipseckey_cred_t ipseckey_cred_t; + +/** + * IPSECKEY credential set. + * + * The ipseckey credential set contains IPSECKEYs as certificates of type + * pubkey_cert_t. + */ +struct ipseckey_cred_t { + + /** + * Implements credential_set_t interface + */ + credential_set_t set; + + /** + * Destroy the ipseckey_cred. + */ + void (*destroy)(ipseckey_cred_t *this); +}; + +/** + * Create an ipseckey_cred instance which uses the given resolver + * to query the DNS for IPSECKEY resource records. + * + * @param res resolver to use + * @return credential set + */ +ipseckey_cred_t *ipseckey_cred_create(resolver_t *res); + +#endif /** IPSECKEY_CRED_H_ @}*/ diff --git a/src/libcharon/plugins/ipseckey/ipseckey_plugin.c b/src/libcharon/plugins/ipseckey/ipseckey_plugin.c new file mode 100644 index 000000000..6f0f10507 --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey_plugin.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +#include "ipseckey_plugin.h" + +#include <daemon.h> +#include "ipseckey_cred.h" + +typedef struct private_ipseckey_plugin_t private_ipseckey_plugin_t; + + +/** + * private data of the ipseckey plugin + */ +struct private_ipseckey_plugin_t { + + /** + * implements plugin interface + */ + ipseckey_plugin_t public; + + /** + * DNS resolver instance + */ + resolver_t *res; + + /** + * credential set + */ + ipseckey_cred_t *cred; + + /** + * IPSECKEY based authentication enabled + */ + bool enabled; +}; + +METHOD(plugin_t, get_name, char*, + private_ipseckey_plugin_t *this) +{ + return "ipseckey"; +} + +METHOD(plugin_t, destroy, void, + private_ipseckey_plugin_t *this) +{ + if (this->enabled) + { + lib->credmgr->remove_set(lib->credmgr, &this->cred->set); + } + this->res->destroy(this->res); + DESTROY_IF(this->cred); + free(this); +} + +/* + * see header file + */ +plugin_t *ipseckey_plugin_create() +{ + private_ipseckey_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .reload = (void*)return_false, + .destroy = _destroy, + }, + }, + .res = lib->resolver->create(lib->resolver), + .enabled = lib->settings->get_bool(lib->settings, + "charon.plugins.ipseckey.enable", FALSE), + ); + + if (!this->res) + { + DBG1(DBG_CFG, "ipseckey_plugin: Failed to create" + "a DNS resolver instance"); + destroy(this); + return NULL; + } + + if (this->enabled) + { + this->cred = ipseckey_cred_create(this->res); + lib->credmgr->add_set(lib->credmgr, &this->cred->set); + } + + return &this->public.plugin; +} + diff --git a/src/libcharon/plugins/ipseckey/ipseckey_plugin.h b/src/libcharon/plugins/ipseckey/ipseckey_plugin.h new file mode 100644 index 000000000..95acc79dd --- /dev/null +++ b/src/libcharon/plugins/ipseckey/ipseckey_plugin.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup ipseckey ipseckey + * @ingroup cplugins + * + * @defgroup ipseckey_plugin ipseckey_plugin + * @{ @ingroup ipseckey + */ + +#ifndef IPSECKEY_PLUGIN_H_ +#define IPSECKEY_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct ipseckey_plugin_t ipseckey_plugin_t; + +/** + * IPSECKEY plugin + * + * The IPSECKEY plugin registers a credential set for IPSECKEYs. + * + * With this credential set it is possible to authenticate tunnel endpoints + * using IPSECKEY resource records which are retrieved from the DNS in a secure + * way (DNSSEC). + */ +struct ipseckey_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** IPSECKEY_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 9c4665eeb..8d6c4583a 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -26,6 +26,7 @@ networking/host.c networking/host_resolver.c networking/packet.c \ networking/tun_device.c \ pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c \ processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \ +resolver/resolver_manager.c resolver/rr_set.c \ selectors/traffic_selector.c threading/thread.c threading/thread_value.c \ threading/mutex.c threading/semaphore.c threading/rwlock.c threading/spinlock.c \ utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \ @@ -63,6 +64,8 @@ database/database.h database/database_factory.h fetcher/fetcher.h \ fetcher/fetcher_manager.h eap/eap.h pen/pen.h ipsec/ipsec_types.h \ networking/host.h networking/host_resolver.h networking/packet.h \ networking/tun_device.h \ +resolver/resolver.h resolver/resolver_response.h resolver/rr_set.h \ +resolver/rr.h resolver/resolver_manager.h \ plugins/plugin_loader.h plugins/plugin.h plugins/plugin_feature.h \ processing/jobs/job.h processing/jobs/callback_job.h processing/processor.h \ processing/scheduler.h selectors/traffic_selector.h \ @@ -323,6 +326,13 @@ if MONOLITHIC endif endif +if USE_UNBOUND + SUBDIRS += plugins/unbound +if MONOLITHIC + libstrongswan_la_LIBADD += plugins/unbound/libstrongswan-unbound.la +endif +endif + if USE_SOUP SUBDIRS += plugins/soup if MONOLITHIC diff --git a/src/libstrongswan/credentials/cred_encoding.h b/src/libstrongswan/credentials/cred_encoding.h index b029fe2ac..41481f376 100644 --- a/src/libstrongswan/credentials/cred_encoding.h +++ b/src/libstrongswan/credentials/cred_encoding.h @@ -85,6 +85,8 @@ enum cred_encoding_type_t { /** PGP key encoding */ PUBKEY_PGP, PRIVKEY_PGP, + /** DNSKEY encoding */ + PUBKEY_DNSKEY, /** ASN.1 DER encoded certificate */ CERT_ASN1_DER, diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c index 30a7774df..819c6808e 100644 --- a/src/libstrongswan/library.c +++ b/src/libstrongswan/library.c @@ -91,6 +91,7 @@ void library_deinit() this->public.crypto->destroy(this->public.crypto); this->public.proposal->destroy(this->public.proposal); this->public.fetcher->destroy(this->public.fetcher); + this->public.resolver->destroy(this->public.resolver); this->public.db->destroy(this->public.db); this->public.printf_hook->destroy(this->public.printf_hook); this->objects->destroy(this->objects); @@ -214,6 +215,7 @@ bool library_init(char *settings) this->public.credmgr = credential_manager_create(); this->public.encoding = cred_encoding_create(); this->public.fetcher = fetcher_manager_create(); + this->public.resolver = resolver_manager_create(); this->public.db = database_factory_create(); this->public.processor = processor_create(); this->public.scheduler = scheduler_create(); diff --git a/src/libstrongswan/library.h b/src/libstrongswan/library.h index f164a6052..3b6d02002 100644 --- a/src/libstrongswan/library.h +++ b/src/libstrongswan/library.h @@ -49,6 +49,9 @@ * @defgroup fetcher fetcher * @ingroup libstrongswan * + * @defgroup resolver resolver + * @ingroup libstrongswan + * * @defgroup ipsec ipsec * @ingroup libstrongswan * @@ -92,6 +95,7 @@ #include "crypto/crypto_factory.h" #include "crypto/proposal/proposal_keywords.h" #include "fetcher/fetcher_manager.h" +#include "resolver/resolver_manager.h" #include "database/database_factory.h" #include "credentials/credential_factory.h" #include "credentials/credential_manager.h" @@ -162,6 +166,11 @@ struct library_t { fetcher_manager_t *fetcher; /** + * Manager for DNS resolvers + */ + resolver_manager_t *resolver; + + /** * database construction factory */ database_factory_t *db; diff --git a/src/libstrongswan/plugins/dnskey/Makefile.am b/src/libstrongswan/plugins/dnskey/Makefile.am index fbba95e0a..0f2e554c1 100644 --- a/src/libstrongswan/plugins/dnskey/Makefile.am +++ b/src/libstrongswan/plugins/dnskey/Makefile.am @@ -11,6 +11,7 @@ endif libstrongswan_dnskey_la_SOURCES = \ dnskey_plugin.h dnskey_plugin.c \ - dnskey_builder.h dnskey_builder.c + dnskey_builder.h dnskey_builder.c \ + dnskey_encoder.h dnskey_encoder.c libstrongswan_dnskey_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/dnskey/dnskey_builder.c b/src/libstrongswan/plugins/dnskey/dnskey_builder.c index b8a451500..71040437d 100644 --- a/src/libstrongswan/plugins/dnskey/dnskey_builder.c +++ b/src/libstrongswan/plugins/dnskey/dnskey_builder.c @@ -39,8 +39,14 @@ enum dnskey_algorithm_t { DNSKEY_ALG_RSA_MD5 = 1, DNSKEY_ALG_DH = 2, DNSKEY_ALG_DSA = 3, - DNSKEY_ALG_ECC = 4, DNSKEY_ALG_RSA_SHA1 = 5, + DNSKEY_ALG_DSA_NSEC3_SHA1 = 6, + DNSKEY_ALG_RSA_SHA1_NSEC3_SHA1 = 7, + DNSKEY_ALG_RSA_SHA256 = 8, + DNSKEY_ALG_RSA_SHA512 = 10, + DNSKEY_ALG_ECC_GOST = 12, + DNSKEY_ALG_ECDSA_P256_SHA256 = 13, + DNSKEY_ALG_ECDSA_P384_SHA384 = 14 }; /** @@ -59,7 +65,11 @@ static dnskey_public_key_t *parse_public_key(chunk_t blob) switch (rr->algorithm) { + case DNSKEY_ALG_RSA_MD5: case DNSKEY_ALG_RSA_SHA1: + case DNSKEY_ALG_RSA_SHA1_NSEC3_SHA1: + case DNSKEY_ALG_RSA_SHA256: + case DNSKEY_ALG_RSA_SHA512: return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, BUILD_BLOB_DNSKEY, blob, BUILD_END); default: diff --git a/src/libstrongswan/plugins/dnskey/dnskey_encoder.c b/src/libstrongswan/plugins/dnskey/dnskey_encoder.c new file mode 100644 index 000000000..d2b9894b8 --- /dev/null +++ b/src/libstrongswan/plugins/dnskey/dnskey_encoder.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * 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. + */ + +#include "dnskey_encoder.h" + +#include <utils/debug.h> + +/** + * Encode an RSA public key in DNSKEY format (RFC 3110) + */ +bool build_pub(chunk_t *encoding, va_list args) +{ + chunk_t n, e, pubkey; + size_t exp_len; + u_char *pos; + + if (cred_encoding_args(args, CRED_PART_RSA_MODULUS, &n, + CRED_PART_RSA_PUB_EXP, &e, CRED_PART_END)) + { + /* remove leading zeros in exponent and modulus */ + while (*e.ptr == 0) + { + e = chunk_skip(e, 1); + } + while (*n.ptr == 0) + { + n = chunk_skip(n, 1); + } + + if (e.len < 256) + { + /* exponent length fits into a single octet */ + exp_len = 1; + pubkey = chunk_alloc(exp_len + e.len + n.len); + pubkey.ptr[0] = (char)e.len; + } + else if (e.len < 65536) + { + /* exponent length fits into two octets preceded by zero octet */ + exp_len = 3; + pubkey = chunk_alloc(exp_len + e.len + n.len); + pubkey.ptr[0] = 0x00; + htoun16(pubkey.ptr + 1, e.len); + } + else + { + /* exponent length is too large */ + return FALSE; + } + + /* copy exponent and modulus and convert to base64 format */ + pos = pubkey.ptr + exp_len; + memcpy(pos, e.ptr, e.len); + pos += e.len; + memcpy(pos, n.ptr, n.len); + *encoding = chunk_to_base64(pubkey, NULL); + chunk_free(&pubkey); + + return TRUE; + } + return FALSE; +} + +/** + * See header. + */ +bool dnskey_encoder_encode(cred_encoding_type_t type, chunk_t *encoding, + va_list args) +{ + switch (type) + { + case PUBKEY_DNSKEY: + return build_pub(encoding, args); + default: + return FALSE; + } +} + + diff --git a/src/libstrongswan/plugins/dnskey/dnskey_encoder.h b/src/libstrongswan/plugins/dnskey/dnskey_encoder.h new file mode 100644 index 000000000..698d29301 --- /dev/null +++ b/src/libstrongswan/plugins/dnskey/dnskey_encoder.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup dnskey_encoder dnskey_encoder + * @{ @ingroup dnskey + */ + +#ifndef DNSKEY_ENCODER_H_ +#define DNSKEY_ENCODER_H_ + +#include <credentials/cred_encoding.h> + +/** + * Encoding function for DNSKEY (RFC 3110) public key format. + */ +bool dnskey_encoder_encode(cred_encoding_type_t type, chunk_t *encoding, + va_list args); + +#endif /** DNSKEY_ENCODER_H_ @}*/ diff --git a/src/libstrongswan/plugins/dnskey/dnskey_plugin.c b/src/libstrongswan/plugins/dnskey/dnskey_plugin.c index b6863e8e3..9a4f6252f 100644 --- a/src/libstrongswan/plugins/dnskey/dnskey_plugin.c +++ b/src/libstrongswan/plugins/dnskey/dnskey_plugin.c @@ -17,6 +17,7 @@ #include <library.h> #include "dnskey_builder.h" +#include "dnskey_encoder.h" typedef struct private_dnskey_plugin_t private_dnskey_plugin_t; @@ -53,6 +54,8 @@ METHOD(plugin_t, get_features, int, METHOD(plugin_t, destroy, void, private_dnskey_plugin_t *this) { + lib->encoding->remove_encoder(lib->encoding, dnskey_encoder_encode); + free(this); } @@ -73,6 +76,8 @@ plugin_t *dnskey_plugin_create() }, ); + lib->encoding->add_encoder(lib->encoding, dnskey_encoder_encode); + return &this->public.plugin; } diff --git a/src/libstrongswan/plugins/unbound/Makefile.am b/src/libstrongswan/plugins/unbound/Makefile.am new file mode 100644 index 000000000..efb313407 --- /dev/null +++ b/src/libstrongswan/plugins/unbound/Makefile.am @@ -0,0 +1,20 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${sysconfdir}\" + + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-unbound.la +else +plugin_LTLIBRARIES = libstrongswan-unbound.la +endif + +libstrongswan_unbound_la_SOURCES = \ + unbound_plugin.h unbound_plugin.c \ + unbound_resolver.c unbound_resolver.h \ + unbound_rr.h unbound_rr.c \ + unbound_response.h unbound_response.c + +libstrongswan_unbound_la_LDFLAGS = -module -avoid-version +libstrongswan_unbound_la_LIBADD = -lunbound -lldns diff --git a/src/libstrongswan/plugins/unbound/unbound_plugin.c b/src/libstrongswan/plugins/unbound/unbound_plugin.c new file mode 100644 index 000000000..90b95330a --- /dev/null +++ b/src/libstrongswan/plugins/unbound/unbound_plugin.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2011-2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +#include "unbound_plugin.h" + +#include <library.h> +#include "unbound_resolver.h" + +typedef struct private_unbound_plugin_t private_unbound_plugin_t; + +/** + * private data of unbound_plugin + */ +struct private_unbound_plugin_t { + + /** + * public functions + */ + unbound_plugin_t public; +}; + +METHOD(plugin_t, get_name, char*, + private_unbound_plugin_t *this) +{ + return "unbound"; +} + +METHOD(plugin_t, destroy, void, + private_unbound_plugin_t *this) +{ + lib->resolver->remove_resolver(lib->resolver, unbound_resolver_create); + free(this); +} + +/* + * see header file + */ +plugin_t *unbound_plugin_create() +{ + private_unbound_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .destroy = _destroy, + }, + }, + ); + + lib->resolver->add_resolver(lib->resolver, unbound_resolver_create); + + return &this->public.plugin; +} diff --git a/src/libstrongswan/plugins/unbound/unbound_plugin.h b/src/libstrongswan/plugins/unbound/unbound_plugin.h new file mode 100644 index 000000000..1f0d36454 --- /dev/null +++ b/src/libstrongswan/plugins/unbound/unbound_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011-2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup unbound_p unbound + * @ingroup plugins + * + * @defgroup unbound_plugin unbound_plugin + * @{ @ingroup unbound_p + */ + +#ifndef unbound_PLUGIN_H_ +#define unbound_PLUGIN_H_ + +#include <plugins/plugin.h> + +typedef struct unbound_plugin_t unbound_plugin_t; + +/** + * Plugin implementing the resolver interface using the libunbound DNS library. + */ +struct unbound_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** unbound_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/unbound/unbound_resolver.c b/src/libstrongswan/plugins/unbound/unbound_resolver.c new file mode 100644 index 000000000..44a2c764b --- /dev/null +++ b/src/libstrongswan/plugins/unbound/unbound_resolver.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2011-2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +#include <unbound.h> +#include <errno.h> +#include <ldns/ldns.h> +#include <string.h> + +#include <library.h> +#include <utils/debug.h> + +#include "unbound_resolver.h" +#include "unbound_response.h" + +/* DNS resolver configuration and DNSSEC trust anchors */ +#define RESOLV_CONF_FILE "/etc/resolv.conf" +#define TRUST_ANCHOR_FILE IPSEC_CONFDIR "/ipsec.d/dnssec.keys" + +typedef struct private_resolver_t private_resolver_t; + +/** + * private data of a unbound_resolver_t object. + */ +struct private_resolver_t { + + /** + * Public data + */ + resolver_t public; + + /** + * private unbound resolver handle (unbound context) + */ + struct ub_ctx *ctx; +}; + +/** + * query method implementation + */ +METHOD(resolver_t, query, resolver_response_t*, + private_resolver_t *this, char *domain, rr_class_t rr_class, + rr_type_t rr_type) +{ + unbound_response_t *response = NULL; + struct ub_result *result = NULL; + int ub_retval; + + ub_retval = ub_resolve(this->ctx, domain, rr_type, rr_class, &result); + if (ub_retval) + { + DBG1(DBG_LIB, "unbound resolver error: %s", ub_strerror(ub_retval)); + ub_resolve_free(result); + return NULL; + } + + response = unbound_response_create_frm_libub_response(result); + if (!response) + { + DBG1(DBG_LIB, "unbound resolver failed to create response"); + ub_resolve_free(result); + return NULL; + } + ub_resolve_free(result); + + return (resolver_response_t*)response; +} + +/** + * destroy method implementation + */ +METHOD(resolver_t, destroy, void, + private_resolver_t *this) +{ + ub_ctx_delete(this->ctx); + free(this); +} + +/* + * Described in header. + */ +resolver_t *unbound_resolver_create(void) +{ + private_resolver_t *this; + int ub_retval = 0; + char *resolv_conf_file; + char *trust_anchor_file; + + resolv_conf_file = lib->settings->get_str(lib->settings, + "libstrongswan.plugins.unbound.resolv_conf", + RESOLV_CONF_FILE); + + trust_anchor_file = lib->settings->get_str(lib->settings, + "libstrongswan.plugins.unbound.trust_anchors", + TRUST_ANCHOR_FILE); + + INIT(this, + .public = { + .query = _query, + .destroy = _destroy, + }, + ); + + this->ctx = ub_ctx_create(); + if (!this->ctx) + { + DBG1(DBG_LIB, "failed to create unbound resolver context"); + destroy(this); + return NULL; + } + + DBG1(DBG_CFG, "loading unbound resolver config from '%s'", resolv_conf_file); + ub_retval = ub_ctx_resolvconf(this->ctx, resolv_conf_file); + if (ub_retval) + { + DBG1(DBG_CFG, "failed to read the resolver config: %s (%s)", + ub_strerror(ub_retval), strerror(errno)); + destroy(this); + return NULL; + } + + DBG1(DBG_CFG, "loading unbound trust anchors from '%s'", trust_anchor_file); + ub_retval = ub_ctx_add_ta_file(this->ctx, trust_anchor_file); + if (ub_retval) + { + DBG1(DBG_CFG, "failed to load trust anchors: %s (%s)", + ub_strerror(ub_retval), strerror(errno)); + } + + return &this->public; +} + diff --git a/src/libstrongswan/plugins/unbound/unbound_resolver.h b/src/libstrongswan/plugins/unbound/unbound_resolver.h new file mode 100644 index 000000000..818a717b8 --- /dev/null +++ b/src/libstrongswan/plugins/unbound/unbound_resolver.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011-2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup unbound_resolver unbound_resolver + * @{ @ingroup unbound_p + */ + +#ifndef unbound_RESOLVER_H_ +#define unbound_RESOLVER_H_ + +/** + * Create a resolver_t instance. + */ +resolver_t *unbound_resolver_create(void); + +#endif /** LIBunbound_RESOLVER_H_ @}*/ diff --git a/src/libstrongswan/plugins/unbound/unbound_response.c b/src/libstrongswan/plugins/unbound/unbound_response.c new file mode 100644 index 000000000..6f6c25e89 --- /dev/null +++ b/src/libstrongswan/plugins/unbound/unbound_response.c @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +#include <resolver/resolver_response.h> +#include <resolver/rr.h> +#include "unbound_rr.h" +#include "unbound_response.h" + +#include <library.h> +#include <utils/debug.h> + +#include <unbound.h> +#include <ldns/ldns.h> + +typedef struct private_unbound_response_t private_unbound_response_t; + +/** + * private data of an unbound_response_t object. + */ +struct private_unbound_response_t { + + /** + * Public data + */ + unbound_response_t public; + + /** + * Original question string + */ + char* query_name; + + /** + * Canonical name of the response + */ + char* canon_name; + + /** + * Are the some RRs in the RRset of this response? + */ + bool has_data; + + /* + * Does the queried name exist? + */ + bool query_name_exist; + + /** + * DNSSEC security state + */ + dnssec_status_t security_state; + + /** + * RRset + */ + rr_set_t *rr_set; +}; + +METHOD(resolver_response_t, get_query_name, char*, + private_unbound_response_t *this) +{ + return this->query_name; +} + +METHOD(resolver_response_t, get_canon_name, char*, + private_unbound_response_t *this) +{ + return this->canon_name; +} + +METHOD(resolver_response_t, has_data, bool, + private_unbound_response_t *this) +{ + return this->has_data; +} + +METHOD(resolver_response_t, query_name_exist, bool, + private_unbound_response_t *this) +{ + return this->query_name_exist; +} + +METHOD(resolver_response_t, get_security_state, dnssec_status_t, + private_unbound_response_t *this) +{ + return this->security_state; +} + +METHOD(resolver_response_t, get_rr_set, rr_set_t*, + private_unbound_response_t *this) +{ + return this->rr_set; +} + +METHOD(resolver_response_t, destroy, void, + private_unbound_response_t *this) +{ + free(this->query_name); + free(this->canon_name); + DESTROY_IF(this->rr_set); + free(this); +} + +/* + * Described in header. + */ +unbound_response_t *unbound_response_create_frm_libub_response( + struct ub_result *libub_response) +{ + private_unbound_response_t *this = NULL; + + INIT(this, + .public = { + .interface = { + .get_query_name = _get_query_name, + .get_canon_name = _get_canon_name, + .has_data = _has_data, + .query_name_exist = _query_name_exist, + .get_security_state = _get_security_state, + .get_rr_set = _get_rr_set, + .destroy = _destroy, + }, + }, + ); + + this->query_name = strdup(libub_response->qname); + + if (libub_response->canonname) + { + this->canon_name = strdup(libub_response->canonname); + } + + this->has_data = libub_response->havedata; + + this->query_name_exist = !(libub_response->nxdomain); + + if (libub_response->secure) + { + this->security_state = SECURE; + } + else if (libub_response->bogus) + { + this->security_state = BOGUS; + } + else + { + this->security_state = INDETERMINATE; + } + + /** + * Create RRset + */ + if (this->query_name_exist && this->has_data) + { + ldns_pkt *dns_pkt = NULL; + ldns_rr_list *orig_rr_list = NULL; + size_t orig_rr_count; + ldns_rr *orig_rr = NULL; + ldns_rdf *orig_rdf = NULL; + ldns_status status; + linked_list_t *rr_list = NULL, *rrsig_list = NULL; + unbound_rr_t *rr = NULL; + int i; + + /**Parse the received DNS packet using the ldns library */ + status = ldns_wire2pkt(&dns_pkt, libub_response->answer_packet, + libub_response->answer_len); + + if (status != LDNS_STATUS_OK) + { + DBG1(DBG_LIB, "failed to parse DNS packet"); + destroy(this); + return NULL; + } + + /* Create a list with the queried RRs. If there are corresponding RRSIGs + * create also a list with these. + */ + rr_list = linked_list_create(); + + orig_rr_list = ldns_pkt_get_section_clone(dns_pkt, LDNS_SECTION_ANSWER); + orig_rr_count = ldns_rr_list_rr_count(orig_rr_list); + + for (i = 0; i < orig_rr_count; i++) + { + orig_rr = ldns_rr_list_rr(orig_rr_list, i); + + if (ldns_rr_get_type(orig_rr) == libub_response->qtype && + ldns_rr_get_class(orig_rr) == libub_response->qclass) + { + /* RR is part of the queried RRset. + * => add it to the list of Resource Records. + */ + rr = unbound_rr_create_frm_ldns_rr(orig_rr); + if (rr) + { + rr_list->insert_last(rr_list, rr); + } + else + { + DBG1(DBG_LIB, "failed to create RR"); + } + } + + if (ldns_rr_get_type(orig_rr) == LDNS_RR_TYPE_RRSIG) + { + orig_rdf = ldns_rr_rrsig_typecovered(orig_rr); + if (!orig_rdf) + { + DBG1(DBG_LIB, "failed to get the type covered by an RRSIG"); + } + else if (ldns_rdf2native_int16(orig_rdf) == libub_response->qtype) + { + /* The current RR represent a signature (RRSIG) + * which belongs to the queried RRset. + * => add it to the list of signatures. + */ + rr = unbound_rr_create_frm_ldns_rr(orig_rr); + if (rr) + { + if (!rrsig_list) + { + rrsig_list = linked_list_create(); + } + rrsig_list->insert_last(rrsig_list, rr); + } + else + { + DBG1(DBG_LIB, "failed to create RRSIG"); + } + } + else + { + DBG1(DBG_LIB, "failed to determine the RR type " + "covered by RRSIG RR"); + } + } + } + /** + * Create the RRset for which the query was performed. + */ + this->rr_set = rr_set_create(rr_list, rrsig_list); + + ldns_pkt_free(dns_pkt); + ldns_rr_list_free(orig_rr_list); + } + return &this->public; +} diff --git a/src/libstrongswan/plugins/unbound/unbound_response.h b/src/libstrongswan/plugins/unbound/unbound_response.h new file mode 100644 index 000000000..d63ead08b --- /dev/null +++ b/src/libstrongswan/plugins/unbound/unbound_response.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup unbound_response unbound_response + * @{ @ingroup unbound_p + */ + +#ifndef UNBOUND_RESPONSE_H_ +#define UNBOUND_RESPONSE_H_ + +#include <resolver/resolver_response.h> +#include <unbound.h> + +typedef struct unbound_response_t unbound_response_t; + +/** + * Implementation of the resolver_response interface using libunbound. + * + */ +struct unbound_response_t { + + /** + * Implements the resolver_response interface + */ + resolver_response_t interface; +}; + +/** + * Create an unbound_response instance from a response of the unbound library. + * + * @param a response of the unbound library + * @return an unbound_response conforming to the resolver_response + * interface, or NULL on failure + */ +unbound_response_t *unbound_response_create_frm_libub_response( + struct ub_result *libub_response); + +#endif /** UNBOUND_RESPONSE_H_ @}*/ diff --git a/src/libstrongswan/plugins/unbound/unbound_rr.c b/src/libstrongswan/plugins/unbound/unbound_rr.c new file mode 100644 index 000000000..97c3b1933 --- /dev/null +++ b/src/libstrongswan/plugins/unbound/unbound_rr.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +#include <resolver/rr.h> + +#include <library.h> +#include <utils/debug.h> + +#include <stdlib.h> +#include <string.h> + +#include "unbound_rr.h" + +typedef struct private_unbound_rr_t private_unbound_rr_t; + +/** + * private data of an unbound_rr_t object. + */ +struct private_unbound_rr_t { + + /** + * Public data + */ + unbound_rr_t public; + + /** + * Owner name + */ + char* name; + + /** + * Type + */ + rr_type_t type; + + /** + * Class + */ + rr_class_t class; + + /** + * TTL + */ + uint32_t ttl; + + /** + * Size of the rdata field in octets + */ + uint16_t size; + + /** + * RDATA field (array of bytes in network order) + */ + u_char *rdata; +}; + +METHOD(rr_t, get_name, char *, + private_unbound_rr_t *this) +{ + return this->name; +} + +METHOD(rr_t, get_type, rr_type_t, + private_unbound_rr_t *this) +{ + return this->type; +} + +METHOD(rr_t, get_class, rr_class_t, + private_unbound_rr_t *this) +{ + return this->class; +} + +METHOD(rr_t, get_ttl, uint32_t, + private_unbound_rr_t *this) +{ + return this->ttl; +} + +METHOD(rr_t, get_rdata, chunk_t, + private_unbound_rr_t *this) +{ + return chunk_create(this->rdata, this->size); +} + +METHOD(rr_t, destroy, void, + private_unbound_rr_t *this) +{ + free(this->name); + free(this->rdata); + free(this); +} + +/* + * Described in header. + */ +unbound_rr_t *unbound_rr_create_frm_ldns_rr(ldns_rr *rr) +{ + private_unbound_rr_t *this; + ldns_status status; + ldns_buffer *buf; + int i; + + INIT(this, + .public = { + .interface = { + .get_name = _get_name, + .get_type = _get_type, + .get_class = _get_class, + .get_ttl = _get_ttl, + .get_rdata = _get_rdata, + .destroy = _destroy, + }, + }, + ); + + this->name = ldns_rdf2str(ldns_rr_owner(rr)); + if (!this->name) + { + DBG1(DBG_LIB, "failed to parse the owner name of a DNS RR"); + _destroy(this); + return NULL; + } + + this->type = ldns_rr_get_type(rr); + this->class = ldns_rr_get_class(rr); + this->ttl = ldns_rr_ttl(rr); + for(i = 0; i < ldns_rr_rd_count(rr); i++) + { + this->size += ldns_rdf_size(ldns_rr_rdf(rr, i)); + } + + /** + * The ldns library splits the RDATA field of a RR in various rdf. + * Here we reassemble these rdf to get the RDATA field of the RR. + */ + buf = ldns_buffer_new(LDNS_MIN_BUFLEN); + /* The buffer will be resized automatically by ldns_rr_rdata2buffer_wire() */ + status = ldns_rr_rdata2buffer_wire(buf, rr); + + if (status != LDNS_STATUS_OK) + { + DBG1(DBG_LIB, "failed to get the RDATA field of a DNS RR"); + _destroy(this); + return NULL; + } + + this->rdata = ldns_buffer_export(buf); + + return &this->public; +} diff --git a/src/libstrongswan/plugins/unbound/unbound_rr.h b/src/libstrongswan/plugins/unbound/unbound_rr.h new file mode 100644 index 000000000..d7c114f86 --- /dev/null +++ b/src/libstrongswan/plugins/unbound/unbound_rr.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup unbound_rr unbound_rr + * @{ @ingroup unbound_p + */ + +#ifndef UNBOUND_RR_H_ +#define UNBOUND_RR_H_ + +#include <resolver/rr.h> +#include <ldns/ldns.h> + +typedef struct unbound_rr_t unbound_rr_t; + +/** + * Implementation of the Resource Record interface using libunbound and libldns. + */ +struct unbound_rr_t { + + /** + * Implements the Resource Record interface + */ + rr_t interface; +}; + +/** + * Create an unbound_rr instance from a Resource Record given by + * a ldns_struct_rr from the ldns library. + * + * @return Resource Record, NULL on error + */ +unbound_rr_t *unbound_rr_create_frm_ldns_rr(ldns_rr *rr); + +#endif /** UNBOUND_RR_H_ @}*/ diff --git a/src/libstrongswan/resolver/resolver.h b/src/libstrongswan/resolver/resolver.h new file mode 100644 index 000000000..5be52b8b1 --- /dev/null +++ b/src/libstrongswan/resolver/resolver.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011-2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup resolveri resolver + * @{ @ingroup resolver + */ + +#ifndef RESOLVER_H_ +#define RESOLVER_H_ + +typedef struct resolver_t resolver_t; + +/** + * Constructor function which creates DNS resolver instances. + */ +typedef resolver_t* (*resolver_constructor_t)(void); + +#include <resolver/resolver_response.h> +#include <resolver/rr_set.h> +#include <resolver/rr.h> + +/** + * Interface of a security-aware DNS resolver. + * + */ +struct resolver_t { + + /** + * Perform a DNS query. + * + * @param domain domain (FQDN) to query + * @param rr_class class of the desired RRs + * @param rr_type type of the desired RRs + * @return response to the query, NULL on failure + */ + resolver_response_t *(*query)(resolver_t *this, char *domain, + rr_class_t rr_class, rr_type_t rr_type); + + /** + * Destroy the resolver instance. + */ + void (*destroy)(resolver_t *this); +}; + +#endif /** RESOLVER_H_ @}*/ diff --git a/src/libstrongswan/resolver/resolver_manager.c b/src/libstrongswan/resolver/resolver_manager.c new file mode 100644 index 000000000..8effe469a --- /dev/null +++ b/src/libstrongswan/resolver/resolver_manager.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011-2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +#include "resolver_manager.h" + +#include <utils/debug.h> + +typedef struct private_resolver_manager_t private_resolver_manager_t; + +/** + * private data of resolver_manager + */ +struct private_resolver_manager_t { + + /** + * public functions + */ + resolver_manager_t public; + + /** + * constructor function to create resolver instances + */ + resolver_constructor_t constructor; +}; + +METHOD(resolver_manager_t, add_resolver, void, + private_resolver_manager_t *this, resolver_constructor_t constructor) +{ + if (!this->constructor) + { + this->constructor = constructor; + } +} + +METHOD(resolver_manager_t, remove_resolver, void, + private_resolver_manager_t *this, resolver_constructor_t constructor) +{ + if (this->constructor == constructor) + { + this->constructor = NULL; + } +} + +METHOD(resolver_manager_t, create, resolver_t*, + private_resolver_manager_t *this) +{ + return this->constructor(); +} + +METHOD(resolver_manager_t, destroy, void, + private_resolver_manager_t *this) +{ + free(this); +} + +/* + * See header + */ +resolver_manager_t *resolver_manager_create() +{ + private_resolver_manager_t *this; + + INIT(this, + .public = { + .add_resolver = _add_resolver, + .remove_resolver = _remove_resolver, + .create = _create, + .destroy = _destroy, + }, + ); + + return &this->public; +} + diff --git a/src/libstrongswan/resolver/resolver_manager.h b/src/libstrongswan/resolver/resolver_manager.h new file mode 100644 index 000000000..6ea22aa24 --- /dev/null +++ b/src/libstrongswan/resolver/resolver_manager.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011-2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** +* @defgroup resolver_manager resolver_manager +* @{ @ingroup resolver +*/ + +#ifndef RESOLVER_MANAGER_H_ +#define RESOLVER_MANAGER_H_ + +typedef struct resolver_manager_t resolver_manager_t; + +#include <resolver/resolver.h> + +/** + * The resolver_manager manages the resolver implementations and + * creates instances of them. + * + * A resolver plugin is registered by providing its constructor function + * to the manager. The manager creates instances of the resolver plugin + * using the registered constructor function. + */ +struct resolver_manager_t { + + /** + * Register a resolver implementation. + * + * @param constructor resolver constructor function + */ + void (*add_resolver)(resolver_manager_t *this, + resolver_constructor_t constructor); + + /** + * Unregister a previously registered resolver implementation. + * + * @param constructor resolver constructor function to unregister + */ + void (*remove_resolver)(resolver_manager_t *this, + resolver_constructor_t constructor); + + /** + * Get a new resolver instance. + * + * @return resolver instance. + */ + resolver_t* (*create)(resolver_manager_t *this); + + /** + * Destroy a resolver_manager instance. + */ + void (*destroy)(resolver_manager_t *this); +}; + +/** + * Create a resolver_manager instance. + */ +resolver_manager_t *resolver_manager_create(); + +#endif /** RESOLVER_MANAGER_H_ @}*/ diff --git a/src/libstrongswan/resolver/resolver_response.h b/src/libstrongswan/resolver/resolver_response.h new file mode 100644 index 000000000..e45fb6401 --- /dev/null +++ b/src/libstrongswan/resolver/resolver_response.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup rsolver_response resolver_response + * @{ @ingroup resolver + */ + +#ifndef RESOLVER_RESPONSE_H_ +#define RESOLVER_RESPONSE_H_ + +typedef struct resolver_response_t resolver_response_t; +typedef enum dnssec_status_t dnssec_status_t; + +#include <library.h> +#include <resolver/rr_set.h> + +/** + * DNSSEC security state. + * + * DNSSEC security state, which a security aware resolver is able determine + * according to RFC 4033. + */ +enum dnssec_status_t { + /** + * The validating resolver has a trust anchor, has a chain of + * trust, and is able to verify all the signatures in the response. + * [RFC4033] + */ + SECURE, + /** + * The validating resolver has a trust anchor, a chain of + * trust, and, at some delegation point, signed proof of the + * non-existence of a DS record. This indicates that subsequent + * branches in the tree are provably insecure. A validating resolver + * may have a local policy to mark parts of the domain space as + * insecure. [RFC4033] + */ + INSECURE, + /** + * The validating resolver has a trust anchor and a secure + * delegation indicating that subsidiary data is signed, but the + * response fails to validate for some reason: missing signatures, + * expired signatures, signatures with unsupported algorithms, data + * missing that the relevant NSEC RR says should be present, and so + * forth. [RFC4033] + */ + BOGUS, + /** + * There is no trust anchor that would indicate that a + * specific portion of the tree is secure. This is the default + * operation mode. [RFC4033] + */ + INDETERMINATE, +}; + + +/** + * A response of the DNS resolver to a DNS query. + * + * A response represents the answer of the Domain Name System to a query. + * It contains the RRset with the queried Resource Records and additional + * information. + */ +struct resolver_response_t { + + /** + * Get the original question string. + * + * The string to which the returned pointer points, is still owned + * by the resolver_response. Clone it if necessary. + * + * @return the queried name + */ + char *(*get_query_name)(resolver_response_t *this); + + /** + * Get the canonical name of the result. + * + * The string to which the returned pointer points, is still owned + * by the resolver_response. Clone it if necessary. + * + * @return - canonical name of result + * - NULL, if result has no canonical name + */ + char *(*get_canon_name)(resolver_response_t *this); + + /** + * Does the RRset of this response contain some Resource Records? + * + * Returns TRUE if the RRset of this response contains some RRs + * (RRSIG Resource Records are ignored). + * + * @return + * - TRUE, if there are some RRs in the RRset + * - FALSE, otherwise + */ + bool (*has_data)(resolver_response_t *this); + + /** + * Does the queried name exist? + * + * @return + * - TRUE, if the queried name exists + * - FALSE, otherwise + */ + bool (*query_name_exist)(resolver_response_t *this); + + /** + * Get the DNSSEC security state of the response. + * + * @return DNSSEC security state + */ + dnssec_status_t (*get_security_state)(resolver_response_t *this); + + /** + * Get the RRset with all Resource Records of this response. + * + * @return - RRset + * - NULL if there is no data or the query name + * does not exist + */ + rr_set_t *(*get_rr_set)(resolver_response_t *this); + + /** + * Destroy this response. + */ + void (*destroy) (resolver_response_t *this); +}; + +#endif /** RR_SET_H_ @}*/ diff --git a/src/libstrongswan/resolver/rr.h b/src/libstrongswan/resolver/rr.h new file mode 100644 index 000000000..109ec5135 --- /dev/null +++ b/src/libstrongswan/resolver/rr.h @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup rr rr + * @{ @ingroup resolver + */ + +#ifndef RR_H_ +#define RR_H_ + +typedef struct rr_t rr_t; +typedef enum rr_type_t rr_type_t; +typedef enum rr_class_t rr_class_t; + +#include <library.h> + +/** + * Resource Record types. + * + * According to www.iana.org/assignments/dns-parameters (version 2012-03-13). + */ +enum rr_type_t { + /** a host address */ + RR_TYPE_A = 1, + /** an authoritative name server */ + RR_TYPE_NS = 2, + //** a mail destination (OBSOLETE - use MX */ + RR_TYPE_MD = 3, + /** a mail forwarder (OBSOLETE - use MX) */ + RR_TYPE_MF = 4, + /** the canonical name for an alias */ + RR_TYPE_CNAME = 5, + /** marks the start of a zone of authority */ + RR_TYPE_SOA = 6, + /** a mailbox domain name (EXPERIMENTAL) */ + RR_TYPE_MB = 7, + /** a mail group member (EXPERIMENTAL) */ + RR_TYPE_MG = 8, + /** a mail rename domain name (EXPERIMENTAL) */ + RR_TYPE_MR = 9, + /** a null RR (EXPERIMENTAL) */ + RR_TYPE_NULL = 10, + /** a well known service description */ + RR_TYPE_WKS = 11, + /** a domain name pointer */ + RR_TYPE_PTR = 12, + /** host information */ + RR_TYPE_HINFO = 13, + /** mailbox or mail list information */ + RR_TYPE_MINFO = 14, + /** mail exchange */ + RR_TYPE_MX = 15, + /** text strings */ + RR_TYPE_TXT = 16, + /** for Responsible Person */ + RR_TYPE_RP = 17, + /** for AFS Data Base location */ + RR_TYPE_AFSDB = 18, + /** for X.25 PSDN address */ + RR_TYPE_X25 = 19, + /** for ISDN address */ + RR_TYPE_ISDN = 20, + /** for Route Through */ + RR_TYPE_RT = 21, + /** for NSAP address, NSAP style A record */ + RR_TYPE_NSAP = 22, + /** for domain name pointer, NSAP style */ + RR_TYPE_NSAP_PTR = 23, + /** for security signature */ + RR_TYPE_SIG = 24, + /** for security key */ + RR_TYPE_KEY = 25, + /** X.400 mail mapping information */ + RR_TYPE_PX = 26, + /** Geographical Position */ + RR_TYPE_GPOS = 27, + /** ipv6 address */ + RR_TYPE_AAAA = 28, + /** Location Information */ + RR_TYPE_LOC = 29, + /** Next Domain (OBSOLETE) */ + RR_TYPE_NXT = 30, + /** Endpoint Identifier */ + RR_TYPE_EID = 31, + /** Nimrod Locator */ + RR_TYPE_NIMLOC = 32, + /** Server Selection */ + RR_TYPE_SRV = 33, + /** ATM Address */ + RR_TYPE_ATMA = 34, + /** Naming Authority Pointer */ + RR_TYPE_NAPTR = 35, + /** Key Exchanger */ + RR_TYPE_KX = 36, + /** CERT */ + RR_TYPE_CERT = 37, + /** A6 (OBSOLETE - use AAAA) */ + RR_TYPE_A6 = 38, + /** DNAME */ + RR_TYPE_DNAME = 39, + /** SINK */ + RR_TYPE_SINK = 40, + /** OPT */ + RR_TYPE_OPT = 41, + /** APL */ + RR_TYPE_APL = 42, + /** Delegation Signer */ + RR_TYPE_DS = 43, + /** SSH Key Fingerprint */ + RR_TYPE_SSHFP = 44, + /** IPSECKEY */ + RR_TYPE_IPSECKEY = 45, + /** RRSIG */ + RR_TYPE_RRSIG = 46, + /** NSEC */ + RR_TYPE_NSEC = 47, + /** DNSKEY */ + RR_TYPE_DNSKEY = 48, + /** DHCID */ + RR_TYPE_DHCID = 49, + /** NSEC3 */ + RR_TYPE_NSEC3 = 50, + /** NSEC3PARAM */ + RR_TYPE_NSEC3PARAM = 51, + + /** Unassigned 52-54 */ + + /** Host Identity Protocol */ + RR_TYPE_HIP = 55, + /** NINFO */ + RR_TYPE_NINFO = 56, + /** RKEY */ + RR_TYPE_RKEY = 57, + /** Trust Anchor LINK */ + RR_TYPE_TALINK = 58, + /** Child DS */ + RR_TYPE_CDS = 59, + + /** Unassigned 60-98 */ + + /** SPF */ + RR_TYPE_SPF = 99, + /** UINFO */ + RR_TYPE_UINFO = 100, + /** UID */ + RR_TYPE_UID = 101, + /** GID */ + RR_TYPE_GID = 102, + /** UNSPEC */ + RR_TYPE_UNSPEC = 103, + + /** Unassigned 104-248 */ + + /** Transaction Key */ + RR_TYPE_TKEY = 249, + /** Transaction Signature */ + RR_TYPE_TSIG = 250, + /** incremental transfer */ + RR_TYPE_IXFR = 251, + /** transfer of an entire zone */ + RR_TYPE_AXFR = 252, + /** mailbox-related RRs (MB, MG or MR) */ + RR_TYPE_MAILB = 253, + /** mail agent RRs (OBSOLETE - see MX) */ + RR_TYPE_MAILA = 254, + /** A request for all records */ + RR_TYPE_ANY = 255, + /** URI */ + RR_TYPE_URI = 256, + /** Certification Authority Authorization */ + RR_TYPE_CAA = 257, + + /** Unassigned 258-32767 */ + + /** DNSSEC Trust Authorities */ + RR_TYPE_TA = 32768, + /** DNSSEC Lookaside Validation */ + RR_TYPE_DLV = 32769, + + /** Unassigned 32770-65279 */ + + /** Private use 65280-65534 */ + + /** Reserved 65535 */ +}; + + +/** + * Resource Record CLASSes + */ +enum rr_class_t { + /** Internet */ + RR_CLASS_IN = 1, + /** Chaos */ + RR_CLASS_CH = 3, + /** Hesiod */ + RR_CLASS_HS = 4, + /** further CLASSes: http://wwwiana.org/assignments/dns-parameters */ +}; + + +/** + * A DNS Resource Record. + * + * Represents a Resource Record of the Domain Name System + * as defined in RFC 1035. + * + */ +struct rr_t { + + /** + * Get the NAME of the owner of this RR. + * + * @return owner name as string + */ + char *(*get_name)(rr_t *this); + + /** + * Get the type of this RR. + * + * @return RR type + */ + rr_type_t (*get_type)(rr_t *this); + + /** + * Get the class of this RR. + * + * @return RR class + */ + rr_class_t (*get_class)(rr_t *this); + + /** + * Get the Time to Live (TTL) of this RR. + * + * @return Time to Live + */ + uint32_t (*get_ttl)(rr_t *this); + + /** + * Get the content of the RDATA field as chunk. + * + * The data pointed by the chunk is still owned by the RR. + * Clone it if needed. + * + * @return RDATA field as chunk + */ + chunk_t (*get_rdata)(rr_t *this); + + /** + * Destroy the Resource Record. + */ + void (*destroy) (rr_t *this); +}; + +#endif /** RR_H_ @}*/ diff --git a/src/libstrongswan/resolver/rr_set.c b/src/libstrongswan/resolver/rr_set.c new file mode 100644 index 000000000..dea5c4086 --- /dev/null +++ b/src/libstrongswan/resolver/rr_set.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +#include "rr_set.h" + +#include <library.h> +#include <utils/debug.h> + +typedef struct private_rr_set_t private_rr_set_t; + +/** +* private data of the rr_set +*/ +struct private_rr_set_t { + + /** + * public functions + */ + rr_set_t public; + + /** + * List of Resource Records which form the RRset + */ + linked_list_t *rr_list; + + /** + * List of the signatures (RRSIGs) of the Resource Records contained in + * this set + */ + linked_list_t *rrsig_list; +}; + +METHOD(rr_set_t, create_rr_enumerator, enumerator_t*, + private_rr_set_t *this) +{ + return this->rr_list->create_enumerator(this->rr_list); +} + +METHOD(rr_set_t, create_rrsig_enumerator, enumerator_t*, + private_rr_set_t *this) +{ + if (this->rrsig_list) + { + return this->rrsig_list->create_enumerator(this->rrsig_list); + } + return NULL; +} + +METHOD(rr_set_t, destroy, void, + private_rr_set_t *this) +{ + this->rr_list->destroy_offset(this->rr_list, + offsetof(rr_t, destroy)); + if (this->rrsig_list) + { + this->rrsig_list->destroy_offset(this->rrsig_list, + offsetof(rr_t, destroy)); + } + free(this); +} + +/* + * see header + */ +rr_set_t *rr_set_create(linked_list_t *list_of_rr, linked_list_t *list_of_rrsig) +{ + private_rr_set_t *this; + + INIT(this, + .public = { + .create_rr_enumerator = _create_rr_enumerator, + .create_rrsig_enumerator = _create_rrsig_enumerator, + .destroy = _destroy, + }, + ); + + if (list_of_rr == NULL) + { + DBG1(DBG_LIB, "could not create a rr_set without a list_of_rr"); + _destroy(this); + return NULL; + } + this->rr_list = list_of_rr; + this->rrsig_list = list_of_rrsig; + + return &this->public; +} + diff --git a/src/libstrongswan/resolver/rr_set.h b/src/libstrongswan/resolver/rr_set.h new file mode 100644 index 000000000..5a1737a05 --- /dev/null +++ b/src/libstrongswan/resolver/rr_set.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012 Reto Guadagnini + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/** + * @defgroup rr_set rr_set + * @{ @ingroup resolver + */ + +#ifndef RR_SET_H_ +#define RR_SET_H_ + +typedef struct rr_set_t rr_set_t; + +#include <library.h> +#include <collections/enumerator.h> +#include <collections/linked_list.h> + +/** + * A set of DNS Resource Records. + * + * Represents a RRset as defined in RFC 2181. This RRset consists of a set of + * Resource Records with the same label, class and type but different data. + * + * The DNSSEC signature Resource Records (RRSIGs) which sign the RRs of this set + * are also part of an object of this type. + */ +struct rr_set_t { + + /** + * Create an enumerator over all Resource Records of this RRset. + * + * @note The enumerator's position is invalid before the first call + * to enumerate(). + * + * @return enumerator over Resource Records + */ + enumerator_t *(*create_rr_enumerator)(rr_set_t *this); + + /** + * Create an enumerator over all RRSIGs of this RRset + * + * @note The enumerator's position is invalid before the first call + * to enumerate(). + * + * @return enumerator over RRSIG Resource Records, + * NULL if there are no RRSIGs for this RRset + */ + enumerator_t *(*create_rrsig_enumerator)(rr_set_t *this); + + /** + * Destroy this RRset with all its Resource Records. + */ + void (*destroy) (rr_set_t *this); +}; + +/** + * Create an rr_set instance. + * + * @param list_of_rr list of Resource Records which form this RRset + * @param list_of_rrsig list of the signatures (RRSIGs) of the + * Resource Records of this set + * @return Resource Record set, NULL on failure + */ +rr_set_t *rr_set_create(linked_list_t *list_of_rr, + linked_list_t *list_of_rrsig); + +#endif /** RR_SET_H_ @}*/ diff --git a/src/pki/commands/pub.c b/src/pki/commands/pub.c index 30078a8fa..9912061f4 100644 --- a/src/pki/commands/pub.c +++ b/src/pki/commands/pub.c @@ -158,7 +158,7 @@ static void __attribute__ ((constructor))reg() pub, 'p', "pub", "extract the public key from a private key/certificate", {"[--in file|--keyid hex] [--type rsa|ecdsa|pkcs10|x509]", - "[--outform der|pem|pgp]"}, + "[--outform der|pem|pgp|dnskey]"}, { {"help", 'h', 0, "show usage information"}, {"in", 'i', 1, "input file, default: stdin"}, diff --git a/src/pki/pki.c b/src/pki/pki.c index 3f77c5e8d..429517b92 100644 --- a/src/pki/pki.c +++ b/src/pki/pki.c @@ -76,6 +76,17 @@ bool get_form(char *form, cred_encoding_type_t *enc, credential_type_t type) return FALSE; } } + else if (streq(form, "dnskey")) + { + switch (type) + { + case CRED_PUBLIC_KEY: + *enc =PUBKEY_DNSKEY; + return TRUE; + default: + return FALSE; + } + } return FALSE; } |