aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/Makefile.am7
-rw-r--r--src/libcharon/plugins/ipseckey/Makefile.am18
-rw-r--r--src/libcharon/plugins/ipseckey/ipseckey.c208
-rw-r--r--src/libcharon/plugins/ipseckey/ipseckey.h149
-rw-r--r--src/libcharon/plugins/ipseckey/ipseckey_cred.c263
-rw-r--r--src/libcharon/plugins/ipseckey/ipseckey_cred.h57
-rw-r--r--src/libcharon/plugins/ipseckey/ipseckey_plugin.c104
-rw-r--r--src/libcharon/plugins/ipseckey/ipseckey_plugin.h48
-rw-r--r--src/libstrongswan/Makefile.am10
-rw-r--r--src/libstrongswan/credentials/cred_encoding.h2
-rw-r--r--src/libstrongswan/library.c2
-rw-r--r--src/libstrongswan/library.h9
-rw-r--r--src/libstrongswan/plugins/dnskey/Makefile.am3
-rw-r--r--src/libstrongswan/plugins/dnskey/dnskey_builder.c12
-rw-r--r--src/libstrongswan/plugins/dnskey/dnskey_encoder.c91
-rw-r--r--src/libstrongswan/plugins/dnskey/dnskey_encoder.h32
-rw-r--r--src/libstrongswan/plugins/dnskey/dnskey_plugin.c5
-rw-r--r--src/libstrongswan/plugins/unbound/Makefile.am20
-rw-r--r--src/libstrongswan/plugins/unbound/unbound_plugin.c66
-rw-r--r--src/libstrongswan/plugins/unbound/unbound_plugin.h42
-rw-r--r--src/libstrongswan/plugins/unbound/unbound_resolver.c143
-rw-r--r--src/libstrongswan/plugins/unbound/unbound_resolver.h29
-rw-r--r--src/libstrongswan/plugins/unbound/unbound_response.c259
-rw-r--r--src/libstrongswan/plugins/unbound/unbound_response.h51
-rw-r--r--src/libstrongswan/plugins/unbound/unbound_rr.c164
-rw-r--r--src/libstrongswan/plugins/unbound/unbound_rr.h48
-rw-r--r--src/libstrongswan/resolver/resolver.h58
-rw-r--r--src/libstrongswan/resolver/resolver_manager.c86
-rw-r--r--src/libstrongswan/resolver/resolver_manager.h72
-rw-r--r--src/libstrongswan/resolver/resolver_response.h143
-rw-r--r--src/libstrongswan/resolver/rr.h268
-rw-r--r--src/libstrongswan/resolver/rr_set.c100
-rw-r--r--src/libstrongswan/resolver/rr_set.h79
-rw-r--r--src/pki/commands/pub.c2
-rw-r--r--src/pki/pki.c11
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;
}