summaryrefslogtreecommitdiff
path: root/sbin/isakmpd
diff options
context:
space:
mode:
authorHakan Olsson <ho@cvs.openbsd.org>2001-01-26 21:49:38 +0000
committerHakan Olsson <ho@cvs.openbsd.org>2001-01-26 21:49:38 +0000
commit5ebd079b39b241cfc9ca571cf5225308222771f5 (patch)
tree95f0c10c99913628118baa6362a5794d9a0ecd2d /sbin/isakmpd
parent6b4dba46dd554999806ae4409eeae7190c0f6b68 (diff)
Preliminary but working code to permit IKE authentication using DNSSEC
validated KEY records. Uses lwresd from the bind-9.1.0 port. Enable by adding 'dnssec' to FEATURES.
Diffstat (limited to 'sbin/isakmpd')
-rw-r--r--sbin/isakmpd/Makefile11
-rw-r--r--sbin/isakmpd/dnssec.c269
-rw-r--r--sbin/isakmpd/dnssec.h31
-rw-r--r--sbin/isakmpd/ike_auth.c35
4 files changed, 340 insertions, 6 deletions
diff --git a/sbin/isakmpd/Makefile b/sbin/isakmpd/Makefile
index fe80d2f8419..8fa24ab982c 100644
--- a/sbin/isakmpd/Makefile
+++ b/sbin/isakmpd/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.29 2000/10/16 23:28:32 niklas Exp $
+# $OpenBSD: Makefile,v 1.30 2001/01/26 21:49:36 ho Exp $
# $EOM: Makefile,v 1.78 2000/10/15 21:33:42 niklas Exp $
#
@@ -52,6 +52,7 @@ OS= openbsd
# Compile-time configuration of otherwise optional features
#FEATURES= tripledes blowfish cast policy x509 ec aggressive debug gmp
+#FEATURES+= dnssec
FEATURES= tripledes blowfish cast policy x509 ec aggressive debug
#FEATURES=
@@ -153,6 +154,14 @@ DPADD+= ${LIBGMP}
CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL
.endif
+.if ${FEATURES:Mdnssec} == "dnssec"
+LIBLWRES= /usr/local/lib/liblwres.a
+CFLAGS+= -I/usr/local/include
+LDADD+= ${LIBLWRES}
+DPADD+= ${LIBLWRES}
+SRCS+= dnssec.c
+.endif
+
.ifdef HAVE_DLOPEN
CFLAGS+= -DHAVE_DLOPEN
SRCS+= dyn.c
diff --git a/sbin/isakmpd/dnssec.c b/sbin/isakmpd/dnssec.c
new file mode 100644
index 00000000000..b4e280c8793
--- /dev/null
+++ b/sbin/isakmpd/dnssec.c
@@ -0,0 +1,269 @@
+/* $OpenBSD: dnssec.c,v 1.1 2001/01/26 21:49:36 ho Exp $ */
+
+/*
+ * Copyright (c) 2000 Håkan Olsson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <dns/keyvalues.h>
+#include <lwres/lwres.h>
+#include <lwres/netdb.h>
+
+#include <openssl/rsa.h>
+
+#include "sysdep.h"
+
+#include "exchange.h"
+#include "log.h"
+#include "message.h"
+#include "transport.h"
+
+#include "ipsec_num.h"
+#include "dnssec.h"
+
+/* adapted from <dns/rdatastruct.h> / RFC 2535 */
+struct dns_rdata_key {
+ u_int16_t flags;
+ u_int8_t protocol;
+ u_int8_t algorithm;
+ u_int16_t datalen;
+ unsigned char *data;
+};
+
+/* XXX IPv4 specific */
+void *
+dns_get_key (int type, struct message *msg, int *keylen)
+{
+ struct rrsetinfo *rr;
+ struct hostent *hostent;
+ struct sockaddr_in *dst;
+ int ret, i;
+ struct dns_rdata_key key_rr;
+ u_int8_t algorithm;
+
+ switch (type)
+ {
+ case IKE_AUTH_RSA_SIG:
+ algorithm = DNS_KEYALG_RSA;
+ break;
+
+ case IKE_AUTH_RSA_ENC:
+ case IKE_AUTH_RSA_ENC_REV:
+ /* XXX Not yes. */
+ /* algorithm = DNS_KEYALG_RSA; */
+ return NULL;
+
+ case IKE_AUTH_DSS:
+ /* XXX Not yet. */
+ /* algorithm = DNS_KEYALG_DSS; */
+ return NULL;
+
+ case IKE_AUTH_PRE_SHARED:
+ default:
+ return NULL;
+ }
+
+ /* Get peer IP address */
+ msg->transport->vtbl->get_dst (msg->transport, (struct sockaddr **)&dst, &i);
+ /* Get peer name and aliases */
+ hostent = lwres_gethostbyaddr ((char *)&dst->sin_addr,
+ sizeof (struct in_addr), PF_INET);
+
+ if (!hostent)
+ {
+ LOG_DBG ((LOG_MISC, 30,
+ "dns_get_key: lwres_gethostbyaddr (%s) failed: %s",
+ inet_ntoa (((struct sockaddr_in *)dst)->sin_addr),
+ lwres_hstrerror (lwres_h_errno)));
+ return NULL;
+ }
+
+ /* Try host official name */
+ LOG_DBG ((LOG_MISC, 50, "dns_get_key: trying KEY RR for %s",
+ hostent->h_name));
+ ret = lwres_getrrsetbyname (hostent->h_name, C_IN, T_KEY, 0, &rr);
+ if (ret)
+ {
+ /* Try host aliases */
+ i = 0;
+ while (hostent->h_aliases[i] && ret)
+ {
+ LOG_DBG ((LOG_MISC, 50, "dns_get_key: trying KEY RR for alias %s",
+ hostent->h_aliases[i]));
+ ret = lwres_getrrsetbyname (hostent->h_aliases[i], C_IN, T_KEY, 0,
+ &rr);
+ i ++;
+ }
+ }
+
+ if (ret)
+ {
+ LOG_DBG ((LOG_MISC, 30, "dns_get_key: no DNS responses (error %d)",
+ ret));
+ return NULL;
+ }
+
+ LOG_DBG ((LOG_MISC, 80,
+ "dns_get_key: rrset class %d type %d ttl %d nrdatas %d nrsigs %d",
+ rr->rri_rdclass, rr->rri_rdtype, rr->rri_ttl, rr->rri_nrdatas,
+ rr->rri_nsigs));
+
+ /* We don't accept unvalidated data. */
+ if (!(rr->rri_flags & RRSET_VALIDATED))
+ {
+ LOG_DBG ((LOG_MISC, 10, "dns_get_key: got unvalidated response"));
+ lwres_freerrset (rr);
+ return NULL;
+ }
+
+ /* Sanity. */
+ if (rr->rri_nrdatas == 0 || rr->rri_rdtype != T_KEY)
+ {
+ LOG_DBG ((LOG_MISC, 30, "dns_get_key: no KEY RRs recieved"));
+ lwres_freerrset (rr);
+ return NULL;
+ }
+
+ memset (&key_rr, 0, sizeof (key_rr));
+
+ /*
+ * Find a key with the wanted algorithm, if any.
+ * XXX If there are several keys present, we currently only find the first.
+ */
+ for (i = 0; i < rr->rri_nrdatas && key_rr.datalen == 0; i ++)
+ {
+ key_rr.flags = ntohs ((u_int16_t) *rr->rri_rdatas[i].rdi_data);
+ key_rr.protocol = *(rr->rri_rdatas[i].rdi_data + 2);
+ key_rr.algorithm = *(rr->rri_rdatas[i].rdi_data + 3);
+
+ if (key_rr.protocol != DNS_KEYPROTO_IPSEC)
+ {
+ LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored non-IPSEC key"));
+ continue;
+ }
+
+ if (key_rr.algorithm != algorithm)
+ {
+ LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored key with other alg"));
+ continue;
+ }
+
+ key_rr.datalen = rr->rri_rdatas[i].rdi_length - 4;
+ if (key_rr.datalen <= 0)
+ {
+ LOG_DBG ((LOG_MISC, 50, "dns_get_key: ignored bad key"));
+ key_rr.datalen = 0;
+ continue;
+ }
+
+ /* This key seems to fit our requirements... */
+ key_rr.data = (char *)malloc (key_rr.datalen);
+ if (!key_rr.data)
+ {
+ log_error ("dns_get_key: malloc (%d) failed", key_rr.datalen);
+ lwres_freerrset (rr);
+ return NULL;
+ }
+ memcpy (key_rr.data, rr->rri_rdatas[i].rdi_data + 4, key_rr.datalen);
+ *keylen = key_rr.datalen;
+ }
+
+ lwres_freerrset (rr);
+
+ if (key_rr.datalen)
+ return key_rr.data;
+ else
+ return NULL;
+}
+
+int
+dns_RSA_dns_to_x509 (u_int8_t *key, int keylen, RSA **rsa_key)
+{
+ RSA *rsa;
+ int key_offset;
+ u_int8_t e_len;
+
+ if (!key || keylen <= 0)
+ {
+ log_print ("dns_RSA_dns_to_x509: invalid public key");
+ return -1;
+ }
+
+ rsa = RSA_new ();
+ if (!rsa)
+ {
+ log_error ("dns_RSA_dns_to_x509: failed to allocate new RSA struct");
+ return -1;
+ }
+
+ e_len = *key;
+ key_offset = 1;
+
+ if (e_len == 0)
+ {
+ if (keylen < 3)
+ {
+ log_print ("dns_RSA_dns_to_x509: invalid public key");
+ RSA_free (rsa);
+ return -1;
+ }
+ e_len = *(key + key_offset++) << 8;
+ e_len += *(key + key_offset++);
+ }
+
+ if (e_len > (keylen - key_offset))
+ {
+ log_print ("dns_RSA_dns_to_x509: invalid public key");
+ RSA_free (rsa);
+ return -1;
+ }
+
+ rsa->e = BN_bin2bn (key + key_offset, e_len, NULL);
+ key_offset += e_len;
+
+ /* XXX if (keylen <= key_offset) -> "invalid public key" ? */
+
+ rsa->n = BN_bin2bn (key + key_offset, keylen - key_offset, NULL);
+
+ *rsa_key = rsa;
+
+ LOG_DBG ((LOG_MISC, 30, "dns_RSA_dns_to_x509: got %d bits RSA key",
+ BN_num_bits (rsa->n)));
+
+ return 0;
+}
+
+#if notyet
+int
+dns_RSA_x509_to_dns (RSA *rsa_key, u_int8_t *key, int *keylen)
+{
+ return 0;
+}
+#endif
diff --git a/sbin/isakmpd/dnssec.h b/sbin/isakmpd/dnssec.h
new file mode 100644
index 00000000000..22c59ce4af6
--- /dev/null
+++ b/sbin/isakmpd/dnssec.h
@@ -0,0 +1,31 @@
+/* $OpenBSD: dnssec.h,v 1.1 2001/01/26 21:49:37 ho Exp $ */
+
+/*
+ * Copyright (c) 2000 Håkan Olsson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+void *dns_get_key (int, struct message *, int *);
+int dns_RSA_dns_to_x509 (u_int8_t *, int, RSA **);
+
diff --git a/sbin/isakmpd/ike_auth.c b/sbin/isakmpd/ike_auth.c
index a0ad3e19d0e..e253b560971 100644
--- a/sbin/isakmpd/ike_auth.c
+++ b/sbin/isakmpd/ike_auth.c
@@ -1,10 +1,11 @@
-/* $OpenBSD: ike_auth.c,v 1.33 2001/01/26 19:12:38 markus Exp $ */
+/* $OpenBSD: ike_auth.c,v 1.34 2001/01/26 21:49:37 ho Exp $ */
/* $EOM: ike_auth.c,v 1.59 2000/11/21 00:21:31 angelos Exp $ */
/*
* Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved.
* Copyright (c) 1999 Niels Provos. All rights reserved.
* Copyright (c) 1999 Angelos D. Keromytis. All rights reserved.
+ * Copyright (c) 2000 Håkan Olsson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -67,6 +68,7 @@
#include "prf.h"
#include "transport.h"
#include "util.h"
+#include "dnssec.h"
#ifdef notyet
static u_int8_t *enc_gen_skeyid (struct exchange *, size_t *);
@@ -545,7 +547,7 @@ rsa_sig_decode_hash (struct message *msg)
struct payload *p;
void *cert;
u_int8_t *rawcert = NULL;
- u_int32_t rawlen;
+ u_int32_t rawcertlen;
RSA *key;
size_t hashsize = ie->hash->hashsize;
char header[80];
@@ -555,6 +557,10 @@ rsa_sig_decode_hash (struct message *msg)
u_int32_t *id_cert_len;
size_t id_len;
int found = 0, n, i, id_found;
+#if defined(USE_DNSSEC)
+ u_int8_t *rawkey = NULL;
+ u_int32_t rawkeylen;
+#endif
/* Choose the right fields to fill-in. */
hash_p = initiator ? &ie->hash_r : &ie->hash_i;
@@ -598,11 +604,11 @@ rsa_sig_decode_hash (struct message *msg)
#endif /* USE_POLICY || USE_KEYNOTE */
/* Obtain a certificate from our certificate storage */
- if (handler->cert_obtain (id, id_len, 0, &rawcert, &rawlen))
+ if (handler->cert_obtain (id, id_len, 0, &rawcert, &rawcertlen))
{
if (handler->id == ISAKMP_CERTENC_X509_SIG)
{
- cert = handler->cert_get (rawcert, rawlen);
+ cert = handler->cert_get (rawcert, rawcertlen);
if (!cert)
LOG_DBG ((LOG_CRYPTO, 50,
"rsa_sig_decode_hash: certificate malformed"));
@@ -748,7 +754,26 @@ rsa_sig_decode_hash (struct message *msg)
found++;
}
- /* If no certificate provided a key, try the config file. */
+ /* If no certificate provided a key, try to find a validated DNSSEC KEY. */
+#if defined(USE_DNSSEC)
+ if (!found)
+ {
+ rawkey = dns_get_key (IKE_AUTH_RSA_SIG, msg, &rawkeylen);
+ if (rawkey)
+ found++;
+
+ /* We need to convert 'void *rawkey' into 'RSA *key'. */
+ if (dns_RSA_dns_to_x509 (rawkey, rawkeylen, &key) == -1)
+ {
+ log_print ("rsa_sig_decode_hash: KEY to RSA key conversion failed");
+ free (rawkey);
+ return -1;
+ }
+ free (rawkey);
+ }
+#endif /* USE_DNSSEC */
+
+ /* If we still have not found a key, try the config file. */
if (!found)
{
#ifdef notyet