diff options
author | Hakan Olsson <ho@cvs.openbsd.org> | 2001-01-26 21:49:38 +0000 |
---|---|---|
committer | Hakan Olsson <ho@cvs.openbsd.org> | 2001-01-26 21:49:38 +0000 |
commit | 5ebd079b39b241cfc9ca571cf5225308222771f5 (patch) | |
tree | 95f0c10c99913628118baa6362a5794d9a0ecd2d /sbin/isakmpd | |
parent | 6b4dba46dd554999806ae4409eeae7190c0f6b68 (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/Makefile | 11 | ||||
-rw-r--r-- | sbin/isakmpd/dnssec.c | 269 | ||||
-rw-r--r-- | sbin/isakmpd/dnssec.h | 31 | ||||
-rw-r--r-- | sbin/isakmpd/ike_auth.c | 35 |
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 |