isakmpd-20041012.orig/0000755000175000017500000000000010133046100014544 5ustar jdivejdive00000000000000isakmpd-20041012.orig/Makefile0000644000175000017500000001342310133045740016220 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.57 2004/08/23 11:16:49 ho Exp $ # $EOM: Makefile,v 1.78 2000/10/15 21:33:42 niklas Exp $ # # Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. # Copyright (c) 2000, 2001 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # # This makefile is a "pmake" one, i.e. the make variant commonly found in # BSD derived systems, where it is indeed named "make". Other systems # may provide this make variant as "pmake" or maybe "bsdmake". # # openbsd means OpenBSD 2.5 or newer. freeswan is the name for Linux with # FreeS/WAN integrated, freebsd/netbsd means FreeBSD/NetBSD with KAME IPsec. OS= openbsd #OS= netbsd #OS= freebsd #OS= freeswan #OS= bsdi # Compile-time configuration of otherwise optional features #FEATURES= tripledes des blowfish cast aes #FEATURES+= policy x509 ec aggressive debug gmp #FEATURES+= rawkey isakmp_cfg dnssec privsep nat_traversal dpd FEATURES= tripledes des blowfish cast aes FEATURES+= policy x509 ec aggressive debug FEATURES+= rawkey isakmp_cfg privsep nat_traversal dpd .PATH: ${.CURDIR}/sysdep/${OS} PROG= isakmpd BINDIR?= /sbin LDSTATIC?= -static SRCS= app.c attribute.c cert.c connection.c constants.c conf.c \ cookie.c crypto.c dh.c doi.c exchange.c exchange_num.c \ field.c gmp_util.c hash.c if.c ike_auth.c ike_main_mode.c \ ike_phase_1.c ike_quick_mode.c init.c ipsec.c ipsec_fld.c \ ipsec_num.c isakmpd.c isakmp_doi.c isakmp_fld.c isakmp_num.c \ key.c libcrypto.c log.c message.c math_2n.c math_group.c \ prf.c sa.c sysdep.c timer.c transport.c virtual.c udp.c \ ui.c util.c GENERATED= exchange_num.h ipsec_fld.h ipsec_num.h isakmp_fld.h \ isakmp_num.h CLEANFILES= exchange_num.c exchange_num.h ipsec_num.c ipsec_num.h \ isakmp_num.c isakmp_num.h ipsec_fld.c ipsec_fld.h \ isakmp_fld.c isakmp_fld.h MAN= isakmpd.8 isakmpd.conf.5 isakmpd.policy.5 CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes \ -Wmissing-declarations -DNEED_SYSDEP_APP \ -I${.CURDIR} -I${.CURDIR}/sysdep/${OS} -I. #CFLAGS+= -Wsign-compare -Werror # Different debugging & profiling suggestions # Include symbolic debugging info #DEBUG= -g # OpenBSD #DEBUG_FLAGS= -g # FreeBSD #CFLAGS+= -g # NetBSD and others #STRIPFLAG= # NETBSD # Do execution time profiles #CFLAGS+= -pg # If you have ElectricFence available, you can spot abuses of the heap. # (/usr/ports/devel/ElectricFence) #LDADD+= -L/usr/local/lib -lefence #DPADD+= /usr/local/lib/libefence.a # If you like to use Boehm's garbage collector (/usr/ports/devel/boehm-gc). #LDADD+= -L/usr/local/lib -lgc #DPADD+= /usr/local/lib/libgc.a #CFLAGS+= -DUSE_BOEHM_GC -DGC_DEBUG # You can also use Boehm's garbage collector as a means to find leaks. # # setenv GC_FIND_LEAK SUBDIR= apps .include "sysdep/${OS}/Makefile.sysdep" .if ${FEATURES} != "" FEATURES_UC!= echo ${FEATURES} | tr '[:lower:]' '[:upper:]' CFLAGS+= ${FEATURES_UC:S/^/-DUSE_/g} .endif .if make(install) SUBDIR+= samples .endif .if !make(install) && !defined(NO_REGRESS) SUBDIR+= regress .endif .for FEATURE in ${FEATURES} .if exists(features/${FEATURE}) .include "features/${FEATURE}" .endif .endfor .if ${FEATURES:Mgmp} == "gmp" CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP LDADD+= -lgmp DPADD+= ${LIBGMP} .else CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL .endif .ifdef USE_KEYNOTE USE_LIBCRYPTO= yes USE_LIBDES= yes LDADD+= -lkeynote -lm DPADD+= ${LIBKEYNOTE} ${LIBM} CFLAGS+= -DUSE_KEYNOTE .endif .ifdef USE_RAWKEY USE_LIBCRYPTO= yes CFLAGS+= -DUSE_RAWKEY .endif .ifdef USE_LIBCRYPTO CFLAGS+= -DUSE_LIBCRYPTO LDADD+= -lcrypto DPADD+= ${LIBCRYPTO} .endif .ifdef USE_LIBDES CFLAGS+= -DUSE_LIBDES LDADD+= -ldes DPADD+= ${LIBDES} .endif SRCS+= ${IPSEC_SRCS} ${X509} ${POLICY} ${EC} ${AGGRESSIVE} ${DNSSEC} \ ${ISAKMP_CFG} ${PRIVSEP} ${DPD} ${NAT_TRAVERSAL} CFLAGS+= ${IPSEC_CFLAGS} ${DNSSEC_CFLAGS} LDADD+= ${DESLIB} ${LWRESLIB} DPADD+= ${DESLIBDEP} ${LWRESLIB} exchange_num.c exchange_num.h: genconstants.sh exchange_num.cst /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/exchange_num ipsec_fld.c ipsec_fld.h: genfields.sh ipsec_fld.fld /bin/sh ${.CURDIR}/genfields.sh ${.CURDIR}/ipsec_fld ipsec_num.c ipsec_num.h: genconstants.sh ipsec_num.cst /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/ipsec_num isakmp_fld.c isakmp_fld.h: genfields.sh isakmp_fld.fld /bin/sh ${.CURDIR}/genfields.sh ${.CURDIR}/isakmp_fld isakmp_num.c isakmp_num.h: genconstants.sh isakmp_num.cst /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/isakmp_num ${PROG} beforedepend: ${GENERATED} .include .include debug: (cd ${.CURDIR}; ${MAKE} DEBUG="-g -Werror") isakmpd-20041012.orig/dnssec.c0000644000175000017500000001734010133045740016205 0ustar jdivejdive00000000000000/* $OpenBSD: dnssec.c,v 1.20 2004/06/14 09:55:41 ho Exp $ */ /* * Copyright (c) 2001 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. * * 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 #include #include #include #include #include #ifdef LWRES #include #include #else #include #endif #include "sysdep.h" #include "dnssec.h" #include "exchange.h" #include "ipsec_num.h" #include "libcrypto.h" #include "log.h" #include "message.h" #include "transport.h" #include "util.h" #ifndef DNS_UFQDN_SEPARATOR #define DNS_UFQDN_SEPARATOR "._ipsec." #endif /* adapted from / 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; }; void * dns_get_key(int type, struct message *msg, int *keylen) { struct exchange *exchange = msg->exchange; struct rrsetinfo *rr; struct dns_rdata_key key_rr; char name[MAXHOSTNAMELEN]; in_addr_t ip4; u_int8_t algorithm, *id, *umark; size_t id_len; int ret, i; 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 yet. */ /* algorithm = DNS_KEYALG_RSA; */ return 0; case IKE_AUTH_DSS: /* XXX Not yet. */ /* algorithm = DNS_KEYALG_DSS; */ return 0; case IKE_AUTH_PRE_SHARED: default: return 0; } id = exchange->initiator ? exchange->id_r : exchange->id_i; id_len = exchange->initiator ? exchange->id_r_len : exchange->id_i_len; memset(name, 0, sizeof name); if (!id || id_len == 0) { log_print("dns_get_key: ID is missing"); return 0; } /* Exchanges (and SAs) don't carry the ID in ISAKMP form */ id -= ISAKMP_GEN_SZ; id_len += ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF; switch (GET_ISAKMP_ID_TYPE(id)) { case IPSEC_ID_IPV4_ADDR: /* We want to lookup a KEY RR in the reverse zone. */ if (id_len < sizeof ip4) return 0; memcpy(&ip4, id + ISAKMP_ID_DATA_OFF, sizeof ip4); snprintf(name, sizeof name, "%d.%d.%d.%d.in-addr.arpa.", ip4 >> 24, (ip4 >> 16) & 0xFF, (ip4 >> 8) & 0xFF, ip4 & 0xFF); break; case IPSEC_ID_IPV6_ADDR: /* XXX Not yet. */ return 0; break; case IPSEC_ID_FQDN: if ((id_len + 1) >= sizeof name) return 0; /* ID is not NULL-terminated. Add trailing dot and NULL. */ memcpy(name, id + ISAKMP_ID_DATA_OFF, id_len); *(name + id_len) = '.'; *(name + id_len + 1) = '\0'; break; case IPSEC_ID_USER_FQDN: /* * Some special handling here. We want to convert the ID * 'user@host.domain' string into 'user._ipsec.host.domain.'. */ if ((id_len + sizeof(DNS_UFQDN_SEPARATOR)) >= sizeof name) return 0; /* Look for the '@' separator. */ for (umark = id + ISAKMP_ID_DATA_OFF; (umark - id) < id_len; umark++) if (*umark == '@') break; if (*umark != '@') { LOG_DBG((LOG_MISC, 50, "dns_get_key: bad UFQDN ID")); return 0; } *umark++ = '\0'; /* id is now terminated. 'umark', however, is not. */ snprintf(name, sizeof name, "%s%s", id + ISAKMP_ID_DATA_OFF, DNS_UFQDN_SEPARATOR); memcpy(name + strlen(name), umark, id_len - strlen(id) - 1); *(name + id_len + sizeof(DNS_UFQDN_SEPARATOR) - 2) = '.'; *(name + id_len + sizeof(DNS_UFQDN_SEPARATOR) - 1) = '\0'; break; default: return 0; } LOG_DBG((LOG_MISC, 50, "dns_get_key: trying KEY RR for %s", name)); ret = getrrsetbyname(name, C_IN, T_KEY, 0, &rr); if (ret) { LOG_DBG((LOG_MISC, 30, "dns_get_key: no DNS responses " "(error %d)", ret)); return 0; } 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")); freerrset(rr); return 0; } /* Sanity. */ if (rr->rri_nrdatas == 0 || rr->rri_rdtype != T_KEY) { LOG_DBG((LOG_MISC, 30, "dns_get_key: no KEY RRs received")); freerrset(rr); return 0; } 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); freerrset(rr); return 0; } memcpy(key_rr.data, rr->rri_rdatas[i].rdi_data + 4, key_rr.datalen); *keylen = key_rr.datalen; } freerrset(rr); if (key_rr.datalen) return key_rr.data; return 0; } 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 == NULL) { 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 isakmpd-20041012.orig/isakmp.h0000644000175000017500000000467010133045740016221 0ustar jdivejdive00000000000000/* $OpenBSD: isakmp.h,v 1.7 2004/06/20 15:24:05 ho Exp $ */ /* $EOM: isakmp.h,v 1.11 2000/07/05 10:48:43 ho Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. All rights reserved. * Copyright (c) 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _ISAKMP_H_ #define _ISAKMP_H_ #include "isakmp_fld.h" #include "isakmp_num.h" /* IANA assigned port */ #define UDP_DEFAULT_PORT 500 #define UDP_DEFAULT_PORT_STR "500" #define ISAKMP_DEFAULT_TRANSPORT "udp" /* draft-ietf-ipsec-nat-t-ike-07.txt */ #define UDP_ENCAP_DEFAULT_PORT 4500 #define UDP_ENCAP_DEFAULT_PORT_STR "4500" /* ISAKMP header extras defines */ #define ISAKMP_HDR_COOKIES_OFF ISAKMP_HDR_ICOOKIE_OFF #define ISAKMP_HDR_COOKIES_LEN (ISAKMP_HDR_ICOOKIE_LEN \ + ISAKMP_HDR_ICOOKIE_LEN) /* ISAKMP attribute utilitiy macros. */ #define ISAKMP_ATTR_FORMAT(x) ((x) >> 15) #define ISAKMP_ATTR_TYPE(x) ((x) & 0x7fff) #define ISAKMP_ATTR_MAKE(fmt, type) (((fmt) << 15) | (type)) /* Version number handling. */ #define ISAKMP_VERSION_MAJOR(x) ((x) >> 4) #define ISAKMP_VERSION_MINOR(x) ((x) & 0xf) #define ISAKMP_VERSION_MAKE(maj, min) ((maj) << 4 | (min)) #endif /* _ISAKMP_H_ */ isakmpd-20041012.orig/regress/0000755000175000017500000000000010133045740016227 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/group/0000755000175000017500000000000010133045740017363 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/group/Makefile0000644000175000017500000000152610133045740021027 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.8 2004/02/25 16:01:29 hshoexer Exp $ # $EOM: Makefile,v 1.12 2000/04/07 20:19:43 niklas Exp $ # Test Group: PROG= grouptest SRCS= math_2n.c math_ec2n.c math_group.c grouptest.c log.c util.c \ sysdep.c gmp_util.c conf.c TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//' .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \ -DUSE_EC NOMAN= LDADD+= -lcrypto DPADD+= ${LIBCRYPTO} DEBUG= -g .if ${FEATURES:Mgmp} == "gmp" CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP LDADD+= -lgmp DPADD+= ${LIBGMP} .else CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL .endif .include isakmpd-20041012.orig/regress/group/.cvsignore0000644000175000017500000000001610133045740021360 0ustar jdivejdive00000000000000grouptest obj isakmpd-20041012.orig/regress/group/grouptest.c0000644000175000017500000000730310133045740021566 0ustar jdivejdive00000000000000/* $OpenBSD: grouptest.c,v 1.4 2003/06/03 14:39:51 ho Exp $ */ /* $EOM: grouptest.c,v 1.2 1998/07/18 21:15:55 provos Exp $ */ /* * Copyright (c) 1998 Niels Provos. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * This module exercises the operations supplied by the group abstraction. */ #include #include #include #include "math_2n.h" #include "math_ec2n.h" #include "math_group.h" #define DUMP_X(_x_) point = (_x_); b2n_print (point->x); int main (void) { int i; char buf[100]; char buf2[100]; struct group *group, *group2; ec2np_ptr point; group_init (); group = group_get (3); group2 = group_get (3); printf ("Testing: setraw, getraw: "); for (i = 0; i < 20; i++) buf[i] = i; group->setraw (group, group->c, buf, 20); if (group->getlen (group) != 20) printf ("FAILED "); else printf ("OKAY "); group->getraw (group, group->c, buf2); for (i = 0; i < 20; i++) if (buf2[i] != i) break; if (i < 20) printf ("FAILED "); else printf ("OKAY "); printf ("\nTesting: setrandom: "); group->setrandom (group, group->c); DUMP_X (group->c); group2->setrandom (group2, group2->c); DUMP_X (group2->c); printf ("\nTesting: operation:\n"); group->operation (group, group->a, group->gen, group->c); point = group->a; printf ("\tX (%d): ", point->x->chunks); b2n_print (point->x); printf ("\tY (%d): ", point->y->chunks); b2n_print (point->y); group2->operation (group2, group2->a, group2->gen, group2->c); point = group2->a; printf ("\tX (%d): ", point->x->chunks); b2n_print (point->x); printf ("\tY (%d): ", point->y->chunks); b2n_print (point->y); printf ("Exchange Value 1: "); b2n_print (group->d); printf ("Exchange Value 2: "); b2n_print (group2->d); printf ("Testing: operation ...:\n"); group->getraw (group, group->a, buf); group2->setraw (group2, group2->b, buf, 20); group2->getraw (group2, group2->a, buf); group->setraw (group, group->b, buf, 20); group2->operation (group2, group2->a, group2->b, group2->c); printf ("Exchange Value 21: "); DUMP_X (group2->a); group->operation (group, group->a, group->b, group->c); printf ("Exchange Value 12: "); DUMP_X (group->a); group->getraw (group, group->a, buf); group2->getraw (group2, group2->a, buf2); printf ("Testing: operation ...: "); if (memcmp(buf, buf2, 20)) printf ("FAILED "); else printf ("OKAY "); printf ("\n"); return 1; } isakmpd-20041012.orig/regress/group/CVS/0000755000175000017500000000000010133045751020020 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/Makefile0000644000175000017500000000305610133045740017673 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.9 2003/06/03 14:39:50 ho Exp $ # $EOM: Makefile,v 1.8 1999/07/17 20:44:13 niklas Exp $ # # Copyright (c) 1998, 1999 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # SUBDIR= b2n crypto dh ec2n exchange group hmac prf rsakeygen util x509 .include isakmpd-20041012.orig/regress/b2n/0000755000175000017500000000000010133045740016710 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/b2n/Makefile0000644000175000017500000000077310133045740020357 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.7 2004/02/25 16:01:29 hshoexer Exp $ # $EOM: Makefile,v 1.12 2000/10/13 13:04:17 ho Exp $ # Test some math PROG= b2ntest SRCS= b2ntest.c conf.c log.c math_2n.c sysdep.c util.c NOMAN= TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall DEBUG= -g .include isakmpd-20041012.orig/regress/b2n/b2ntest.c0000644000175000017500000002545510133045740020450 0ustar jdivejdive00000000000000/* $OpenBSD: b2ntest.c,v 1.8 2003/06/03 14:39:50 ho Exp $ */ /* $EOM: b2ntest.c,v 1.4 1998/07/16 19:31:55 provos Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 2001 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * B2N is a module for doing arithmetic on the Field GF(2**n) which is * isomorph to ring of polynomials GF(2)[x]/p(x) where p(x) is an * irreduciable polynomial over GF(2)[x] with grade n. */ #include #include #include #include "math_2n.h" #define BUFSIZE 200 #define CMP_FAIL(n,x) b2n_snprint (buf, BUFSIZE, n); if (strcmp (buf, (x))) \ printf ("FAILED: %s != %s ", buf, x); else printf ("OKAY "); int main (void) { int i; b2n_t n, m, d, r; char buf[BUFSIZE]; b2n_init (n); b2n_init (m); b2n_init (d); b2n_init (r); printf ("Arithimetic Tests for GF(2)[x]:\n"); printf ("Testing: b2n_set*: "); b2n_set_ui (n, 0xffc0); CMP_FAIL (n, "0xffc0"); b2n_set_str (m, "0x180c0"); CMP_FAIL (m, "0x0180c0"); b2n_set_str (m, "0x808b8080c0"); CMP_FAIL (m, "0x808b8080c0"); printf ("\nTesting: b2n_add: "); b2n_add (d, n, m); CMP_FAIL (d, "0x808b807f00"); b2n_add (n, n, m); CMP_FAIL (n, "0x808b807f00"); b2n_add (n, n, n); CMP_FAIL (n, "0x00"); b2n_set_str (n, "0x9090900000000000000000"); b2n_set_ui (m, 0); b2n_add (n, n, m); CMP_FAIL (n, "0x9090900000000000000000"); printf ("\nTesting: b2n_lshift: "); b2n_set_str (m, "0x808b8080c0"); b2n_lshift (n, m, 3); CMP_FAIL (n, "0x04045c040600"); b2n_lshift (n, m, 11); CMP_FAIL (n, "0x04045c04060000"); b2n_set (n, m); for (i = 0; i < 11; i++) b2n_lshift (n, n, 1); CMP_FAIL (n, "0x04045c04060000"); b2n_lshift (d, m, 12); CMP_FAIL (d, "0x0808b8080c0000"); b2n_set_str (m, "0xdeadbeef"); b2n_lshift (d, m, 103); CMP_FAIL (d, "0x6f56df7780000000000000000000000000"); printf ("\nTesting: b2n_rshift: "); b2n_rshift (m, n, 3); CMP_FAIL (m, "0x808b8080c000"); b2n_rshift (m, m, 11); CMP_FAIL (m, "0x1011701018"); b2n_set_str (m, "0x12381998713258186712365"); b2n_rshift (m, m, 23); CMP_FAIL (m, "0x024703330e264b030c"); b2n_set_str (m, "0x12381998713258186712365"); for (i=0; i<23; i++) b2n_rshift (m, m, 1); CMP_FAIL (m, "0x024703330e264b030c"); printf ("\nTesting: b2n_mul: 0x9 o 0x5: "); b2n_set_ui (n, 9); b2n_set_ui (m, 5); b2n_mul (d, n, m); CMP_FAIL (d, "0x2d"); b2n_mul (n, n, m); CMP_FAIL (d, "0x2d"); printf ("\nTesting: b2n_mul: 0x9 o 0x0: "); b2n_set_ui (n, 9); b2n_set_ui (m, 0); b2n_mul (d, n, m); CMP_FAIL (d, "0x00"); b2n_set_ui (n, 0); b2n_set_ui (m, 9); b2n_mul (d, n, m); CMP_FAIL (d, "0x00"); printf ("\nTesting: b2n_mul: 0x9 o 0x1: "); b2n_set_ui (n, 9); b2n_set_ui (m, 1); b2n_mul (d, n, m); CMP_FAIL (d, "0x09"); printf ("\nTesting: b2n_mul: 0x12329 o 0x1235: "); b2n_set_str (n, "0x12329"); b2n_set_str (m, "0x1235"); b2n_mul (d, n, m); CMP_FAIL (d, "0x10473a3d"); b2n_mul (n, n, m); CMP_FAIL (d, "0x10473a3d"); printf ("\nTesting: b2n_square: 0x1235 o 0x1235: "); b2n_set_str (m, "0x1235"); b2n_square (n, m); CMP_FAIL (n, "0x01040511"); printf ("\nTesting: b2n_square: 0x80c1235 o 0x80c1235: "); b2n_set_str (m, "0x80c1235"); b2n_square (n, m); CMP_FAIL (n, "0x40005001040511"); b2n_set_str (m, "0x12329"); printf ("\nTesting: sigbit: 0x12329: %d, %s", b2n_sigbit(m), b2n_sigbit(m) == 17 ? "OKAY" : "FAILED"); b2n_set_ui (m, 0); printf ("\nTesting: sigbit: 0x0: %d, %s", b2n_sigbit(m), b2n_sigbit(m) == 0 ? "OKAY" : "FAILED"); b2n_set_str (m, "0x7f3290000"); printf ("\nTesting: sigbit: 0x7f3290000: %d, %s", b2n_sigbit(m), b2n_sigbit(m) == 35 ? "OKAY" : "FAILED"); printf ("\nTesting: b2n_cmp: "); b2n_set_str (m, "0x2234"); b2n_set_str (n, "0x1234"); printf ("%d <-> %d, ", b2n_sigbit (m), b2n_sigbit(n)); printf ("%d, %d ,%d: ", b2n_cmp (m,m), b2n_cmp (m,n), b2n_cmp (n,m)); if (b2n_cmp (m,m) || b2n_cmp (m,n) != 1 || b2n_cmp (n,m) != -1) printf ("FAILED"); else printf ("OKAY"); printf ("\nTesting: b2n_cmp_null: "); b2n_set_str (m, "0x2234"); b2n_set_ui (n, 0); printf ("%d, %d: ", b2n_cmp_null (m), b2n_cmp_null (n)); if (b2n_cmp_null (m) != 1 || b2n_cmp_null (n)) printf ("FAILED"); else printf ("OKAY"); printf ("\nTesting: b2n_div: 0x2d / 0x5: "); b2n_set_str (n, "0x2d"); b2n_set_ui (m, 5); b2n_div (n, m, n, m); CMP_FAIL (n, "0x09"); CMP_FAIL (m, "0x00"); printf ("\nTesting: b2n_div: 0x2d / 0x1: "); b2n_set_str (n, "0x2d"); b2n_set_ui (m, 1); b2n_div (n, m, n, m); CMP_FAIL (n, "0x2d"); CMP_FAIL (m, "0x00"); printf ("\nTesting: b2n_div: 0x10473a3d / 0x1235: "); b2n_set_str (n, "0x10473a3d"); b2n_set_str (m, "0x1235"); b2n_div (n, m, n, m); CMP_FAIL (n, "0x012329"); CMP_FAIL (m, "0x00"); printf ("\nTesting: b2n_div: 0x10473a3d / 0x1536: "); b2n_set_str (n, "0x10473a3d"); b2n_set_str (m, "0x1536"); b2n_div (n, m, n, m); CMP_FAIL (n, "0x014331"); CMP_FAIL (m, "0xab"); b2n_set_str (n, "0x10473a3d"); b2n_set_str (m, "0x1536"); b2n_div_q (d, n, m); CMP_FAIL (d, "0x014331"); b2n_div_r (d, n, m); CMP_FAIL (d, "0xab"); printf ("\nTesting: b2n_div: " "0x0800000000000000000000004000000000000001 / 0xffab09909a00: "); b2n_set_str (n, "0x0800000000000000000000004000000000000001"); b2n_set_str (m, "0xffab09909a00"); b2n_div_q (d, n, m); CMP_FAIL (d, "0x18083e83a98647cedae0b3e69a5e"); b2n_div_r (d, n, m); CMP_FAIL (d, "0x5b8bf98cac01"); b2n_set (d, m); b2n_div (n, m, n, m); CMP_FAIL (n, "0x18083e83a98647cedae0b3e69a5e"); CMP_FAIL (m, "0x5b8bf98cac01"); printf ("\nTesting: b2n_div: " "0x0800000000000000000000004000000000000001 / 0x7b: "); b2n_set_str (n, "0x0800000000000000000000004000000000000001"); b2n_set_str (m, "0x7b"); b2n_div (n, m, n, m); CMP_FAIL (n, "0x32dea27065bd44e0cb7a89c000000000000000"); CMP_FAIL (m, "0x01"); printf ("\n\nArithimetic Tests for GF(2**m) ~= GF(2)[x]/p(x):\n"); printf ("Testing: b2n_gcd: "); b2n_set_str (d, "0x771"); b2n_set_str (m, "0x26d"); b2n_gcd (n, m, d); CMP_FAIL (n, "0x0b"); b2n_set_str (d, "0x0800000000000000000000004000000000000001"); b2n_set_str (m, "0xffab09909a00"); b2n_gcd (n, m, d); CMP_FAIL (n, "0x01"); b2n_set_str (d, "0x0800000000000000000000004000000000000001"); b2n_set_str (m, "0x7b"); b2n_gcd (n, m, d); CMP_FAIL (n, "0x01"); printf ("\nTesting: b2n_mul_inv: "); b2n_set_str (d, "0x0800000000000000000000004000000000000001"); b2n_set_str (m, "0xffab09909a00"); b2n_mul_inv (n, m, d); CMP_FAIL (n, "0x074029149f69304174d28858ae5c60df208a22a8"); b2n_set_str (n, "0xffab09909a00"); b2n_mul_inv (n, n, d); CMP_FAIL (n, "0x074029149f69304174d28858ae5c60df208a22a8"); b2n_mul (n, n, m); b2n_mod (n, n, d); CMP_FAIL (n, "0x01"); b2n_set_str (d, "0x0800000000000000000000004000000000000001"); b2n_set_str (m, "0x7b"); b2n_mul_inv (n, m, d); CMP_FAIL (n, "0x32dea27065bd44e0cb7a89c000000000000000"); b2n_mul (n, n, m); b2n_mod (n, n, d); CMP_FAIL (n, "0x01"); printf ("\nTesting: b2n_random: "); b2n_random (m, 155); b2n_snprint (buf, BUFSIZE, m); printf ("%s, %d", buf, b2n_sigbit(m)); printf ("\nTesting: b2n_sqrt: "); b2n_set_str (n, "0x0800000000000000000000004000000000000001"); b2n_set_ui (d, 2); b2n_sqrt (m, d, n); b2n_square (d, m); b2n_add (d, d, m); b2n_mod (d, d, n); CMP_FAIL (d, "0x02"); /* x**3 + b */ b2n_set_ui (n, 0x7b); b2n_square (d, n); b2n_mul (d, d, n); b2n_set_str (n, "0x07338f"); b2n_add (d, d, n); b2n_set_str (n, "0x0800000000000000000000004000000000000001"); b2n_mod (d, d, n); /* \alpha = x**3 + b - end */ /* \beta = x**(-2)*\alpha */ b2n_set_ui (m, 0x7b); b2n_mul_inv (m, m, n); b2n_square (m, m); b2n_mod (m, m, n); b2n_mul (d, d, m); b2n_mod (d, d, n); b2n_set (r, d); /* \beta = x**(-2)*\alpha - end */ b2n_sqrt (m, d, n); CMP_FAIL (m, "0x0690aec7cd215d8f9a42bb1f0000000000000004"); b2n_square (d, m); b2n_mod (d, d, n); b2n_add (d, d, m); b2n_mod (d, d, n); printf ("Squaring Check: "); CMP_FAIL (d, "0x03d5af92c8311d9e8f56be4b3e690aec7cd215cc"); printf ("\nTesting: b2n_trace: "); b2n_set_ui (m, 2); b2n_trace (d, m, n); CMP_FAIL (d, "0x00"); b2n_set_ui (m, 0x11223); b2n_trace (d, m, n); CMP_FAIL (d, "0x01"); printf ("\nTesting: b2n_exp_mod: "); b2n_set_ui (m, 0x7b); b2n_exp_mod (d, m, 5, n); CMP_FAIL (d, "0x7cccb7cb"); b2n_set_str (m, "0x123456789abcdef"); b2n_exp_mod (d, m, 13, n); CMP_FAIL (d, "0x043f0a8550cb69b3c50d0340d1c6d5c97ecd60d4"); printf ("\nTesting: b2n_3mul: "); b2n_set_ui (m, 0x7b); b2n_3mul (m, m); CMP_FAIL (m, "0x0171"); b2n_set_ui (m, 0x7fffffff); b2n_3mul (m, m); CMP_FAIL (m, "0x017ffffffd"); printf ("\nTesting: b2n_nadd: "); b2n_set_str (m, "0x7fffffff"); b2n_set_str (n, "0x10203045"); b2n_nadd (d, n, m); CMP_FAIL (d, "0x90203044"); b2n_set_str (m, "0x9a4a54d8b8dfa566112849991214329a233d"); b2n_set_str (n, "0x70ee40dd60c8657e58eda9a17ad9176e28b4b457e5a34a0948e335"); b2n_nadd (d, n, m); CMP_FAIL (d, "0x70ee40dd60c8657e5987f3f65391f7138ec5dca17eb55e3be30672"); printf ("\nTesting: b2n_nsub: "); b2n_set_str (n, "0x90203044"); b2n_set_str (m, "0x10203045"); b2n_nsub (d, n, m); CMP_FAIL (d, "0x7fffffff"); b2n_set_str (n, "0x70ee40dd60c8657e5987f3f65391f7138ec5dca17eb55e3be30672"); b2n_set_str (m, "0x70ee40dd60c8657e58eda9a17ad9176e28b4b457e5a34a0948e335"); b2n_nsub (d, n, m); CMP_FAIL (d, "0x9a4a54d8b8dfa566112849991214329a233d"); b2n_clear (n); b2n_clear (m); b2n_clear (d); b2n_clear (r); printf ("\n"); return 1; } isakmpd-20041012.orig/regress/b2n/.cvsignore0000644000175000017500000000001410133045740020703 0ustar jdivejdive00000000000000b2ntest obj isakmpd-20041012.orig/regress/b2n/CVS/0000755000175000017500000000000010133045751017345 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/check.sh0000644000175000017500000000516010133045740017642 0ustar jdivejdive00000000000000#!/bin/sh # $OpenBSD: check.sh,v 1.4 2003/06/03 14:39:50 ho Exp $ # $EOM: check.sh,v 1.4 1998/07/17 21:33:13 niklas Exp $ # # Copyright (c) 1998 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson. # PROGNAME=$0 NC=/usr/bin/nc HOST=localhost ISAKMP_PORT=500 set -- `getopt p: $*` if [ $? != 0 ]; then echo 'usage: $PROGNAME [-p port] host' >&2 exit 2 fi for i; do case "$i" in -p) ISAKMP_PORT=$2; shift; shift;; --) shift; break;; esac done if [ $# -gt 0 ]; then HOST=$1 fi send () { ${NC} -u -w 1 ${HOST} ${ISAKMP_PORT} } # Short message printf "SHORT!" |send # (Most probably) invalid cookie printf "INVALID COOKIES!\0\x10\0\0\0\0\0\0\0\0\0\x1c" |send # Invalid next payload type printf "01234567\0\0\0\0\0\0\0\0!\x10\0\0\0\0\0\0\0\0\0\x1c" |send # Invalid major version printf "01234567\0\0\0\0\0\0\0\0\0\x20\0\0\0\0\0\0\0\0\0\x1c" |send # Invalid minor version printf "01234567\0\0\0\0\0\0\0\0\0\x11\0\0\0\0\0\0\0\0\0\x1c" |send # Invalid exchange type printf "01234567\0\0\0\0\0\0\0\0\0\x10!\0\0\0\0\0\0\0\0\x1c" |send # Invalid flags printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\x80\0\0\0\0\0\0\0\x1c" |send # Invalid message ID printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\0BAD!\0\0\0\x1c" |send # Short length printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\0\0\0\0\0\0\0\0\x1b" |send # Long length printf "01234567\0\0\0\0\0\0\0\0\0\x10\2\0\0\0\0\0\0\0\0\x1d" |send isakmpd-20041012.orig/regress/util/0000755000175000017500000000000010133045740017204 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/util/Makefile0000644000175000017500000000071310133045740020645 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.2 2004/02/25 16:01:29 hshoexer Exp $ # Test some utility functions PROG= utiltest SRCS= log.c sysdep.c util.c utiltest.c conf.c TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall NOMAN= DEBUG= -g .include isakmpd-20041012.orig/regress/util/utiltest.c0000644000175000017500000000520210133045740021224 0ustar jdivejdive00000000000000/* $OpenBSD: utiltest.c,v 1.3 2003/06/03 14:39:51 ho Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist. 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. * * 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 #include #include #include #include "sysdep.h" #include "util.h" int test_1 (char *, char *, int); int main (int argc, char *argv[]) { test_1 ("10.0.0.1", "10", 0); test_1 ("10.0.0.1", "isakmp", 0); test_1 ("10::1", "10", 0); test_1 ("10::1", "isakmp", 0); test_1 ("10.0x0.1", "10", -1); test_1 ("10.0.0.1", "telnet", -1); test_1 ("10::x:1", "10", -1); test_1 ("10::1", "telnet", -1); return 0; } int test_1 (char *address, char *port, int ok) { struct sockaddr *sa; #ifdef DEBUG struct sockaddr_in *sai; struct sockaddr_in6 *sai6; int i; #endif int rv; printf ("test_1 (\"%s\", \"%s\") ", address, port); rv = text2sockaddr (address, port, &sa) == ok; printf (rv ? "OK" : "FAIL"); printf ("\n"); #ifdef DEBUG printf ("af %d len %d ", sa->sa_family, sa->sa_len); if (sa->sa_family == AF_INET) { sai = (struct sockaddr_in *)sa; printf ("addr %08x port %d\n", ntohl (sai->sin_addr.s_addr), ntohs (sai->sin_port)); } else { sai6 = (struct sockaddr_in6 *)sa; printf ("addr "); for (i = 0; i < sizeof sai6->sin6_addr; i++) printf ("%02x", sai6->sin6_addr.s6_addr[i]); printf (" port %d\n", ntohs (sai6->sin6_port)); } #endif return rv; } isakmpd-20041012.orig/regress/util/CVS/0000755000175000017500000000000010133045751017641 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/rsakeygen/0000755000175000017500000000000010133045740020217 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/rsakeygen/Makefile0000644000175000017500000000535110133045740021663 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.15 2004/02/25 16:01:29 hshoexer Exp $ # $EOM: Makefile,v 1.10 2000/03/28 21:23:24 ho Exp $ # # Copyright (c) 1999 Niels Provos. All rights reserved. # Copyright (c) 1999, 2001 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # RSA Key Generation PROG= rsakeygen SRCS= libcrypto.c log.c rsakeygen.c sysdep.c util.c conf.c TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//' .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \ -DUSE_DEBUG NOMAN= DEBUG= -g .if ${FEATURES:Mgmp} == "gmp" CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP LDADD+= -lgmp DPADD+= ${LIBGMP} .else CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL .endif .include "${TOPSRC}/sysdep/${OS}/Makefile.sysdep" .ifdef HAVE_DLOPEN CFLAGS+= -DHAVE_DLOPEN SRCS+= dyn.c .endif .ifdef USE_LIBCRYPTO CFLAGS+= -DUSE_LIBCRYPTO LDADD+= -lcrypto DPADD+= ${LIBCRYPTO} .endif .if !defined (HAVE_DLOPEN) && !defined (USE_LIBCRYPTO) .BEGIN: @echo RSA cannot be used in this environmet, skipping... PROG= .else # USE_X509 is required for libcrypto.h to include the correct headers, # but it is not set by ${OS}/Makefile.sysdep - setting it manually here # should be safe enough. CFLAGS+= -DUSE_X509 .endif LDADD+= ${DESLIB} DPADD+= ${DESLIBDEP} .include isakmpd-20041012.orig/regress/rsakeygen/rsakeygen.c0000644000175000017500000000727210133045740022363 0ustar jdivejdive00000000000000/* $OpenBSD: rsakeygen.c,v 1.19 2004/02/26 15:27:05 hshoexer Exp $ */ /* $EOM: rsakeygen.c,v 1.10 2000/12/21 15:18:53 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. * Copyright (c) 1999, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2001 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include "libcrypto.h" #include "log.h" #include "math_mp.h" #define nibble2bin(y) (tolower (y) < 'a' ? (y) - '0' : tolower (y) - 'a' + 10) #define hexchar2bin(x) ((nibble2bin ((x)[0]) << 4) + nibble2bin ((x)[1])) #define nibble2c(x) ((x) >= 10 ? ('a' - 10 + (x)) : ('0' + (x))) #define TEST_STRING "!Dies ist ein Test" int main (void) { u_int8_t enc[256], dec[256], *asn, *foo; int len; FILE *fd; int erg = 0; RSA *key; libcrypto_init (); log_debug_cmd (LOG_CRYPTO, 99); memset (dec, '\0', sizeof dec); strlcpy (dec, TEST_STRING, 256); key = RSA_generate_key (1024, RSA_F4, NULL, NULL); if (key == NULL) { printf("Failed to generate key\n"); return 0; } printf ("n: 0x"); BN_print_fp (stdout, key->n); printf ("\ne: 0x"); BN_print_fp (stdout, key->e); printf ("\n"); printf ("n: 0x"); BN_print_fp (stdout, key->n); printf ("\ne: 0x"); BN_print_fp (stdout, key->e); printf ("\nd: 0x"); BN_print_fp (stdout, key->d); printf ("\np: 0x"); BN_print_fp (stdout, key->p); printf ("\nq: 0x"); BN_print_fp (stdout, key->q); printf ("\n"); printf ("Testing Signing/Verifying: "); /* Sign with Private Key */ len = RSA_private_encrypt (strlen (dec) + 1, dec, enc, key, RSA_PKCS1_PADDING); if (len == -1) printf ("SIGN FAILED "); else { /* Decrypt/Verify with Public Key */ erg = RSA_public_decrypt (len, enc, dec, key, RSA_PKCS1_PADDING); if (erg == -1 || strcmp (dec, TEST_STRING)) printf ("VERIFY FAILED"); else printf ("OKAY"); } printf ("\n"); len = i2d_RSAPublicKey (key, NULL); foo = asn = malloc (len); len = i2d_RSAPublicKey (key, &foo); fd = fopen ("isakmpd_key.pub", "w"); fwrite (asn, len, 1, fd); fclose (fd); free (asn); len = i2d_RSAPrivateKey (key, NULL); foo = asn = malloc (len); len = i2d_RSAPrivateKey (key, &foo); fd = fopen ("isakmpd_key", "w"); fwrite (asn, len, 1, fd); fclose (fd); free (asn); RSA_free (key); return 1; } isakmpd-20041012.orig/regress/rsakeygen/.cvsignore0000644000175000017500000000005210133045740022214 0ustar jdivejdive00000000000000isakmpd_key isakmpd_key.pub rsakeygen obj isakmpd-20041012.orig/regress/rsakeygen/CVS/0000755000175000017500000000000010133045751020654 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/ec2n/0000755000175000017500000000000010133045740017056 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/ec2n/Makefile0000644000175000017500000000100410133045740020511 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.7 2004/02/25 16:01:29 hshoexer Exp $ # $EOM: Makefile,v 1.9 2000/10/13 13:04:17 ho Exp $ # Test EC2N: PROG= ec2ntest SRCS= math_2n.c math_ec2n.c ec2ntest.c log.c sysdep.c util.c conf.c TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall NOMAN= DEBUG= -g .include isakmpd-20041012.orig/regress/ec2n/.cvsignore0000644000175000017500000000001510133045740021052 0ustar jdivejdive00000000000000ec2ntest obj isakmpd-20041012.orig/regress/ec2n/ec2ntest.c0000644000175000017500000001004210133045740020746 0ustar jdivejdive00000000000000/* $OpenBSD: ec2ntest.c,v 1.5 2003/06/04 07:31:17 ho Exp $ */ /* $EOM: ec2ntest.c,v 1.3 1998/07/16 09:21:59 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * B2N is a module for doing arithmetic on the Field GF(2**n) which is * isomorph to ring of polynomials GF(2)[x]/p(x) where p(x) is an * irreduciable polynomial over GF(2)[x] with grade n. */ #include #include #include #include "math_2n.h" #include "math_ec2n.h" #define BUFSIZE 200 #define CMP_FAIL(n,x) b2n_snprint (buf, BUFSIZE, n); if (strcmp (buf, (x))) \ printf ("FAILED: %s != %s ", buf, x); else printf ("OKAY "); int main (void) { b2n_t k; ec2np_t p, q, r; ec2ng_t g; char buf[BUFSIZE]; b2n_init (k); ec2np_init (p); ec2np_init (q); ec2np_init (r); ec2ng_init (g); printf ("Testing: ec2ng_set* :"); /* Init Group */ ec2ng_set_p_str (g, "0x0800000000000000000000004000000000000001"); CMP_FAIL (g->p, "0x0800000000000000000000004000000000000001"); ec2ng_set_a_ui (g, 0); CMP_FAIL (g->a, "0x00"); ec2ng_set_b_str (g, "0x07338f"); CMP_FAIL (g->b, "0x07338f"); printf ("\nTesting: ec2np_find_y: "); /* Init Point */ ec2np_set_x_ui (p, 0x7b); ec2np_find_y (p, g); CMP_FAIL (p->y, "0x01c8"); printf ("\nTesting: ec2np_ison: "); if (ec2np_ison (p, g)) printf ("OKAY "); else printf ("FAILED "); ec2np_set_x_ui (q, 0x4); ec2np_find_y (q, g); if (ec2np_ison (q, g)) printf ("OKAY "); else printf ("FAILED "); printf ("\nTesting: ec2np_add: "); ec2np_set (r, p); b2n_add (r->y, r->y, r->x); ec2np_add (r, r, p, g); if (!r->inf) printf ("FAILED "); else printf ("OKAY "); ec2np_add (q, p, q, g); CMP_FAIL (q->x, "0x06f32d7cc82cec8612a87a86e026350fb7595469"); CMP_FAIL (q->y, "0x4ab92e21e51358ca8deab3fbbc9f7d8a7d1575"); if (ec2np_ison (q, g)) printf ("OKAY "); else printf ("FAILED "); ec2np_add (p, q, q, g); CMP_FAIL (p->x, "0x0390001461385559a22ac9b6181c1e1889b38451"); CMP_FAIL (p->y, "0x0188e61f38d747d7813c6a8b33d14dfb7418b04c"); if (ec2np_ison (p, g)) printf ("OKAY "); else printf ("FAILED "); printf ("\nTesting: ec2np_mul: "); b2n_set_ui (k, 57); ec2np_set (q, p); ec2np_mul (q, q, k, g); if (ec2np_ison (q, g)) printf ("OKAY "); else printf ("FAILED "); CMP_FAIL (q->x, "0x06bcf88caab88f99399350c46559da3b91afbf9d"); b2n_set_str (k, "0x0800000000000000000057db5698537193aef943"); ec2np_set (q, p); ec2np_mul (q, q, k, g); if (ec2np_ison (q, g)) printf ("OKAY "); else printf ("FAILED "); CMP_FAIL (q->x, "0x0390001461385559a22ac9b6181c1e1889b38451"); printf ("\n"); ec2np_clear (p); ec2np_clear (q); ec2np_clear (r); ec2ng_clear (g); b2n_clear (k); return 1; } isakmpd-20041012.orig/regress/ec2n/CVS/0000755000175000017500000000000010133045751017513 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/crypto/0000755000175000017500000000000010133045740017547 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/crypto/Makefile0000644000175000017500000000117410133045740021212 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.11 2004/02/25 16:01:29 hshoexer Exp $ # $EOM: Makefile,v 1.7 2000/03/28 21:22:06 ho Exp $ # Test Crypto: PROG= cryptotest SRCS= crypto.c cryptotest.c conf.c log.c sysdep.c util.c TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \ -DUSE_TRIPLEDES -DUSE_CAST -DUSE_BLOWFISH -DUSE_DES \ -DUSE_AES LDADD+= -lcrypto -ldes DPADD+= ${LIBCRYPTO} ${LIBDES} NOMAN= DEBUG= -g .include isakmpd-20041012.orig/regress/crypto/cryptotest.c0000644000175000017500000001035110133045740022133 0ustar jdivejdive00000000000000/* $OpenBSD: cryptotest.c,v 1.13 2004/04/07 22:45:50 ho Exp $ */ /* $EOM: cryptotest.c,v 1.5 1998/10/07 16:40:49 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 2001 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include "crypto.h" void test_crypto (enum transform); #define SET_KEY(x,y) {size_t i; for (i=0; i < (y); i++) (x)[i] = i;} int verify_buf (u_int8_t *buf, u_int16_t len) { int i; for (i = 0; i < len; i++) if (buf[i] != i) return 0; return 1; } #define nibble2bin(y) (tolower((y)) < 'a' ? (y) - '0': tolower((y)) - 'a' + 10) #define hexchar2bin(x) ((nibble2bin((x)[0]) << 4) + nibble2bin((x)[1])) #define nibble2c(x) ((x) >= 10 ? ('a'-10+(x)) : ('0' + (x))) static void asc2bin (u_int8_t *bin, u_int8_t *asc, u_int16_t len) { int i; for (i = 0; i < len; i += 2, asc += 2) { *bin++ = hexchar2bin(asc); } } void special_test_blf (void) { u_int8_t *akey = "0123456789ABCDEFF0E1D2C3B4A59687"; u_int8_t *aiv = "FEDCBA9876543210"; u_int8_t data[] = "7654321 Now is the time for \0\0\0"; /* len 29 */ u_int8_t *acipher = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CCE7"; u_int8_t key[16], cipher[32], iv[8]; struct crypto_xf *xf; struct keystate *ks; enum cryptoerr err; int i; asc2bin (key, akey, strlen (akey)); asc2bin (iv, aiv, strlen (aiv)); asc2bin (cipher, acipher, 64); xf = crypto_get (BLOWFISH_CBC); printf ("Special Test-Case %s: ", xf->name); ks = crypto_init (xf, key, 16, &err); if (!ks) { printf ("FAILED (init %d)", err); goto fail; } crypto_init_iv (ks, iv, xf->blocksize); crypto_encrypt (ks, data, 32); for (i = 0; i < 32; i++) if (data[i] != cipher[i]) break; if (i < 32) printf ("FAILED "); else printf ("OKAY "); free (ks); fail: printf ("\n"); return; } int main (void) { test_crypto (DES_CBC); test_crypto (TRIPLEDES_CBC); test_crypto (BLOWFISH_CBC); test_crypto (CAST_CBC); test_crypto (AES_CBC); special_test_blf (); return 1; } void dump_buf (u_int8_t *buf, size_t len) { size_t i; for (i = 0; i < len; i++) printf ("%02x ", buf[i]); printf ("\n"); } void test_crypto (enum transform which) { u_int8_t buf[256]; struct crypto_xf *xf; struct keystate *ks; enum cryptoerr err; xf = crypto_get (which); printf ("Testing %s: ", xf->name); SET_KEY (buf, xf->keymax); ks = crypto_init (xf, buf, xf->keymax, &err); if (!ks) { printf ("FAILED (init %d)", err); goto fail; } SET_KEY (buf, sizeof (buf)); crypto_init_iv (ks, buf, xf->blocksize); crypto_encrypt (ks, buf, sizeof (buf)); dump_buf (buf, sizeof buf); crypto_decrypt (ks, buf, sizeof (buf)); if (!verify_buf (buf, sizeof (buf))) printf ("FAILED "); else printf ("OKAY "); free (ks); fail: printf ("\n"); return; } isakmpd-20041012.orig/regress/crypto/.cvsignore0000644000175000017500000000001710133045740021545 0ustar jdivejdive00000000000000cryptotest obj isakmpd-20041012.orig/regress/crypto/CVS/0000755000175000017500000000000010133045751020204 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/hmac/0000755000175000017500000000000010133045740017137 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/hmac/Makefile0000644000175000017500000000073210133045740020601 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.4 1999/02/26 03:28:31 niklas Exp $ # $EOM: Makefile,v 1.3 1999/02/25 15:14:24 niklas Exp $ # Test HMAC: PROG= hmactest SRCS= hash.c hmactest.c TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall NOMAN= DEBUG= -g .include isakmpd-20041012.orig/regress/hmac/hmactest.c0000644000175000017500000000571610133045740021124 0ustar jdivejdive00000000000000/* $OpenBSD: hmactest.c,v 1.5 2003/06/04 07:31:17 ho Exp $ */ /* $EOM: hmactest.c,v 1.3 1998/08/09 19:16:24 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include "hash.h" int test_hmac(char *, struct hash *, char *, int, char *, int, char *); #define nibble2c(x) ((x) >= 10 ? ('a'-10+(x)) : ('0' + (x))) int main (void) { char key[100]; memset(key, 11, 20); test_hmac ("HMAC-MD5 Test Case 1", hash_get (HASH_MD5), key, 16, "Hi There", 8, "9294727a3638bb1c13f48ef8158bfc9d"); test_hmac ("HMAC-MD5 Test Case 2", hash_get (HASH_MD5), "Jefe", 4, "what do ya want for nothing?", 28, "750c783e6ab0b503eaa86e310a5db738"); test_hmac ("HMAC-SHA1 Test Case 1", hash_get (HASH_SHA1), key, 20, "Hi There", 8, "b617318655057264e28bc0b6fb378c8ef146be00"); test_hmac ("HMAC-SHA1 Test Case 2", hash_get (HASH_SHA1), "Jefe", 4, "what do ya want for nothing?", 28, "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"); return 1; } int test_hmac(char *test, struct hash *hash, char *key, int klen, char *data, int dlen, char *cmp) { char output[2*HASH_MAX+1]; int i; printf("Testing %s: ", test); hash->HMACInit(hash, key, klen); hash->Update(hash->ctx, data, dlen); hash->HMACFinal(hash->digest, hash); for (i=0; ihashsize; i++) { output[2*i] = nibble2c((hash->digest[i] >> 4) & 0xf); output[2*i+1] = nibble2c(hash->digest[i] & 0xf); } output[2*i] = 0; if (!strcmp(output, cmp)) { printf("OKAY\n"); return 1; } printf("%s <-> %s\n", output, cmp); return 0; } isakmpd-20041012.orig/regress/hmac/.cvsignore0000644000175000017500000000001510133045740021133 0ustar jdivejdive00000000000000hmactest obj isakmpd-20041012.orig/regress/hmac/CVS/0000755000175000017500000000000010133045751017574 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/dh/0000755000175000017500000000000010133045740016622 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/dh/Makefile0000644000175000017500000000152210133045740020262 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.8 2004/02/25 16:01:29 hshoexer Exp $ # $EOM: Makefile,v 1.10 2000/04/07 20:19:43 niklas Exp $ # Test DH: PROG= dhtest SRCS= math_2n.c math_ec2n.c math_group.c dh.c dhtest.c log.c util.c \ sysdep.c gmp_util.c conf.c TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//' .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \ -DUSE_EC NOMAN= LDADD+= -lcrypto DPADD+= ${LIBCRYPTO} DEBUG= -g .if ${FEATURES:Mgmp} == "gmp" CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP LDADD+= -lgmp DPADD+= ${LIBGMP} .else CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL .endif .include isakmpd-20041012.orig/regress/dh/dhtest.c0000644000175000017500000000551310133045740020265 0ustar jdivejdive00000000000000/* $OpenBSD: dhtest.c,v 1.5 2003/06/03 14:39:50 ho Exp $ */ /* $EOM: dhtest.c,v 1.1 1998/07/18 21:14:20 provos Exp $ */ /* * Copyright (c) 1998 Niels Provos. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * This module does a Diffie-Hellman Exchange */ #include #include #include #include "math_group.h" #include "dh.h" #define DUMP_X(_x_) point = (_x_); b2n_print (point->x); int main (void) { int len; char buf[100], buf2[100]; char sec[100], sec2[100]; struct group *group, *group2; group_init (); group = group_get (4); group2 = group_get (4); printf ("Testing DH (elliptic curve): \n"); printf ("dh_getlen\n"); len = dh_getlen (group); printf ("dh_create_exchange\n"); dh_create_exchange (group, buf); dh_create_exchange (group2, buf2); printf ("dh_create_shared\n"); dh_create_shared (group, sec, buf2); dh_create_shared (group2, sec2, buf); printf ("Result: "); if (memcmp (sec, sec2, len)) printf ("FAILED "); else printf ("OKAY "); group_free (group); group_free (group2); printf ("\nTesting DH (MODP): \n"); group = group_get (1); group2 = group_get (1); printf ("dh_getlen\n"); len = dh_getlen (group); printf ("dh_create_exchange\n"); dh_create_exchange (group, buf); dh_create_exchange (group2, buf2); printf ("dh_create_shared\n"); dh_create_shared (group, sec, buf2); dh_create_shared (group2, sec2, buf); printf ("Result: "); if (memcmp (sec, sec2, len)) printf ("FAILED "); else printf ("OKAY "); printf ("\n"); return 1; } isakmpd-20041012.orig/regress/dh/.cvsignore0000644000175000017500000000001310133045740020614 0ustar jdivejdive00000000000000dhtest obj isakmpd-20041012.orig/regress/dh/CVS/0000755000175000017500000000000010133045751017257 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/exchange/0000755000175000017500000000000010133045740020011 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/exchange/Makefile0000644000175000017500000000414410133045740021454 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.7 2003/06/03 14:39:50 ho Exp $ # $EOM: Makefile,v 1.8 2000/03/28 21:22:07 ho Exp $ # # Copyright (c) 1998, 1999 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall RUN= ISAKMPD=${TOPOBJ}/isakmpd ${.CURDIR}/run.sh TESTS= def all: test: ${TESTS:S/^/test-/} .for TEST in ${TESTS} test-${TEST}: .ifdef ONLY_INIT @echo Testing "${TEST}" test as initiator @${RUN} ${RUNFLAGS} ${.CURDIR}/${TEST} .endif .ifdef ONLY_RESP @echo Testing "${TEST}" test as responder @${RUN} -r ${RUNFLAGS} ${.CURDIR}/${TEST} .endif .endfor .include .include isakmpd-20041012.orig/regress/exchange/run.pl0000644000175000017500000000670510133045740021162 0ustar jdivejdive00000000000000#!/usr/bin/perl # $OpenBSD: run.pl,v 1.2 2004/01/26 14:56:03 niklas Exp $ # $EOM: run.pl,v 1.2 1999/08/05 22:42:42 niklas Exp $ # # Copyright (c) 2004 Niklas Hallqvist. 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. # # 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. # use strict; require 5.002; require 'sys/syscall.ph'; use Socket; use Sys::Hostname; my ($rfd, $tickfac, $myaddr, $myport, $hisaddr, $hisport, $proto, $bindaddr, $conaddr, $sec, $tick, $action, $template, $data, $next, $nfd, $pkt, $verbose); $| = 1; $verbose = 1; $tickfac = 0.001; $myaddr = gethostbyname ('127.0.0.1'); $myport = 1501; $hisaddr = inet_aton ('127.0.0.1'); $hisport = 1500; $proto = getprotobyname ('udp'); $bindaddr = sockaddr_in ($myport, $myaddr); socket (SOCKET, PF_INET, SOCK_DGRAM, $proto) || die "socket: $!"; bind (SOCKET, $bindaddr); vec ($rfd, fileno SOCKET, 1) = 1; $conaddr = sockaddr_in ($hisport, $hisaddr); sub getsec { my ($tv) = pack ("ll", 0, 0); my ($tz) = pack ("ii", 0, 0); syscall (&SYS_gettimeofday, $tv, $tz) && return undef; my ($sec, $usec) = unpack ("ll", $tv); $sec % 86400 + $usec / 1000000; } $sec = &getsec; while (<>) { next if /^\s*#/o || /^\s*$/o; chop; ($tick, $action, $template, $data) = split ' ', $_, 4; while ($data =~ /\\$/o) { chop $data; $_ = <>; next if /^\s*#/o; chop; $data .= $_; } $data =~ s/\s//go; $data = pack $template, $data; $next = $sec + $tick * $tickfac; if ($action eq "send") { # Wait for the moment to come. print STDERR "waiting ", $next - $sec, " secs\n"; select undef, undef, undef, $next - $sec while ($sec = &getsec) < $next; # print $data; send SOCKET, $data, 0, $conaddr; print STDERR "sent ", unpack ("H*", $data), "\n" if $verbose; } elsif ($action eq "recv") { $sec = &getsec; printf (STDERR "waiting for data or the %.3f sec timeout\n", $next - $sec); $nfd = select $rfd, undef, undef, $next - $sec; if ($nfd) { printf STDERR "got back after %.3f secs\n", &getsec - $sec if $verbose; # sysread (STDIN, $pkt, 65536) if $nfd; sysread (SOCKET, $pkt, 65536) if $nfd; print STDERR "read ", unpack ("H*", $pkt), "\n" if $verbose; print STDERR "cmp ", unpack ("H*", $data), "\n" if $verbose; } else { print STDERR "timed out\n" if $verbose; } die "mismatch\n" if $pkt ne $data; } } isakmpd-20041012.orig/regress/exchange/mm-i-1.t0000644000175000017500000000352310133045740021176 0ustar jdivejdive00000000000000# $OpenBSD: mm-i-1.t,v 1.1 1999/08/05 22:41:39 niklas Exp $ # $EOM: mm-i-1.t,v 1.1 1999/08/05 15:07:38 niklas Exp $ # The seed to isakmpd was 19990805 # Initiate a MM 0 send H* ad9de636 f12460bb 00000000 00000000 01100200 00000000 \ 00000050 00000034 00000001 00000001 00000028 01010001 \ 00000020 00010000 80010005 80020002 80030001 80040002 \ 800b0001 800c0258 400 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 01100200 00000000 \ 00000050 00000034 00000001 00000001 00000028 01010001 \ 00000020 00010000 80010005 80020002 80030001 80040002 \ 800b0001 800c0258 110 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ 000000b4 0a000084 60a8c102 ce97687e 45e3fdd9 6fd586b4 \ f3a91167 559dd214 a78d678e 2772b7b2 83267487 15ec02a9 \ 419b77ee 0f2add09 e9e09b7d ad40c883 ef2039c9 c59b67ff \ 56e4d6f8 c99d47cb d4a565bc 8d192f76 f695d243 09121df5 \ 524884a7 3f702630 7f4fad44 e222c4b1 242fd1cd ca3a161d \ bcdf6706 025cc90d c4b00ef9 bee5ada2 00000014 ff7c493c \ 88e68a10 4ab19a6a 7e75c771 800 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ 000000b4 0a000084 681b9859 7680a3ff 894bb982 ef924bc8 \ 4d9c7ebf 3a92db7b bcfe68f7 6e1de327 a975293f f5c550b1 \ 9c69d6ed 64f201ec 514f4f44 0e6242b9 df4917e6 4418212d \ 66a66eb1 f3b70c2d 4e14e382 d42ebe04 1027957c 5dadcaf1 \ a531c085 6cee739f 433c185c 12a8a946 88622f66 f211783c \ 277e134d 22d8e809 f1d38bab 6ca2a35f 00000014 6a917048 \ a406fd47 b3d16554 cd6f0967 140 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ 0000005c d6571dec a8b55acb 1069210c 7d195417 1c2738e9 \ 42f1d9a3 8561d0ec 0697cd06 ac1beb19 1dc8acf5 904ec1d5 \ 5b2b154e 38b0de90 4f2e1f71 083047ca 10cab3d5 900 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ 00000044 b46b1db4 9ecfbfa6 a5e9baa2 8eb3cb68 be3a857c \ b039fa72 d595e69f 03669dbd 350781e2 56c36dce isakmpd-20041012.orig/regress/exchange/run.sh0000644000175000017500000000703610133045740021157 0ustar jdivejdive00000000000000#!/bin/sh # $OpenBSD: run.sh,v 1.8 2004/01/09 10:03:04 hshoexer Exp $ # $EOM: run.sh,v 1.6 1999/08/05 15:02:33 niklas Exp $ # # Copyright (c) 1998, 1999 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # Defaults SRCPORT=1500 DSTPORT=1501 FIFO=test.fifo TIMEOUT=2 NC=${NC:-/usr/bin/nc} ISAKMPD=${ISAKMPD:-/sbin/isakmpd} progname=`basename $0` indent=`echo -n $progname |sed 's/./ /g'` seed=980801 initiator=yes retval=0 verbose=no clean=yes usage () { echo "usage: $progname [-nrv] [-d dst-port] [-f fifo] [-s src-port]" >&2 echo " $indent [-t timeout] testsuite" >&2 exit 2 } set -- `getopt d:f:nrs:t:v $*` if [ $? != 0 ]; then usage fi for i; do case "$i" in -d) DSTPORT=$2; shift; shift;; -f) FIFO=$2; shift; shift;; -n) clean=no; shift;; -r) initiator=no; shift;; -s) SRCPORT=$2; shift; shift;; -t) TIMEOUT=$2; shift; shift;; -v) verbose=yes; shift;; --) shift; break;; esac done if [ $# -eq 1 ]; then suite=$1 else usage fi [ ${verbose} = yes ] && set -x # Start isakmpd and wait for the fifo to get created rm -f ${FIFO} ${ISAKMPD} -d -p${SRCPORT} -f${FIFO} -r${seed} & isakmpd_pid=$! trap 'kill $isakmpd_pid; rm -f${FIFO}; [ $clean = yes ] && rm -f packet' 1 2 15 while [ ! -p ${FIFO} ]; do sleep 1 done # Start the exchange if [ $initiator = yes ]; then ${NC} -nul -w${TIMEOUT} 127.0.0.1 ${DSTPORT} packet & # ${NC} -nu -w${TIMEOUT} -p${SRCPORT} 127.0.0.1 ${DSTPORT} packet sleep 1 echo "c udp 127.0.0.1:${DSTPORT} 2 1" >${FIFO} in_packets=`ls ${suite}-i.* 2>/dev/null` out_packets=`ls ${suite}-r.* 2>/dev/null` else in_packets=`ls ${suite}-r.* 2>/dev/null` out_packets=`ls ${suite}-i.* 2>/dev/null` fi his_turn=$initiator while [ \( $his_turn = yes -a X"$in_packets" != X \) \ -o \( $his_turn = no -a X"$out_packets" != X \) ]; do if [ $his_turn = no ]; then set $out_packets packet=$1 shift out_packets=$* cat $packet |${NC} -nu -w${TIMEOUT} -p${SRCPORT} 127.0.0.1 ${DSTPORT} \ >packet my_turn=no else set $in_packets packet=$1 shift in_packets=$* if ! cmp $packet packet 2>/dev/null; then retval=1 break fi my_turn=yes fi done kill $isakmpd_pid rm -f ${FIFO} [ $clean = yes ] && rm -f packet exit $retval isakmpd-20041012.orig/regress/exchange/README0000644000175000017500000000600210133045740020667 0ustar jdivejdive00000000000000$OpenBSD: README,v 1.1 1999/08/05 22:41:39 niklas Exp $ $EOM: README,v 1.1 1999/08/05 15:07:37 niklas Exp $ XXX The old run.sh test-framework is obsoleted, it will go away anyday. We wanted to do a regression test environment which was flexible enough to be able to easily reproduce anomalies in isakmpd. It turns out this is not easy to do, as many problems are timing related. Currently ticks are milliseconds. An idea is to try to measure isakmpd's response time somehow, and use that time as some kind of basis for a tick. Our test environment should be able to parse scripts like this: #Tick Action Format Data 0 send H* ffffffff 0 recv H* 00000000 1000 send H* deadbeef Ticks are not absolute but relative to the last event. the format is Perl's pack/unpack template formats. Data is in the given format with one exception, spaces are ignored, newlines are end-of-data unless preceeded by a backslash. Comments are lines with a numbersign as the first non-whitespace character. Empty lines are ignored, unless inside a multi-line data in which it will be part of the data buffer. Here is a real world example: # $RCSId$ # Initiate a MM 0 send H* ad9de636 f12460bb 00000000 00000000 01100200 00000000 \ 00000050 00000034 00000001 00000001 00000028 01010001 \ 00000020 00010000 80010005 80020002 80030001 80040002 \ 800b0001 800c0258 400 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 01100200 00000000 \ 00000050 00000034 00000001 00000001 00000028 01010001 \ 00000020 00010000 80010005 80020002 80030001 80040002 \ 800b0001 800c0258 110 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ 000000b4 0a000084 60a8c102 ce97687e 45e3fdd9 6fd586b4 \ f3a91167 559dd214 a78d678e 2772b7b2 83267487 15ec02a9 \ 419b77ee 0f2add09 e9e09b7d ad40c883 ef2039c9 c59b67ff \ 56e4d6f8 c99d47cb d4a565bc 8d192f76 f695d243 09121df5 \ 524884a7 3f702630 7f4fad44 e222c4b1 242fd1cd ca3a161d \ bcdf6706 025cc90d c4b00ef9 bee5ada2 00000014 ff7c493c \ 88e68a10 4ab19a6a 7e75c771 800 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ 000000b4 0a000084 681b9859 7680a3ff 894bb982 ef924bc8 \ 4d9c7ebf 3a92db7b bcfe68f7 6e1de327 a975293f f5c550b1 \ 9c69d6ed 64f201ec 514f4f44 0e6242b9 df4917e6 4418212d \ 66a66eb1 f3b70c2d 4e14e382 d42ebe04 1027957c 5dadcaf1 \ a531c085 6cee739f 433c185c 12a8a946 88622f66 f211783c \ 277e134d 22d8e809 f1d38bab 6ca2a35f 00000014 6a917048 \ a406fd47 b3d16554 cd6f0967 140 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ 0000005c d6571dec a8b55acb 1069210c 7d195417 1c2738e9 \ 42f1d9a3 8561d0ec 0697cd06 ac1beb19 1dc8acf5 904ec1d5 \ 5b2b154e 38b0de90 4f2e1f71 083047ca 10cab3d5 900 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ 00000044 b46b1db4 9ecfbfa6 a5e9baa2 8eb3cb68 be3a857c \ b039fa72 d595e69f 03669dbd 350781e2 56c36dce run with: perl run.pl filename You need to have an isakmpd listening on the address which is given in run.pl. Of course you need to run it in deterministic mode (-r). There will be a better explanation soon. isakmpd-20041012.orig/regress/exchange/.cvsignore0000644000175000017500000000000410133045740022003 0ustar jdivejdive00000000000000obj isakmpd-20041012.orig/regress/exchange/def-i.10000644000175000017500000000011010133045740021047 0ustar jdivejdive00000000000000•þT©ºçH, €€€€isakmpd-20041012.orig/regress/exchange/def-r.10000644000175000017500000000011010133045740021060 0ustar jdivejdive00000000000000•þT©ºçlðj»°H, €€€€isakmpd-20041012.orig/regress/exchange/mm-1-setup.sh0000644000175000017500000000106510133045740022254 0ustar jdivejdive00000000000000# $OpenBSD: mm-1-setup.sh,v 1.2 2000/01/26 15:23:52 niklas Exp $ # $EOM: mm-1-setup.sh,v 1.2 1999/10/05 12:54:27 niklas Exp $ # XXX Need to start isakmpd here in a nice way. echo "C set [Phase 1]:127.0.0.1=localhost 1">/tmp/fifo echo "C set [localhost]:phase=1 1">/tmp/fifo echo "C set [localhost]:transport=udp 1">/tmp/fifo echo "C set [localhost]:address=127.0.0.1 1">/tmp/fifo echo "C set [localhost]:port=1501 1">/tmp/fifo echo "C set [localhost]:configuration=default-main-mode 1">/tmp/fifo echo "C set [localhost]:authentication=mekmitasdigoat 1">/tmp/fifo isakmpd-20041012.orig/regress/exchange/CVS/0000755000175000017500000000000010133045751020446 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/exchange/mm-r-1.t0000644000175000017500000000353310133045740021210 0ustar jdivejdive00000000000000# $OpenBSD: mm-r-1.t,v 1.1 1999/08/05 22:41:39 niklas Exp $ # $EOM: mm-r-1.t,v 1.1 1999/08/05 15:07:38 niklas Exp $ # The seed to isakmpd was 19990805 # Respond to this MM 999999 recv H* ad9de636 f12460bb 00000000 00000000 01100200 00000000 \ 00000050 00000034 00000001 00000001 00000028 01010001 \ 00000020 00010000 80010005 80020002 80030001 80040002 \ 800b0001 800c0258 40 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 01100200 00000000 \ 00000050 00000034 00000001 00000001 00000028 01010001 \ 00000020 00010000 80010005 80020002 80030001 80040002 \ 800b0001 800c0258 1100 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ 000000b4 0a000084 60a8c102 ce97687e 45e3fdd9 6fd586b4 \ f3a91167 559dd214 a78d678e 2772b7b2 83267487 15ec02a9 \ 419b77ee 0f2add09 e9e09b7d ad40c883 ef2039c9 c59b67ff \ 56e4d6f8 c99d47cb d4a565bc 8d192f76 f695d243 09121df5 \ 524884a7 3f702630 7f4fad44 e222c4b1 242fd1cd ca3a161d \ bcdf6706 025cc90d c4b00ef9 bee5ada2 00000014 ff7c493c \ 88e68a10 4ab19a6a 7e75c771 80 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 04100200 00000000 \ 000000b4 0a000084 681b9859 7680a3ff 894bb982 ef924bc8 \ 4d9c7ebf 3a92db7b bcfe68f7 6e1de327 a975293f f5c550b1 \ 9c69d6ed 64f201ec 514f4f44 0e6242b9 df4917e6 4418212d \ 66a66eb1 f3b70c2d 4e14e382 d42ebe04 1027957c 5dadcaf1 \ a531c085 6cee739f 433c185c 12a8a946 88622f66 f211783c \ 277e134d 22d8e809 f1d38bab 6ca2a35f 00000014 6a917048 \ a406fd47 b3d16554 cd6f0967 1400 recv H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ 0000005c d6571dec a8b55acb 1069210c 7d195417 1c2738e9 \ 42f1d9a3 8561d0ec 0697cd06 ac1beb19 1dc8acf5 904ec1d5 \ 5b2b154e 38b0de90 4f2e1f71 083047ca 10cab3d5 90 send H* ad9de636 f12460bb 2aa5a583 ab2f3980 05100201 00000000 \ 00000044 b46b1db4 9ecfbfa6 a5e9baa2 8eb3cb68 be3a857c \ b039fa72 d595e69f 03669dbd 350781e2 56c36dce isakmpd-20041012.orig/regress/CVS/0000755000175000017500000000000010133045751016664 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/prf/0000755000175000017500000000000010133045740017016 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/prf/Makefile0000644000175000017500000000077010133045740020462 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.7 2004/02/25 16:01:29 hshoexer Exp $ # $EOM: Makefile,v 1.6 2000/03/28 21:22:07 ho Exp $ # Test PRF: PROG= prftest SRCS= prf.c hash.c log.c prftest.c conf.c sysdep.c util.c TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall NOMAN= DEBUG= -g .include isakmpd-20041012.orig/regress/prf/.cvsignore0000644000175000017500000000001410133045740021011 0ustar jdivejdive00000000000000prftest obj isakmpd-20041012.orig/regress/prf/prftest.c0000644000175000017500000000701410133045740020653 0ustar jdivejdive00000000000000/* $OpenBSD: prftest.c,v 1.7 2003/06/03 14:39:51 ho Exp $ */ /* $EOM: prftest.c,v 1.2 1998/10/07 16:40:50 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include "hash.h" #include "prf.h" int test_prf (char *, enum hashes, char *, int, char *, int, char *); #define nibble2c(x) ((x) >= 10 ? ('a'-10+(x)) : ('0' + (x))) /* * Basically the same as the HMAC regress, but to keep with modularity * prf seems to be useful. So here we just check the HMAC test cases, * until there are more PRFs. */ int main (void) { char key[100]; memset (key, 11, 20); test_prf ("PRF MD5 Test Case 1", HASH_MD5, key, 16, "Hi There", 8, "9294727a3638bb1c13f48ef8158bfc9d"); test_prf ("PRF MD5 Test Case 2", HASH_MD5, "Jefe", 4, "what do ya want for nothing?", 28, "750c783e6ab0b503eaa86e310a5db738"); test_prf ("PRF SHA1 Test Case 1", HASH_SHA1, key, 20, "Hi There", 8, "b617318655057264e28bc0b6fb378c8ef146be00"); test_prf ("PRF SHA1 Test Case 2", HASH_SHA1, "Jefe", 4, "what do ya want for nothing?", 28, "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"); test_prf ("PRF SHA1 Test Case 3", HASH_SHA1, "Bloody long key, this one, eben longer than the blocksize " "of ordinary keyed HMAC functions", 90, "what do ya want for nothing?", 28, "52ca5fbcd7d4821bc6bf8b6e95e131109dff901b"); return 0; } int test_prf (char *test, enum hashes hash, char *key, int klen, char *data, int dlen, char *cmp) { char output[2*HASH_MAX+1]; char digest[HASH_MAX]; struct prf *prf; int i; printf ("Testing %s: ", test); prf = prf_alloc (PRF_HMAC, hash, key, klen); if (!prf) { printf("prf_alloc () failed\n"); return 0; } prf->Init (prf->prfctx); prf->Update (prf->prfctx, data, dlen); prf->Final (digest, prf->prfctx); prf_free (prf); for (i = 0; i < prf->blocksize; i++) { output[2 * i] = nibble2c ((digest[i] >> 4) & 0xf); output[2 * i + 1] = nibble2c (digest[i] & 0xf); } output[2 * i] = 0; if (strcmp (output, cmp) == 0) { printf ("OKAY\n"); return 1; } printf ("%s <-> %s\n", output, cmp); return 0; } isakmpd-20041012.orig/regress/prf/CVS/0000755000175000017500000000000010133045751017453 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/x509/0000755000175000017500000000000010133045740016734 5ustar jdivejdive00000000000000isakmpd-20041012.orig/regress/x509/Makefile0000644000175000017500000000561110133045740020377 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.14 2003/06/03 14:39:51 ho Exp $ # $EOM: Makefile,v 1.16 2000/09/28 12:53:27 niklas Exp $ # # Copyright (c) 1999 Niels Provos. All rights reserved. # Copyright (c) 1999, 2001 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # Test X509 # Enable this if you have a DNSSEC enabled OpenSSL #LIBLWRES= /usr/local/lib/liblwres.a PROG= x509test SRCS= x509test.c conf.c log.c libcrypto.c sysdep.c field.c util.c \ isakmp_fld.c ipsec_fld.c ipsec_num.c isakmp_num.c constants.c \ cert.c TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//' .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall \ -DUSE_X509 NOMAN= DEBUG= -g .if ${FEATURES:Mgmp} == "gmp" CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP LDADD+= -lgmp DPADD+= ${LIBGMP} .else CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL .endif .include "${TOPSRC}/sysdep/${OS}/Makefile.sysdep" .ifdef HAVE_DLOPEN X509= x509.c POLICY= policy.c CFLAGS+= -DHAVE_DLOPEN SRCS+= dyn.c .endif .ifdef USE_KEYNOTE USE_LIBCRYPTO= yes POLICY= policy.c LDADD+= -lkeynote -lm DPADD+= ${LIBKEYNOTE} ${LIBM} CFLAGS+= -DUSE_KEYNOTE .endif .ifdef USE_LIBCRYPTO X509= x509.c CFLAGS+= -DUSE_LIBCRYPTO LDADD+= -lcrypto ${LIBLWRES} DPADD+= ${LIBCRYPTO} .endif .if !defined (HAVE_DLOPEN) && !defined (USE_LIBCRYPTO) || !defined (USE_KEYNOTE) .BEGIN: PROG= .endif SRCS+= ${X509} ${POLICY} LDADD+= ${DESLIB} DPADD+= ${DESLIBDEP} .include isakmpd-20041012.orig/regress/x509/x509test.c0000644000175000017500000001656010133045740020515 0ustar jdivejdive00000000000000/* $OpenBSD: x509test.c,v 1.22 2003/06/03 14:39:51 ho Exp $ */ /* $EOM: x509test.c,v 1.9 2000/12/21 15:24:25 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. * Copyright (c) 1999, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2001 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * This program takes a certificate generated by ssleay and a key pair * from rsakeygen. It reads the IP address from certificate.txt and * includes this as subject alt name extension into the certifcate. * The result gets written as new certificate that can be used by * isakmpd. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "conf.h" #include "ipsec_num.h" #include "isakmp_fld.h" #include "libcrypto.h" #include "log.h" #include "math_mp.h" #include "x509.h" static int x509_check_subjectaltname (u_char *, u_int, X509 *); u_int32_t file_sz; #if 0 /* XXX Currently unused. */ static u_int8_t * open_file (char *name) { int fd; struct stat st; u_int8_t *addr; if (stat (name, &st) == -1) log_fatal ("stat (\"%s\", &st)", name); file_sz = st.st_size; fd = open (name, O_RDONLY); if (fd == -1) log_fatal ("open (\"%s\", O_RDONLY)", name); addr = mmap (0, file_sz, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) log_fatal ("mmap (0, %d, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE," "%d, 0)", file_sz, fd); close (fd); return addr; } #endif /* * Check that a certificate has a subjectAltName and that it matches our ID. */ static int x509_check_subjectaltname (u_char *id, u_int id_len, X509 *scert) { u_int8_t *altname; u_int32_t altlen; int type, idtype, ret; type = x509_cert_subjectaltname (scert, &altname, &altlen); if (!type) { log_print ("x509_check_subjectaltname: can't access subjectAltName"); return 0; } /* * Now that we have the X509 certicate in native form, get the * subjectAltName extension and verify that it matches our ID. */ /* XXX Get type of ID. */ idtype = id[0]; id += ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; id_len -= ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; ret = 0; switch (idtype) { case IPSEC_ID_IPV4_ADDR: if (type == X509v3_IP_ADDR) ret = 1; break; case IPSEC_ID_FQDN: if (type == X509v3_DNS_NAME) ret = 1; break; case IPSEC_ID_USER_FQDN: if (type == X509v3_RFC_NAME) ret = 1; break; default: ret = 0; break; } if (!ret) { LOG_DBG ((LOG_CRYPTO, 50, "x509_check_subjectaltname: " "our ID type (%d) does not match X509 cert ID type (%d)", idtype, type)); return 0; } if (altlen != id_len || memcmp (altname, id, id_len) != 0) { LOG_DBG ((LOG_CRYPTO, 50, "x509_check_subjectaltname: " "our ID does not match X509 cert ID")); return 0; } return 1; } int main (int argc, char *argv[]) { RSA *pub_key, *priv_key; X509 *cert; BIO *certfile, *keyfile; EVP_PKEY *pkey_pub; u_char ipaddr[6]; struct in_addr saddr; char enc[256], dec[256]; u_int8_t idpayload[8]; int err, len; if (argc < 3 || argc > 4) { fprintf (stderr, "usage: x509test private-key certificate ip-address\n"); exit (1); } /* * X509_verify will fail, as will all other functions that call * EVP_get_digest_byname. */ libcrypto_init (); printf ("Reading private key %s\n", argv[1]); keyfile = BIO_new (BIO_s_file ()); if (BIO_read_filename (keyfile, argv[1]) == -1) { perror ("read"); exit (1); } #if SSLEAY_VERSION_NUMBER >= 0x00904100L priv_key = PEM_read_bio_RSAPrivateKey (keyfile, NULL, NULL, NULL); #else priv_key = PEM_read_bio_RSAPrivateKey (keyfile, NULL, NULL); #endif BIO_free (keyfile); if (priv_key == NULL) { printf("PEM_read_bio_RSAPrivateKey () failed\n"); exit (1); } /* Use a certificate created by ssleay. */ printf ("Reading ssleay created certificate %s\n", argv[2]); certfile = BIO_new (BIO_s_file ()); if (BIO_read_filename (certfile, argv[2]) == -1) { perror ("read"); exit (1); } #if SSLEAY_VERSION_NUMBER >= 0x00904100L cert = PEM_read_bio_X509 (certfile, NULL, NULL, NULL); #else cert = PEM_read_bio_X509 (certfile, NULL, NULL); #endif BIO_free (certfile); if (cert == NULL) { printf("PEM_read_bio_X509 () failed\n"); exit (1); } pkey_pub = X509_get_pubkey (cert); /* XXX Violation of the interface? */ pub_key = pkey_pub->pkey.rsa; if (pub_key == NULL) { exit (1); } printf ("Testing RSA keys: "); err = 0; strlcpy (dec, "Eine kleine Testmeldung", 256); if ((len = RSA_private_encrypt (strlen (dec), dec, enc, priv_key, RSA_PKCS1_PADDING)) == -1) printf ("SIGN FAILED "); else err = RSA_public_decrypt (len, enc, dec, pub_key, RSA_PKCS1_PADDING); if (err == -1 || strcmp (dec, "Eine kleine Testmeldung")) printf ("SIGN/VERIFY FAILED"); else printf ("OKAY"); printf ("\n"); printf ("Validate SIGNED: "); err = X509_verify (cert, pkey_pub); printf ("X509 verify: %d ", err); if (err == -1) printf ("FAILED "); else printf ("OKAY "); printf ("\n"); if (argc == 4) { printf ("Verifying extension: "); if (inet_aton (argv[3], &saddr) == 0) { printf ("inet_aton () failed\n"); exit (1); } saddr.s_addr = htonl (saddr.s_addr); ipaddr[0] = 0x87; ipaddr[1] = 0x04; ipaddr[2] = saddr.s_addr >> 24; ipaddr[3] = (saddr.s_addr >> 16) & 0xff; ipaddr[4] = (saddr.s_addr >> 8) & 0xff; ipaddr[5] = saddr.s_addr & 0xff; bzero (idpayload, sizeof idpayload); idpayload[0] = IPSEC_ID_IPV4_ADDR; bcopy (ipaddr + 2, idpayload + 4, 4); if (!x509_check_subjectaltname (idpayload, sizeof idpayload, cert)) printf("FAILED "); else printf("OKAY "); printf ("\n"); } return 1; } isakmpd-20041012.orig/regress/x509/.cvsignore0000644000175000017500000000001510133045740020730 0ustar jdivejdive00000000000000x509test obj isakmpd-20041012.orig/regress/x509/CVS/0000755000175000017500000000000010133045751017371 5ustar jdivejdive00000000000000isakmpd-20041012.orig/util.c0000644000175000017500000002506610133045740015707 0ustar jdivejdive00000000000000/* $OpenBSD: util.c,v 1.48 2004/08/08 19:11:06 deraadt Exp $ */ /* $EOM: util.c,v 1.23 2000/11/23 12:22:08 niklas Exp $ */ /* * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2000, 2001, 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include #include #include #include #include #include "sysdep.h" #include "log.h" #include "message.h" #include "monitor.h" #include "sysdep.h" #include "transport.h" #include "util.h" /* * Set if -N is given, allowing name lookups to be done, possibly stalling * the daemon for quite a while. */ int allow_name_lookups = 0; /* * This is set to true in case of regression-test mode, when it will * cause predictable random numbers be generated. */ int regrand = 0; /* * If in regression-test mode, this is the seed used. */ u_long seed; /* * XXX These might be turned into inlines or macros, maybe even * machine-dependent ones, for performance reasons. */ u_int16_t decode_16(u_int8_t *cp) { return cp[0] << 8 | cp[1]; } u_int32_t decode_32(u_int8_t *cp) { return cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; } u_int64_t decode_64(u_int8_t *cp) { return (u_int64_t) cp[0] << 56 | (u_int64_t) cp[1] << 48 | (u_int64_t) cp[2] << 40 | (u_int64_t) cp[3] << 32 | cp[4] << 24 | cp[5] << 16 | cp[6] << 8 | cp[7]; } #if 0 /* * XXX I severly doubt that we will need this. IPv6 does not have the legacy * of representation in host byte order, AFAIK. */ void decode_128(u_int8_t *cp, u_int8_t *cpp) { #if BYTE_ORDER == LITTLE_ENDIAN int i; for (i = 0; i < 16; i++) cpp[i] = cp[15 - i]; #elif BYTE_ORDER == BIG_ENDIAN bcopy(cp, cpp, 16); #else #error "Byte order unknown!" #endif } #endif void encode_16(u_int8_t *cp, u_int16_t x) { *cp++ = x >> 8; *cp = x & 0xff; } void encode_32(u_int8_t *cp, u_int32_t x) { *cp++ = x >> 24; *cp++ = (x >> 16) & 0xff; *cp++ = (x >> 8) & 0xff; *cp = x & 0xff; } void encode_64(u_int8_t *cp, u_int64_t x) { *cp++ = x >> 56; *cp++ = (x >> 48) & 0xff; *cp++ = (x >> 40) & 0xff; *cp++ = (x >> 32) & 0xff; *cp++ = (x >> 24) & 0xff; *cp++ = (x >> 16) & 0xff; *cp++ = (x >> 8) & 0xff; *cp = x & 0xff; } #if 0 /* * XXX I severly doubt that we will need this. IPv6 does not have the legacy * of representation in host byte order, AFAIK. */ void encode_128(u_int8_t *cp, u_int8_t *cpp) { decode_128(cpp, cp); } #endif /* Check a buffer for all zeroes. */ int zero_test(const u_int8_t *p, size_t sz) { while (sz-- > 0) if (*p++ != 0) return 0; return 1; } /* Check a buffer for all ones. */ int ones_test(const u_int8_t *p, size_t sz) { while (sz-- > 0) if (*p++ != 0xff) return 0; return 1; } /* * Generate a random data, len bytes long. */ u_int8_t * getrandom(u_int8_t *buf, size_t len) { u_int32_t tmp = 0; size_t i; for (i = 0; i < len; i++) { if (i % sizeof tmp == 0) tmp = sysdep_random(); buf[i] = tmp & 0xff; tmp >>= 8; } return buf; } static __inline int hex2nibble(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } /* * Convert hexadecimal string in S to raw binary buffer at BUF sized SZ * bytes. Return 0 if everything is OK, -1 otherwise. */ int hex2raw(char *s, u_int8_t *buf, size_t sz) { u_int8_t *bp; char *p; int tmp; if (strlen(s) > sz * 2) return -1; for (p = s + strlen(s) - 1, bp = &buf[sz - 1]; bp >= buf; bp--) { *bp = 0; if (p >= s) { tmp = hex2nibble(*p--); if (tmp == -1) return -1; *bp = tmp; } if (p >= s) { tmp = hex2nibble(*p--); if (tmp == -1) return -1; *bp |= tmp << 4; } } return 0; } int text2sockaddr(char *address, char *port, struct sockaddr **sa) { struct addrinfo *ai, hints; memset(&hints, 0, sizeof hints); if (!allow_name_lookups) hints.ai_flags = AI_NUMERICHOST; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; if (getaddrinfo(address, port, &hints, &ai)) return -1; *sa = malloc(sysdep_sa_len(ai->ai_addr)); if (!*sa) { freeaddrinfo(ai); return -1; } memcpy(*sa, ai->ai_addr, sysdep_sa_len(ai->ai_addr)); freeaddrinfo(ai); return 0; } /* * Convert a sockaddr to text. With zflag non-zero fill out with zeroes, * i.e 10.0.0.10 --> "010.000.000.010" */ int sockaddr2text(struct sockaddr *sa, char **address, int zflag) { char buf[NI_MAXHOST], *token, *bstart, *ep; int addrlen, i, j; long val; if (getnameinfo(sa, sysdep_sa_len(sa), buf, sizeof buf, 0, 0, allow_name_lookups ? 0 : NI_NUMERICHOST)) return -1; if (zflag == 0) { *address = strdup(buf); if (!*address) return -1; } else switch (sa->sa_family) { case AF_INET: addrlen = sizeof "000.000.000.000"; *address = malloc(addrlen); if (!*address) return -1; buf[addrlen] = '\0'; bstart = buf; **address = '\0'; while ((token = strsep(&bstart, ".")) != NULL) { if (strlen(*address) > 12) { free(*address); return -1; } val = strtol(token, &ep, 10); if (ep == token || val < (long)0 || val > (long)UCHAR_MAX) { free(*address); return -1; } snprintf(*address + strlen(*address), addrlen - strlen(*address), "%03ld", val); if (bstart) strlcat(*address, ".", addrlen); } break; case AF_INET6: /* * XXX In the algorithm below there are some magic * numbers we probably could give explaining names. */ addrlen = sizeof "0000:0000:0000:0000:0000:0000:0000:0000"; *address = malloc(addrlen); if (!*address) return -1; for (i = 0, j = 0; i < 8; i++) { snprintf((*address) + j, addrlen - j, "%02x%02x", ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2*i], ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2*i + 1]); j += 4; (*address)[j] = (j < (addrlen - 1)) ? ':' : '\0'; j++; } break; default: *address = strdup(""); if (!*address) return -1; } return 0; } /* * sockaddr_addrlen and sockaddr_addrdata return the relevant sockaddr info * depending on address family. Useful to keep other code shorter(/clearer?). */ int sockaddr_addrlen(struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET6: return sizeof((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr; case AF_INET: return sizeof((struct sockaddr_in *)sa)->sin_addr.s_addr; default: log_print("sockaddr_addrlen: unsupported protocol family %d", sa->sa_family); return 0; } } u_int8_t * sockaddr_addrdata(struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET6: return (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr; case AF_INET: return (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr.s_addr; default: log_print("sockaddr_addrdata: unsupported protocol family %d", sa->sa_family); return 0; } } in_port_t sockaddr_port(struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET6: return ((struct sockaddr_in6 *)sa)->sin6_port; case AF_INET: return ((struct sockaddr_in *)sa)->sin_port; default: log_print("sockaddr_port: unsupported protocol family %d", sa->sa_family); return 0; } } /* Utility function used to set the port of a sockaddr. */ void sockaddr_set_port(struct sockaddr *sa, in_port_t port) { switch (sa->sa_family) { case AF_INET: ((struct sockaddr_in *)sa)->sin_port = htons (port); break; case AF_INET6: ((struct sockaddr_in6 *)sa)->sin6_port = htons (port); break; } } /* * Convert network address to text. The network address does not need * to be properly aligned. */ void util_ntoa(char **buf, int af, u_int8_t *addr) { struct sockaddr_storage from; struct sockaddr *sfrom = (struct sockaddr *) & from; socklen_t fromlen = sizeof from; memset(&from, 0, fromlen); sfrom->sa_family = af; #ifndef USE_OLD_SOCKADDR switch (af) { case AF_INET: sfrom->sa_len = sizeof(struct sockaddr_in); break; case AF_INET6: sfrom->sa_len = sizeof(struct sockaddr_in6); break; } #endif memcpy(sockaddr_addrdata(sfrom), addr, sockaddr_addrlen(sfrom)); if (sockaddr2text(sfrom, buf, 0)) { log_print("util_ntoa: could not make printable address out " "of sockaddr %p", sfrom); *buf = 0; } } /* * Perform sanity check on files containing secret information. * Returns -1 on failure, 0 otherwise. * Also, if FILE_SIZE is a not a null pointer, store file size here. */ int check_file_secrecy_fd(int fd, char *name, size_t *file_size) { struct stat st; if (fstat(fd, &st) == -1) { log_error("check_file_secrecy: stat (\"%s\") failed", name); return -1; } if (st.st_uid != 0 && st.st_uid != getuid()) { log_print("check_file_secrecy_fd: " "not loading %s - file owner is not process user", name); errno = EPERM; return -1; } if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) { log_print("check_file_secrecy_fd: not loading %s - too open " "permissions", name); errno = EPERM; return -1; } if (file_size) *file_size = (size_t)st.st_size; return 0; } /* Special for compiling with Boehms GC. See Makefile and sysdep.h */ #if defined (USE_BOEHM_GC) char * gc_strdup(const char *x) { char *strcpy(char *,const char *); char *y = malloc(strlen(x) + 1); return strcpy(y,x); } #endif isakmpd-20041012.orig/dpd.c0000644000175000017500000002362010133045740015473 0ustar jdivejdive00000000000000/* $OpenBSD: dpd.c,v 1.4 2004/08/10 15:59:10 ho Exp $ */ /* * Copyright (c) 2004 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. * * 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 #include #include "sysdep.h" #include "conf.h" #include "dpd.h" #include "exchange.h" #include "hash.h" #include "ipsec.h" #include "isakmp_fld.h" #include "log.h" #include "message.h" #include "sa.h" #include "timer.h" #include "transport.h" #include "util.h" /* From RFC 3706. */ #define DPD_MAJOR 0x01 #define DPD_MINOR 0x00 #define DPD_SEQNO_SZ 4 static const char dpd_vendor_id[] = { 0xAF, 0xCA, 0xD7, 0x13, 0x68, 0xA1, 0xF1, /* RFC 3706 */ 0xC9, 0x6B, 0x86, 0x96, 0xFC, 0x77, 0x57, DPD_MAJOR, DPD_MINOR }; #define DPD_RETRANS_MAX 5 /* max number of retries. */ #define DPD_RETRANS_WAIT 5 /* seconds between retries. */ /* DPD Timer State */ enum dpd_tstate { DPD_TIMER_NORMAL, DPD_TIMER_CHECK }; static void dpd_check_event(void *); static void dpd_event(void *); static u_int32_t dpd_timer_interval(u_int32_t); static void dpd_timer_reset(struct sa *, u_int32_t, enum dpd_tstate); /* Add the DPD VENDOR ID payload. */ int dpd_add_vendor_payload(struct message *msg) { u_int8_t *buf; size_t buflen = sizeof dpd_vendor_id + ISAKMP_GEN_SZ; buf = malloc(buflen); if (!buf) { log_error("dpd_add_vendor_payload: malloc(%lu) failed", (unsigned long)buflen); return -1; } SET_ISAKMP_GEN_LENGTH(buf, buflen); memcpy(buf + ISAKMP_VENDOR_ID_OFF, dpd_vendor_id, sizeof dpd_vendor_id); if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) { free(buf); return -1; } return 0; } /* * Check an incoming message for DPD capability markers. */ void dpd_check_vendor_payload(struct message *msg, struct payload *p) { u_int8_t *pbuf = p->p; size_t vlen; /* Already checked? */ if (msg->exchange->flags & EXCHANGE_FLAG_DPD_CAP_PEER) { /* Just mark it as handled and return. */ p->flags |= PL_MARK; return; } vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ; if (vlen != sizeof dpd_vendor_id) { LOG_DBG((LOG_EXCHANGE, 90, "dpd_check_vendor_payload: bad size %d != %d", vlen, sizeof dpd_vendor_id)); return; } if (memcmp(dpd_vendor_id, pbuf + ISAKMP_GEN_SZ, vlen) == 0) { /* This peer is DPD capable. */ if (msg->isakmp_sa) { msg->exchange->flags |= EXCHANGE_FLAG_DPD_CAP_PEER; LOG_DBG((LOG_EXCHANGE, 10, "dpd_check_vendor_payload: " "DPD capable peer detected")); if (dpd_timer_interval(0) != 0) { LOG_DBG((LOG_EXCHANGE, 10, "dpd_check_vendor_payload: enabling")); msg->isakmp_sa->flags |= SA_FLAG_DPD; dpd_timer_reset(msg->isakmp_sa, 0, DPD_TIMER_NORMAL); } } p->flags |= PL_MARK; } return; } /* * All incoming DPD Notify messages enter here. Message has been validated. */ void dpd_handle_notify(struct message *msg, struct payload *p) { struct sa *isakmp_sa = msg->isakmp_sa; u_int16_t notify = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p); u_int32_t p_seq; /* Extract the sequence number. */ memcpy(&p_seq, p->p + ISAKMP_NOTIFY_SPI_OFF + ISAKMP_HDR_COOKIES_LEN, sizeof p_seq); p_seq = ntohl(p_seq); LOG_DBG((LOG_MESSAGE, 40, "dpd_handle_notify: got %s seq %u", constant_name(isakmp_notify_cst, notify), p_seq)); switch (notify) { case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE: /* The other peer wants to know we're alive. */ if (p_seq <= isakmp_sa->dpd_rseq) { log_print("dpd_handle_notify: bad R_U_THERE seqno " "%u <= %u", p_seq, isakmp_sa->dpd_rseq); return; } isakmp_sa->dpd_rseq = p_seq; message_send_dpd_notify(isakmp_sa, ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK, p_seq); break; case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK: /* This should be a response to a R_U_THERE we've sent. */ if (isakmp_sa->dpd_seq != p_seq) { log_print("dpd_handle_notify: got bad ACK seqno %u, " "expected %u", p_seq, isakmp_sa->dpd_seq); /* XXX Give up? Retry? */ return; } break; default: } /* Mark handled. */ p->flags |= PL_MARK; /* The other peer is alive, so we can safely wait a while longer. */ if (isakmp_sa->flags & SA_FLAG_DPD) dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_NORMAL); } /* Calculate the time until next DPD exchange. */ static u_int32_t dpd_timer_interval(u_int32_t offset) { int32_t v = 0; #ifdef notyet v = ...; /* XXX Per-peer specified DPD intervals? */ #endif if (!v) v = conf_get_num("General", "DPD-check-interval", 0); if (v < 1) return 0; /* DPD-Check-Interval < 1 means disable DPD */ v -= offset; return v < 1 ? 1 : v; } static void dpd_timer_reset(struct sa *sa, u_int32_t time_passed, enum dpd_tstate mode) { struct timeval tv; if (sa->dpd_event) timer_remove_event(sa->dpd_event); gettimeofday(&tv, 0); switch (mode) { case DPD_TIMER_NORMAL: tv.tv_sec += dpd_timer_interval(time_passed); sa->dpd_event = timer_add_event("dpd_event", dpd_event, sa, &tv); break; case DPD_TIMER_CHECK: tv.tv_sec += DPD_RETRANS_WAIT; sa->dpd_event = timer_add_event("dpd_check_event", dpd_check_event, sa, &tv); break; default: } if (!sa->dpd_event) log_print("dpd_timer_reset: timer_add_event failed"); } /* Helper function for dpd_exchange_finalization(). */ static int dpd_find_sa(struct sa *sa, void *v_sa) { struct sa *isakmp_sa = v_sa; return (sa->phase == 2 && memcmp(sa->id_i, isakmp_sa->id_i, sa->id_i_len) == 0 && memcmp(sa->id_r, isakmp_sa->id_r, sa->id_r_len) == 0); } struct dpd_args { struct sa *isakmp_sa; u_int32_t interval; }; /* Helper function for dpd_event(). */ static int dpd_check_time(struct sa *sa, void *v_arg) { struct dpd_args *args = v_arg; struct sockaddr *dst; struct proto *proto; struct sa_kinfo *ksa; struct timeval tv; if (sa->phase == 1 || (args->isakmp_sa->flags & SA_FLAG_DPD) == 0 || dpd_find_sa(sa, args->isakmp_sa) == 0) return 0; proto = TAILQ_FIRST(&sa->protos); if (!proto || !proto->data) return 0; sa->transport->vtbl->get_src(sa->transport, &dst); gettimeofday(&tv, 0); ksa = sysdep_ipsec_get_kernel_sa(proto->spi[1], proto->spi_sz[1], proto->proto, dst); if (!ksa || !ksa->last_used) return 0; LOG_DBG((LOG_MESSAGE, 80, "dpd_check_time: " "SA %p last use %u second(s) ago", sa, (u_int32_t)(tv.tv_sec - ksa->last_used))); if ((u_int32_t)(tv.tv_sec - ksa->last_used) < args->interval) { args->interval = (u_int32_t)(tv.tv_sec - ksa->last_used); return 1; } return 0; } /* Called by the timer. */ static void dpd_event(void *v_sa) { struct sa *isakmp_sa = v_sa; struct dpd_args args; #if defined (USE_DEBUG) struct sockaddr *dst; char *addr; #endif isakmp_sa->dpd_event = 0; /* Check if there's been any incoming SA activity since last time. */ args.isakmp_sa = isakmp_sa; args.interval = dpd_timer_interval(0); if (sa_find(dpd_check_time, &args)) { if (args.interval > dpd_timer_interval(0)) args.interval = 0; dpd_timer_reset(isakmp_sa, args.interval, DPD_TIMER_NORMAL); return; } /* No activity seen, do a DPD exchange. */ if (isakmp_sa->dpd_seq == 0) { /* * RFC 3706: first seq# should be random, with MSB zero, * otherwise we just increment it. */ getrandom((u_int8_t *)&isakmp_sa->dpd_seq, sizeof isakmp_sa->dpd_seq); isakmp_sa->dpd_seq &= 0x7FFF; } else isakmp_sa->dpd_seq++; #if defined (USE_DEBUG) isakmp_sa->transport->vtbl->get_dst(isakmp_sa->transport, &dst); if (sockaddr2text(dst, &addr, 0) == -1) addr = 0; LOG_DBG((LOG_MESSAGE, 30, "dpd_event: sending R_U_THERE to %s seq %u", addr ? addr : "", isakmp_sa->dpd_seq)); if (addr) free(addr); #endif message_send_dpd_notify(isakmp_sa, ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE, isakmp_sa->dpd_seq); /* And set the short timer. */ dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_CHECK); } /* * Called by the timer. If this function is called, it means we did not * recieve any R_U_THERE_ACK confirmation from the other peer. */ static void dpd_check_event(void *v_sa) { struct sa *isakmp_sa = v_sa; struct sa *sa; isakmp_sa->dpd_event = 0; if (++isakmp_sa->dpd_failcount < DPD_RETRANS_MAX) { LOG_DBG((LOG_MESSAGE, 10, "dpd_check_event: " "peer not responding, retry %u of %u", isakmp_sa->dpd_failcount, DPD_RETRANS_MAX)); message_send_dpd_notify(isakmp_sa, ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE, isakmp_sa->dpd_seq); dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_CHECK); return; } /* * Peer is considered dead. Delete all SAs created under isakmp_sa. */ LOG_DBG((LOG_MESSAGE, 10, "dpd_check_event: peer is dead, " "deleting all SAs connected to SA %p", isakmp_sa)); while ((sa = sa_find(dpd_find_sa, isakmp_sa)) != 0) { LOG_DBG((LOG_MESSAGE, 30, "dpd_check_event: deleting SA %p", sa)); sa_delete(sa, 0); } LOG_DBG((LOG_MESSAGE, 30, "dpd_check_event: deleting ISAKMP SA %p", isakmp_sa)); sa_delete(isakmp_sa, 0); } isakmpd-20041012.orig/cert.c0000644000175000017500000001017210133045740015657 0ustar jdivejdive00000000000000/* $OpenBSD: cert.c,v 1.28 2004/06/14 09:55:41 ho Exp $ */ /* $EOM: cert.c,v 1.18 2000/09/28 12:53:27 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. * Copyright (c) 1999, 2000 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include "sysdep.h" #include "isakmp_num.h" #include "log.h" #include "cert.h" #ifdef USE_X509 #include "x509.h" #endif #ifdef USE_KEYNOTE #include "policy.h" #endif struct cert_handler cert_handler[] = { #ifdef USE_X509 { ISAKMP_CERTENC_X509_SIG, x509_cert_init, x509_crl_init, x509_cert_get, x509_cert_validate, x509_cert_insert, x509_cert_free, x509_certreq_validate, x509_certreq_decode, x509_free_aca, x509_cert_obtain, x509_cert_get_key, x509_cert_get_subjects, x509_cert_dup, x509_serialize, x509_printable, x509_from_printable }, #endif #ifdef USE_KEYNOTE { ISAKMP_CERTENC_KEYNOTE, keynote_cert_init, NULL, keynote_cert_get, keynote_cert_validate, keynote_cert_insert, keynote_cert_free, keynote_certreq_validate, keynote_certreq_decode, keynote_free_aca, keynote_cert_obtain, keynote_cert_get_key, keynote_cert_get_subjects, keynote_cert_dup, keynote_serialize, keynote_printable, keynote_from_printable }, #endif }; /* Initialize all certificate handlers */ int cert_init(void) { size_t i; int err = 1; for (i = 0; i < sizeof cert_handler / sizeof cert_handler[0]; i++) if (cert_handler[i].cert_init && !(*cert_handler[i].cert_init)()) err = 0; return err; } int crl_init(void) { size_t i; int err = 1; for (i = 0; i < sizeof cert_handler / sizeof cert_handler[0]; i++) if (cert_handler[i].crl_init && !(*cert_handler[i].crl_init)()) err = 0; return err; } struct cert_handler * cert_get(u_int16_t id) { size_t i; for (i = 0; i < sizeof cert_handler / sizeof cert_handler[0]; i++) if (id == cert_handler[i].id) return &cert_handler[i]; return 0; } /* * Decode the certificate request of type TYPE contained in DATA extending * DATALEN bytes. Return a certreq_aca structure which the caller is * responsible for deallocating. */ struct certreq_aca * certreq_decode(u_int16_t type, u_int8_t *data, u_int32_t datalen) { struct cert_handler *handler; struct certreq_aca aca, *ret; handler = cert_get(type); if (!handler) return 0; aca.id = type; aca.handler = handler; if (datalen > 0) { aca.data = handler->certreq_decode(data, datalen); if (!aca.data) return 0; } else aca.data = 0; ret = malloc(sizeof aca); if (!ret) { log_error("certreq_decode: malloc (%lu) failed", (unsigned long)sizeof aca); handler->free_aca(aca.data); return 0; } memcpy(ret, &aca, sizeof aca); return ret; } void cert_free_subjects(int n, u_int8_t **id, u_int32_t *len) { int i; for (i = 0; i < n; i++) free(id[i]); free(id); free(len); } isakmpd-20041012.orig/ipsec.c0000644000175000017500000017450310133045740016036 0ustar jdivejdive00000000000000/* $OpenBSD: ipsec.c,v 1.104 2004/09/17 13:53:08 ho Exp $ */ /* $EOM: ipsec.c,v 1.143 2000/12/11 23:57:42 niklas Exp $ */ /* * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2001 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2001 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include #include "sysdep.h" #include "attribute.h" #include "conf.h" #include "constants.h" #include "crypto.h" #include "dh.h" #include "doi.h" #if defined (USE_DPD) #include "dpd.h" #endif #include "exchange.h" #include "hash.h" #include "ike_aggressive.h" #include "ike_auth.h" #include "ike_main_mode.h" #include "ike_quick_mode.h" #include "ipsec.h" #include "ipsec_doi.h" #include "isakmp.h" #include "isakmp_cfg.h" #include "isakmp_fld.h" #include "isakmp_num.h" #include "log.h" #include "math_group.h" #include "message.h" #if defined (USE_NAT_TRAVERSAL) #include "nat_traversal.h" #endif #include "prf.h" #include "sa.h" #include "timer.h" #include "transport.h" #include "util.h" #ifdef USE_X509 #include "x509.h" #endif extern int acquire_only; /* Backwards compatibility. */ #ifndef NI_MAXHOST #define NI_MAXHOST 1025 #endif /* The replay window size used for all IPsec protocols if not overridden. */ #define DEFAULT_REPLAY_WINDOW 16 struct ipsec_decode_arg { struct message *msg; struct sa *sa; struct proto *proto; }; /* These variables hold the contacted peers ADT state. */ struct contact { struct sockaddr *addr; socklen_t len; } *contacts = 0; int contact_cnt = 0, contact_limit = 0; static int addr_cmp(const void *, const void *); static int ipsec_add_contact(struct message *); static int ipsec_contacted(struct message *); #ifdef USE_DEBUG static int ipsec_debug_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); #endif static void ipsec_delete_spi(struct sa *, struct proto *, int); static int16_t *ipsec_exchange_script(u_int8_t); static void ipsec_finalize_exchange(struct message *); static void ipsec_free_exchange_data(void *); static void ipsec_free_proto_data(void *); static void ipsec_free_sa_data(void *); static struct keystate *ipsec_get_keystate(struct message *); static u_int8_t *ipsec_get_spi(size_t *, u_int8_t, struct message *); static int ipsec_handle_leftover_payload(struct message *, u_int8_t, struct payload *); static int ipsec_informational_post_hook(struct message *); static int ipsec_informational_pre_hook(struct message *); static int ipsec_initiator(struct message *); static void ipsec_proto_init(struct proto *, char *); static int ipsec_responder(struct message *); static void ipsec_setup_situation(u_int8_t *); static int ipsec_set_network(u_int8_t *, u_int8_t *, struct ipsec_sa *); static size_t ipsec_situation_size(void); static u_int8_t ipsec_spi_size(u_int8_t); static int ipsec_validate_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); static int ipsec_validate_exchange(u_int8_t); static int ipsec_validate_id_information(u_int8_t, u_int8_t *, u_int8_t *, size_t, struct exchange *); static int ipsec_validate_key_information(u_int8_t *, size_t); static int ipsec_validate_notification(u_int16_t); static int ipsec_validate_proto(u_int8_t); static int ipsec_validate_situation(u_int8_t *, size_t *, size_t); static int ipsec_validate_transform_id(u_int8_t, u_int8_t); static struct doi ipsec_doi = { {0}, IPSEC_DOI_IPSEC, sizeof(struct ipsec_exch), sizeof(struct ipsec_sa), sizeof(struct ipsec_proto), #ifdef USE_DEBUG ipsec_debug_attribute, #endif ipsec_delete_spi, ipsec_exchange_script, ipsec_finalize_exchange, ipsec_free_exchange_data, ipsec_free_proto_data, ipsec_free_sa_data, ipsec_get_keystate, ipsec_get_spi, ipsec_handle_leftover_payload, ipsec_informational_post_hook, ipsec_informational_pre_hook, ipsec_is_attribute_incompatible, ipsec_proto_init, ipsec_setup_situation, ipsec_situation_size, ipsec_spi_size, ipsec_validate_attribute, ipsec_validate_exchange, ipsec_validate_id_information, ipsec_validate_key_information, ipsec_validate_notification, ipsec_validate_proto, ipsec_validate_situation, ipsec_validate_transform_id, ipsec_initiator, ipsec_responder, ipsec_decode_ids }; int16_t script_quick_mode[] = { ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */ ISAKMP_PAYLOAD_SA, ISAKMP_PAYLOAD_NONCE, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_HASH, /* Responder -> initiator. */ ISAKMP_PAYLOAD_SA, ISAKMP_PAYLOAD_NONCE, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */ EXCHANGE_SCRIPT_END }; int16_t script_new_group_mode[] = { ISAKMP_PAYLOAD_HASH, /* Initiator -> responder. */ ISAKMP_PAYLOAD_SA, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_HASH, /* Responder -> initiator. */ ISAKMP_PAYLOAD_SA, EXCHANGE_SCRIPT_END }; struct dst_spi_proto_arg { struct sockaddr *dst; u_int32_t spi; u_int8_t proto; }; /* * Check if SA matches what we are asking for through V_ARG. It has to * be a finished phase 2 SA. * if "proto" arg is 0, match any proto */ static int ipsec_sa_check(struct sa *sa, void *v_arg) { struct dst_spi_proto_arg *arg = v_arg; struct proto *proto; struct sockaddr *dst, *src; int incoming; if (sa->phase != 2 || !(sa->flags & SA_FLAG_READY)) return 0; sa->transport->vtbl->get_dst(sa->transport, &dst); if (memcmp(sockaddr_addrdata(dst), sockaddr_addrdata(arg->dst), sockaddr_addrlen(dst)) == 0) incoming = 0; else { sa->transport->vtbl->get_src(sa->transport, &src); if (memcmp(sockaddr_addrdata(src), sockaddr_addrdata(arg->dst), sockaddr_addrlen(src)) == 0) incoming = 1; else return 0; } for (proto = TAILQ_FIRST(&sa->protos); proto; proto = TAILQ_NEXT(proto, link)) if ((arg->proto == 0 || proto->proto == arg->proto) && memcmp(proto->spi[incoming], &arg->spi, sizeof arg->spi) == 0) return 1; return 0; } /* Find an SA with a "name" of DST, SPI & PROTO. */ struct sa * ipsec_sa_lookup(struct sockaddr *dst, u_int32_t spi, u_int8_t proto) { struct dst_spi_proto_arg arg; arg.dst = dst; arg.spi = spi; arg.proto = proto; return sa_find(ipsec_sa_check, &arg); } /* * Check if SA matches the flow of another SA in V_ARG. It has to * be a finished non-replaced phase 2 SA. * XXX At some point other selectors will matter here too. */ static int ipsec_sa_check_flow(struct sa *sa, void *v_arg) { struct sa *sa2 = v_arg; struct ipsec_sa *isa = sa->data, *isa2 = sa2->data; if (sa == sa2 || sa->phase != 2 || (sa->flags & (SA_FLAG_READY | SA_FLAG_REPLACED)) != SA_FLAG_READY) return 0; if (isa->tproto != isa2->tproto || isa->sport != isa2->sport || isa->dport != isa2->dport) return 0; return isa->src_net->sa_family == isa2->src_net->sa_family && memcmp(sockaddr_addrdata(isa->src_net), sockaddr_addrdata(isa2->src_net), sockaddr_addrlen(isa->src_net)) == 0 && memcmp(sockaddr_addrdata(isa->src_mask), sockaddr_addrdata(isa2->src_mask), sockaddr_addrlen(isa->src_mask)) == 0 && memcmp(sockaddr_addrdata(isa->dst_net), sockaddr_addrdata(isa2->dst_net), sockaddr_addrlen(isa->dst_net)) == 0 && memcmp(sockaddr_addrdata(isa->dst_mask), sockaddr_addrdata(isa2->dst_mask), sockaddr_addrlen(isa->dst_mask)) == 0; } /* * Do IPsec DOI specific finalizations task for the exchange where MSG was * the final message. */ static void ipsec_finalize_exchange(struct message *msg) { struct sa *isakmp_sa = msg->isakmp_sa; struct ipsec_sa *isa; struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct sa *sa = 0, *old_sa; struct proto *proto, *last_proto = 0; #ifdef USE_DEBUG char *addr1, *addr2, *mask1, *mask2; #endif switch (exchange->phase) { case 1: switch (exchange->type) { case ISAKMP_EXCH_ID_PROT: case ISAKMP_EXCH_AGGRESSIVE: isa = isakmp_sa->data; isa->hash = ie->hash->type; isa->prf_type = ie->prf_type; isa->skeyid_len = ie->skeyid_len; isa->skeyid_d = ie->skeyid_d; isa->skeyid_a = ie->skeyid_a; /* Prevents early free of SKEYID_*. */ ie->skeyid_a = ie->skeyid_d = 0; /* * If a lifetime was negotiated setup the expiration * timers. */ if (isakmp_sa->seconds) sa_setup_expirations(isakmp_sa); #if defined (USE_NAT_TRAVERSAL) if (isakmp_sa->flags & SA_FLAG_NAT_T_KEEPALIVE) nat_t_setup_keepalive(isakmp_sa); #endif break; } break; case 2: switch (exchange->type) { case IKE_EXCH_QUICK_MODE: /* * Tell the application(s) about the SPIs and key * material. */ for (sa = TAILQ_FIRST(&exchange->sa_list); sa; sa = TAILQ_NEXT(sa, next)) { isa = sa->data; if (exchange->initiator) { /* * Initiator is source, responder is * destination. */ if (ipsec_set_network(ie->id_ci, ie->id_cr, isa)) { log_print( "ipsec_finalize_exchange: " "ipsec_set_network " "failed"); return; } } else { /* * Responder is source, initiator is * destination. */ if (ipsec_set_network(ie->id_cr, ie->id_ci, isa)) { log_print( "ipsec_finalize_exchange: " "ipsec_set_network " "failed"); return; } } for (proto = TAILQ_FIRST(&sa->protos), last_proto = 0; proto; proto = TAILQ_NEXT(proto, link)) { if (sysdep_ipsec_set_spi(sa, proto, 0, isakmp_sa) || (last_proto && sysdep_ipsec_group_spis(sa, last_proto, proto, 0)) || sysdep_ipsec_set_spi(sa, proto, 1, isakmp_sa) || (last_proto && sysdep_ipsec_group_spis(sa, last_proto, proto, 1))) /* * XXX Tear down this * exchange. */ return; last_proto = proto; } #ifdef USE_DEBUG if (sockaddr2text(isa->src_net, &addr1, 0)) addr1 = 0; if (sockaddr2text(isa->src_mask, &mask1, 0)) mask1 = 0; if (sockaddr2text(isa->dst_net, &addr2, 0)) addr2 = 0; if (sockaddr2text(isa->dst_mask, &mask2, 0)) mask2 = 0; LOG_DBG((LOG_EXCHANGE, 50, "ipsec_finalize_exchange: src %s %s " "dst %s %s tproto %u sport %u dport %u", addr1 ? addr1 : "", mask1 ? mask1 : "", addr2 ? addr2 : "", mask2 ? mask2 : "", isa->tproto, ntohs(isa->sport), ntohs(isa->dport))); if (addr1) free(addr1); if (mask1) free(mask1); if (addr2) free(addr2); if (mask2) free(mask2); #endif /* USE_DEBUG */ /* * If this is not an SA acquired by the * kernel, it needs to have a SPD entry * (a.k.a. flow) set up. */ if (!(sa->flags & SA_FLAG_ONDEMAND || conf_get_str("General", "Acquire-Only") || acquire_only) && sysdep_ipsec_enable_sa(sa, isakmp_sa)) /* XXX Tear down this exchange. */ return; /* * Mark elder SAs with the same flow * information as replaced. */ while ((old_sa = sa_find(ipsec_sa_check_flow, sa)) != 0) sa_mark_replaced(old_sa); } break; } } } /* Set the client addresses in ISA from SRC_ID and DST_ID. */ static int ipsec_set_network(u_int8_t *src_id, u_int8_t *dst_id, struct ipsec_sa *isa) { int id; /* Set source address/mask. */ id = GET_ISAKMP_ID_TYPE(src_id); switch (id) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV4_ADDR_SUBNET: isa->src_net = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in)); if (!isa->src_net) goto memfail; isa->src_net->sa_family = AF_INET; #ifndef USE_OLD_SOCKADDR isa->src_net->sa_len = sizeof(struct sockaddr_in); #endif isa->src_mask = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in)); if (!isa->src_mask) goto memfail; isa->src_mask->sa_family = AF_INET; #ifndef USE_OLD_SOCKADDR isa->src_mask->sa_len = sizeof(struct sockaddr_in); #endif break; case IPSEC_ID_IPV6_ADDR: case IPSEC_ID_IPV6_ADDR_SUBNET: isa->src_net = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in6)); if (!isa->src_net) goto memfail; isa->src_net->sa_family = AF_INET6; #ifndef USE_OLD_SOCKADDR isa->src_net->sa_len = sizeof(struct sockaddr_in6); #endif isa->src_mask = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in6)); if (!isa->src_mask) goto memfail; isa->src_mask->sa_family = AF_INET6; #ifndef USE_OLD_SOCKADDR isa->src_mask->sa_len = sizeof(struct sockaddr_in6); #endif break; case IPSEC_ID_IPV4_RANGE: case IPSEC_ID_IPV6_RANGE: case IPSEC_ID_DER_ASN1_DN: case IPSEC_ID_DER_ASN1_GN: case IPSEC_ID_KEY_ID: default: log_print("ipsec_set_network: ID type %d (%s) not supported", id, constant_name(ipsec_id_cst, id)); return -1; } /* Net */ memcpy(sockaddr_addrdata(isa->src_net), src_id + ISAKMP_ID_DATA_OFF, sockaddr_addrlen(isa->src_net)); /* Mask */ switch (id) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: memset(sockaddr_addrdata(isa->src_mask), 0xff, sockaddr_addrlen(isa->src_mask)); break; case IPSEC_ID_IPV4_ADDR_SUBNET: case IPSEC_ID_IPV6_ADDR_SUBNET: memcpy(sockaddr_addrdata(isa->src_mask), src_id + ISAKMP_ID_DATA_OFF + sockaddr_addrlen(isa->src_net), sockaddr_addrlen(isa->src_mask)); break; } memcpy(&isa->sport, src_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PORT_OFF, IPSEC_ID_PORT_LEN); /* Set destination address. */ id = GET_ISAKMP_ID_TYPE(dst_id); switch (id) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV4_ADDR_SUBNET: isa->dst_net = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in)); if (!isa->dst_net) goto memfail; isa->dst_net->sa_family = AF_INET; #ifndef USE_OLD_SOCKADDR isa->dst_net->sa_len = sizeof(struct sockaddr_in); #endif isa->dst_mask = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in)); if (!isa->dst_mask) goto memfail; isa->dst_mask->sa_family = AF_INET; #ifndef USE_OLD_SOCKADDR isa->dst_mask->sa_len = sizeof(struct sockaddr_in); #endif break; case IPSEC_ID_IPV6_ADDR: case IPSEC_ID_IPV6_ADDR_SUBNET: isa->dst_net = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in6)); if (!isa->dst_net) goto memfail; isa->dst_net->sa_family = AF_INET6; #ifndef USE_OLD_SOCKADDR isa->dst_net->sa_len = sizeof(struct sockaddr_in6); #endif isa->dst_mask = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in6)); if (!isa->dst_mask) goto memfail; isa->dst_mask->sa_family = AF_INET6; #ifndef USE_OLD_SOCKADDR isa->dst_mask->sa_len = sizeof(struct sockaddr_in6); #endif break; } /* Net */ memcpy(sockaddr_addrdata(isa->dst_net), dst_id + ISAKMP_ID_DATA_OFF, sockaddr_addrlen(isa->dst_net)); /* Mask */ switch (id) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: memset(sockaddr_addrdata(isa->dst_mask), 0xff, sockaddr_addrlen(isa->dst_mask)); break; case IPSEC_ID_IPV4_ADDR_SUBNET: case IPSEC_ID_IPV6_ADDR_SUBNET: memcpy(sockaddr_addrdata(isa->dst_mask), dst_id + ISAKMP_ID_DATA_OFF + sockaddr_addrlen(isa->dst_net), sockaddr_addrlen(isa->dst_mask)); break; } memcpy(&isa->tproto, dst_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PROTO_OFF, IPSEC_ID_PROTO_LEN); memcpy(&isa->dport, dst_id + ISAKMP_ID_DOI_DATA_OFF + IPSEC_ID_PORT_OFF, IPSEC_ID_PORT_LEN); return 0; memfail: log_error("ipsec_set_network: calloc () failed"); return -1; } /* Free the DOI-specific exchange data pointed to by VIE. */ static void ipsec_free_exchange_data(void *vie) { struct ipsec_exch *ie = vie; #ifdef USE_ISAKMP_CFG struct isakmp_cfg_attr *attr; #endif if (ie->sa_i_b) free(ie->sa_i_b); if (ie->id_ci) free(ie->id_ci); if (ie->id_cr) free(ie->id_cr); if (ie->g_xi) free(ie->g_xi); if (ie->g_xr) free(ie->g_xr); if (ie->g_xy) free(ie->g_xy); if (ie->skeyid) free(ie->skeyid); if (ie->skeyid_d) free(ie->skeyid_d); if (ie->skeyid_a) free(ie->skeyid_a); if (ie->skeyid_e) free(ie->skeyid_e); if (ie->hash_i) free(ie->hash_i); if (ie->hash_r) free(ie->hash_r); if (ie->group) group_free(ie->group); #ifdef USE_ISAKMP_CFG for (attr = LIST_FIRST(&ie->attrs); attr; attr = LIST_FIRST(&ie->attrs)) { LIST_REMOVE(attr, link); if (attr->length) free(attr->value); free(attr); } #endif } /* Free the DOI-specific SA data pointed to by VISA. */ static void ipsec_free_sa_data(void *visa) { struct ipsec_sa *isa = visa; if (isa->src_net) free(isa->src_net); if (isa->src_mask) free(isa->src_mask); if (isa->dst_net) free(isa->dst_net); if (isa->dst_mask) free(isa->dst_mask); if (isa->skeyid_a) free(isa->skeyid_a); if (isa->skeyid_d) free(isa->skeyid_d); } /* Free the DOI-specific protocol data of an SA pointed to by VIPROTO. */ static void ipsec_free_proto_data(void *viproto) { struct ipsec_proto *iproto = viproto; int i; for (i = 0; i < 2; i++) if (iproto->keymat[i]) free(iproto->keymat[i]); } /* Return exchange script based on TYPE. */ static int16_t * ipsec_exchange_script(u_int8_t type) { switch (type) { #ifdef USE_ISAKMP_CFG case ISAKMP_EXCH_TRANSACTION: return script_transaction; #endif case IKE_EXCH_QUICK_MODE: return script_quick_mode; case IKE_EXCH_NEW_GROUP_MODE: return script_new_group_mode; } return 0; } /* Initialize this DOI, requires doi_init to already have been called. */ void ipsec_init(void) { doi_register(&ipsec_doi); } /* Given a message MSG, return a suitable IV (or rather keystate). */ static struct keystate * ipsec_get_keystate(struct message *msg) { struct keystate *ks; struct hash *hash; /* If we have already have an IV, use it. */ if (msg->exchange && msg->exchange->keystate) { ks = malloc(sizeof *ks); if (!ks) { log_error("ipsec_get_keystate: malloc (%lu) failed", (unsigned long) sizeof *ks); return 0; } memcpy(ks, msg->exchange->keystate, sizeof *ks); return ks; } /* * For phase 2 when no SA yet is setup we need to hash the IV used by * the ISAKMP SA concatenated with the message ID, and use that as an * IV for further cryptographic operations. */ if (!msg->isakmp_sa->keystate) { log_print("ipsec_get_keystate: no keystate in ISAKMP SA %p", msg->isakmp_sa); return 0; } ks = crypto_clone_keystate(msg->isakmp_sa->keystate); if (!ks) return 0; hash = hash_get(((struct ipsec_sa *)msg->isakmp_sa->data)->hash); hash->Init(hash->ctx); LOG_DBG_BUF((LOG_CRYPTO, 80, "ipsec_get_keystate: final phase 1 IV", ks->riv, ks->xf->blocksize)); hash->Update(hash->ctx, ks->riv, ks->xf->blocksize); LOG_DBG_BUF((LOG_CRYPTO, 80, "ipsec_get_keystate: message ID", ((u_int8_t *) msg->iov[0].iov_base) + ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN)); hash->Update(hash->ctx, ((u_int8_t *) msg->iov[0].iov_base) + ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN); hash->Final(hash->digest, hash->ctx); crypto_init_iv(ks, hash->digest, ks->xf->blocksize); LOG_DBG_BUF((LOG_CRYPTO, 80, "ipsec_get_keystate: phase 2 IV", hash->digest, ks->xf->blocksize)); return ks; } static void ipsec_setup_situation(u_int8_t *buf) { SET_IPSEC_SIT_SIT(buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY); } static size_t ipsec_situation_size(void) { return IPSEC_SIT_SIT_LEN; } static u_int8_t ipsec_spi_size(u_int8_t proto) { return IPSEC_SPI_SIZE; } static int ipsec_validate_attribute(u_int16_t type, u_int8_t * value, u_int16_t len, void *vmsg) { struct message *msg = vmsg; if ((msg->exchange->phase == 1 && (type < IKE_ATTR_ENCRYPTION_ALGORITHM || type > IKE_ATTR_GROUP_ORDER)) || (msg->exchange->phase == 2 && (type < IPSEC_ATTR_SA_LIFE_TYPE || type > IPSEC_ATTR_ECN_TUNNEL))) return -1; return 0; } static int ipsec_validate_exchange(u_int8_t exch) { return exch != IKE_EXCH_QUICK_MODE && exch != IKE_EXCH_NEW_GROUP_MODE; } static int ipsec_validate_id_information(u_int8_t type, u_int8_t *extra, u_int8_t *buf, size_t sz, struct exchange *exchange) { u_int8_t proto = GET_IPSEC_ID_PROTO(extra); u_int16_t port = GET_IPSEC_ID_PORT(extra); LOG_DBG((LOG_MESSAGE, 40, "ipsec_validate_id_information: proto %d port %d type %d", proto, port, type)); if (type < IPSEC_ID_IPV4_ADDR || type > IPSEC_ID_KEY_ID) return -1; switch (type) { case IPSEC_ID_IPV4_ADDR: LOG_DBG_BUF((LOG_MESSAGE, 40, "ipsec_validate_id_information: IPv4", buf, sizeof(struct in_addr))); break; case IPSEC_ID_IPV6_ADDR: LOG_DBG_BUF((LOG_MESSAGE, 40, "ipsec_validate_id_information: IPv6", buf, sizeof(struct in6_addr))); break; case IPSEC_ID_IPV4_ADDR_SUBNET: LOG_DBG_BUF((LOG_MESSAGE, 40, "ipsec_validate_id_information: IPv4 network/netmask", buf, 2 * sizeof(struct in_addr))); break; case IPSEC_ID_IPV6_ADDR_SUBNET: LOG_DBG_BUF((LOG_MESSAGE, 40, "ipsec_validate_id_information: IPv6 network/netmask", buf, 2 * sizeof(struct in6_addr))); break; default: break; } if (exchange->phase == 1 && (proto != IPPROTO_UDP || port != UDP_DEFAULT_PORT) && (proto != 0 || port != 0)) { /* * XXX SSH's ISAKMP tester fails this test (proto 17 - port * 0). */ #ifdef notyet return -1; #else log_print("ipsec_validate_id_information: dubious ID " "information accepted"); #endif } /* XXX More checks? */ return 0; } static int ipsec_validate_key_information(u_int8_t *buf, size_t sz) { /* XXX Not implemented yet. */ return 0; } static int ipsec_validate_notification(u_int16_t type) { return type < IPSEC_NOTIFY_RESPONDER_LIFETIME || type > IPSEC_NOTIFY_INITIAL_CONTACT ? -1 : 0; } static int ipsec_validate_proto(u_int8_t proto) { return proto < IPSEC_PROTO_IPSEC_AH || proto > IPSEC_PROTO_IPCOMP ? -1 : 0; } static int ipsec_validate_situation(u_int8_t *buf, size_t *sz, size_t len) { if (len < IPSEC_SIT_SIT_OFF + IPSEC_SIT_SIT_LEN) { log_print("ipsec_validate_situation: payload too short: %u", (unsigned int) len); return -1; } /* Currently only "identity only" situations are supported. */ if (GET_IPSEC_SIT_SIT(buf) != IPSEC_SIT_IDENTITY_ONLY) return 1; *sz = IPSEC_SIT_SIT_LEN; return 0; } static int ipsec_validate_transform_id(u_int8_t proto, u_int8_t transform_id) { switch (proto) { /* * As no unexpected protocols can occur, we just tie the * default case to the first case, in orer to silence a GCC * warning. */ default: case ISAKMP_PROTO_ISAKMP: return transform_id != IPSEC_TRANSFORM_KEY_IKE; case IPSEC_PROTO_IPSEC_AH: return transform_id < IPSEC_AH_MD5 || transform_id > IPSEC_AH_DES ? -1 : 0; case IPSEC_PROTO_IPSEC_ESP: return transform_id < IPSEC_ESP_DES_IV64 || (transform_id > IPSEC_ESP_AES_128_CTR && transform_id < IPSEC_ESP_AES_MARS) || transform_id > IPSEC_ESP_AES_TWOFISH ? -1 : 0; case IPSEC_PROTO_IPCOMP: return transform_id < IPSEC_IPCOMP_OUI || transform_id > IPSEC_IPCOMP_V42BIS ? -1 : 0; } } static int ipsec_initiator(struct message *msg) { struct exchange *exchange = msg->exchange; int (**script)(struct message *) = 0; /* Check that the SA is coherent with the IKE rules. */ if (exchange->type != ISAKMP_EXCH_TRANSACTION && ((exchange->phase == 1 && exchange->type != ISAKMP_EXCH_ID_PROT && exchange->type != ISAKMP_EXCH_AGGRESSIVE && exchange->type != ISAKMP_EXCH_INFO) || (exchange->phase == 2 && exchange->type != IKE_EXCH_QUICK_MODE && exchange->type != ISAKMP_EXCH_INFO))) { log_print("ipsec_initiator: unsupported exchange type %d " "in phase %d", exchange->type, exchange->phase); return -1; } switch (exchange->type) { case ISAKMP_EXCH_ID_PROT: script = ike_main_mode_initiator; break; #ifdef USE_AGGRESSIVE case ISAKMP_EXCH_AGGRESSIVE: script = ike_aggressive_initiator; break; #endif #ifdef USE_ISAKMP_CFG case ISAKMP_EXCH_TRANSACTION: script = isakmp_cfg_initiator; break; #endif case ISAKMP_EXCH_INFO: return message_send_info(msg); case IKE_EXCH_QUICK_MODE: script = ike_quick_mode_initiator; break; default: log_print("ipsec_initiator: unsupported exchange type %d", exchange->type); return -1; } /* Run the script code for this step. */ if (script) return script[exchange->step] (msg); return 0; } /* * delete all SA's from addr with the associated proto and SPI's * * spis[] is an array of SPIs of size 16-octet for proto ISAKMP * or 4-octet otherwise. */ static void ipsec_delete_spi_list(struct sockaddr *addr, u_int8_t proto, u_int8_t *spis, int nspis, char *type) { struct sa *sa; int i; for (i = 0; i < nspis; i++) { if (proto == ISAKMP_PROTO_ISAKMP) { u_int8_t *spi = spis + i * ISAKMP_HDR_COOKIES_LEN; /* * This really shouldn't happen in IPSEC DOI * code, but Cisco VPN 3000 sends ISAKMP DELETE's * this way. */ sa = sa_lookup_isakmp_sa(addr, spi); } else { u_int32_t spi = ((u_int32_t *)spis)[i]; sa = ipsec_sa_lookup(addr, spi, proto); } if (sa == NULL) { LOG_DBG((LOG_SA, 30, "ipsec_delete_spi_list: could " "not locate SA (SPI %08x, proto %u)", ((u_int32_t *)spis)[i], proto)); continue; } /* Delete the SA and search for the next */ LOG_DBG((LOG_SA, 30, "ipsec_delete_spi_list: " "%s made us delete SA %p (%d references) for proto %d", type, sa, sa->refcnt, proto)); sa_free(sa); } } static int ipsec_responder(struct message *msg) { struct exchange *exchange = msg->exchange; int (**script)(struct message *) = 0; struct payload *p; u_int16_t type; /* Check that a new exchange is coherent with the IKE rules. */ if (exchange->step == 0 && exchange->type != ISAKMP_EXCH_TRANSACTION && ((exchange->phase == 1 && exchange->type != ISAKMP_EXCH_ID_PROT && exchange->type != ISAKMP_EXCH_AGGRESSIVE && exchange->type != ISAKMP_EXCH_INFO) || (exchange->phase == 2 && exchange->type != IKE_EXCH_QUICK_MODE && exchange->type != ISAKMP_EXCH_INFO))) { message_drop(msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE, 0, 1, 0); return -1; } LOG_DBG((LOG_MISC, 30, "ipsec_responder: phase %d exchange %d step %d", exchange->phase, exchange->type, exchange->step)); switch (exchange->type) { case ISAKMP_EXCH_ID_PROT: script = ike_main_mode_responder; break; #ifdef USE_AGGRESSIVE case ISAKMP_EXCH_AGGRESSIVE: script = ike_aggressive_responder; break; #endif #ifdef USE_ISAKMP_CFG case ISAKMP_EXCH_TRANSACTION: script = isakmp_cfg_responder; break; #endif case ISAKMP_EXCH_INFO: for (p = payload_first(msg, ISAKMP_PAYLOAD_NOTIFY); p; p = TAILQ_NEXT(p, link)) { type = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p); LOG_DBG((LOG_EXCHANGE, 10, "ipsec_responder: got NOTIFY of type %s", constant_name(isakmp_notify_cst, type))); switch (type) { case IPSEC_NOTIFY_INITIAL_CONTACT: /* Handled by leftover logic. */ break; #if defined (USE_DPD) case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE: case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK: dpd_handle_notify(msg, p); break; #endif default: p->flags |= PL_MARK; break; } } /* * If any DELETEs are in here, let the logic of leftover * payloads deal with them. */ return 0; case IKE_EXCH_QUICK_MODE: script = ike_quick_mode_responder; break; default: message_drop(msg, ISAKMP_NOTIFY_UNSUPPORTED_EXCHANGE_TYPE, 0, 1, 0); return -1; } /* Run the script code for this step. */ if (script) return script[exchange->step] (msg); /* * XXX So far we don't accept any proposals for exchanges we don't * support. */ if (payload_first(msg, ISAKMP_PAYLOAD_SA)) { message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); return -1; } return 0; } static enum hashes from_ike_hash(u_int16_t hash) { switch (hash) { case IKE_HASH_MD5: return HASH_MD5; case IKE_HASH_SHA: return HASH_SHA1; } return -1; } static enum transform from_ike_crypto(u_int16_t crypto) { /* Coincidentally this is the null operation :-) */ return crypto; } /* * Find out whether the attribute of type TYPE with a LEN length value * pointed to by VALUE is incompatible with what we can handle. * VMSG is a pointer to the current message. */ int ipsec_is_attribute_incompatible(u_int16_t type, u_int8_t *value, u_int16_t len, void *vmsg) { struct message *msg = vmsg; u_int16_t dv = decode_16(value); if (msg->exchange->phase == 1) { switch (type) { case IKE_ATTR_ENCRYPTION_ALGORITHM: return !crypto_get(from_ike_crypto(dv)); case IKE_ATTR_HASH_ALGORITHM: return !hash_get(from_ike_hash(dv)); case IKE_ATTR_AUTHENTICATION_METHOD: return !ike_auth_get(dv); case IKE_ATTR_GROUP_DESCRIPTION: return (dv < IKE_GROUP_DESC_MODP_768 || dv > IKE_GROUP_DESC_MODP_1536) && (dv < IKE_GROUP_DESC_MODP_2048 || dv > IKE_GROUP_DESC_MODP_8192); case IKE_ATTR_GROUP_TYPE: return 1; case IKE_ATTR_GROUP_PRIME: return 1; case IKE_ATTR_GROUP_GENERATOR_1: return 1; case IKE_ATTR_GROUP_GENERATOR_2: return 1; case IKE_ATTR_GROUP_CURVE_A: return 1; case IKE_ATTR_GROUP_CURVE_B: return 1; case IKE_ATTR_LIFE_TYPE: return dv < IKE_DURATION_SECONDS || dv > IKE_DURATION_KILOBYTES; case IKE_ATTR_LIFE_DURATION: return len != 2 && len != 4; case IKE_ATTR_PRF: return 1; case IKE_ATTR_KEY_LENGTH: /* * Our crypto routines only allows key-lengths which * are multiples of an octet. */ return dv % 8 != 0; case IKE_ATTR_FIELD_SIZE: return 1; case IKE_ATTR_GROUP_ORDER: return 1; } } else { switch (type) { case IPSEC_ATTR_SA_LIFE_TYPE: return dv < IPSEC_DURATION_SECONDS || dv > IPSEC_DURATION_KILOBYTES; case IPSEC_ATTR_SA_LIFE_DURATION: return len != 2 && len != 4; case IPSEC_ATTR_GROUP_DESCRIPTION: return (dv < IKE_GROUP_DESC_MODP_768 || dv > IKE_GROUP_DESC_MODP_1536) && (dv < IKE_GROUP_DESC_MODP_2048 || IKE_GROUP_DESC_MODP_8192 < dv); case IPSEC_ATTR_ENCAPSULATION_MODE: #if defined (USE_NAT_TRAVERSAL) return dv != IPSEC_ENCAP_TUNNEL && dv != IPSEC_ENCAP_TRANSPORT && dv != IPSEC_ENCAP_UDP_ENCAP_TUNNEL && dv != IPSEC_ENCAP_UDP_ENCAP_TRANSPORT; #else return dv < IPSEC_ENCAP_TUNNEL || dv > IPSEC_ENCAP_TRANSPORT; #endif /* USE_NAT_TRAVERSAL */ case IPSEC_ATTR_AUTHENTICATION_ALGORITHM: return dv < IPSEC_AUTH_HMAC_MD5 || dv > IPSEC_AUTH_HMAC_RIPEMD; case IPSEC_ATTR_KEY_LENGTH: /* * XXX Blowfish needs '0'. Others appear to disregard * this attr? */ return 0; case IPSEC_ATTR_KEY_ROUNDS: return 1; case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE: return 1; case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM: return 1; case IPSEC_ATTR_ECN_TUNNEL: return 1; } } /* XXX Silence gcc. */ return 1; } #ifdef USE_DEBUG /* * Log the attribute of TYPE with a LEN length value pointed to by VALUE * in human-readable form. VMSG is a pointer to the current message. */ int ipsec_debug_attribute(u_int16_t type, u_int8_t *value, u_int16_t len, void *vmsg) { struct message *msg = vmsg; char val[20]; /* XXX Transient solution. */ if (len == 2) snprintf(val, sizeof val, "%d", decode_16(value)); else if (len == 4) snprintf(val, sizeof val, "%d", decode_32(value)); else snprintf(val, sizeof val, "unrepresentable"); LOG_DBG((LOG_MESSAGE, 50, "Attribute %s value %s", constant_name(msg->exchange->phase == 1 ? ike_attr_cst : ipsec_attr_cst, type), val)); return 0; } #endif /* * Decode the attribute of type TYPE with a LEN length value pointed to by * VALUE. VIDA is a pointer to a context structure where we can find the * current message, SA and protocol. */ int ipsec_decode_attribute(u_int16_t type, u_int8_t *value, u_int16_t len, void *vida) { struct ipsec_decode_arg *ida = vida; struct message *msg = ida->msg; struct sa *sa = ida->sa; struct ipsec_sa *isa = sa->data; struct proto *proto = ida->proto; struct ipsec_proto *iproto = proto->data; struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; static int lifetype = 0; if (exchange->phase == 1) { switch (type) { case IKE_ATTR_ENCRYPTION_ALGORITHM: /* XXX Errors possible? */ exchange->crypto = crypto_get(from_ike_crypto( decode_16(value))); break; case IKE_ATTR_HASH_ALGORITHM: /* XXX Errors possible? */ ie->hash = hash_get(from_ike_hash(decode_16(value))); break; case IKE_ATTR_AUTHENTICATION_METHOD: /* XXX Errors possible? */ ie->ike_auth = ike_auth_get(decode_16(value)); break; case IKE_ATTR_GROUP_DESCRIPTION: isa->group_desc = decode_16(value); break; case IKE_ATTR_GROUP_TYPE: break; case IKE_ATTR_GROUP_PRIME: break; case IKE_ATTR_GROUP_GENERATOR_1: break; case IKE_ATTR_GROUP_GENERATOR_2: break; case IKE_ATTR_GROUP_CURVE_A: break; case IKE_ATTR_GROUP_CURVE_B: break; case IKE_ATTR_LIFE_TYPE: lifetype = decode_16(value); return 0; case IKE_ATTR_LIFE_DURATION: switch (lifetype) { case IKE_DURATION_SECONDS: switch (len) { case 2: sa->seconds = decode_16(value); break; case 4: sa->seconds = decode_32(value); break; default: log_print("ipsec_decode_attribute: " "unreasonable lifetime"); } break; case IKE_DURATION_KILOBYTES: switch (len) { case 2: sa->kilobytes = decode_16(value); break; case 4: sa->kilobytes = decode_32(value); break; default: log_print("ipsec_decode_attribute: " "unreasonable lifetime"); } break; default: log_print("ipsec_decode_attribute: unknown " "lifetime type"); } break; case IKE_ATTR_PRF: break; case IKE_ATTR_KEY_LENGTH: exchange->key_length = decode_16(value) / 8; break; case IKE_ATTR_FIELD_SIZE: break; case IKE_ATTR_GROUP_ORDER: break; } } else { switch (type) { case IPSEC_ATTR_SA_LIFE_TYPE: lifetype = decode_16(value); return 0; case IPSEC_ATTR_SA_LIFE_DURATION: switch (lifetype) { case IPSEC_DURATION_SECONDS: switch (len) { case 2: sa->seconds = decode_16(value); break; case 4: sa->seconds = decode_32(value); break; default: log_print("ipsec_decode_attribute: " "unreasonable lifetime"); } break; case IPSEC_DURATION_KILOBYTES: switch (len) { case 2: sa->kilobytes = decode_16(value); break; case 4: sa->kilobytes = decode_32(value); break; default: log_print("ipsec_decode_attribute: " "unreasonable lifetime"); } break; default: log_print("ipsec_decode_attribute: unknown " "lifetime type"); } break; case IPSEC_ATTR_GROUP_DESCRIPTION: isa->group_desc = decode_16(value); break; case IPSEC_ATTR_ENCAPSULATION_MODE: /* * XXX Multiple protocols must have same * encapsulation mode, no? */ iproto->encap_mode = decode_16(value); break; case IPSEC_ATTR_AUTHENTICATION_ALGORITHM: iproto->auth = decode_16(value); break; case IPSEC_ATTR_KEY_LENGTH: iproto->keylen = decode_16(value); break; case IPSEC_ATTR_KEY_ROUNDS: iproto->keyrounds = decode_16(value); break; case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE: break; case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM: break; case IPSEC_ATTR_ECN_TUNNEL: break; } } lifetype = 0; return 0; } /* * Walk over the attributes of the transform payload found in BUF, and * fill out the fields of the SA attached to MSG. Also mark the SA as * processed. */ void ipsec_decode_transform(struct message *msg, struct sa *sa, struct proto *proto, u_int8_t *buf) { struct ipsec_exch *ie = msg->exchange->data; struct ipsec_decode_arg ida; LOG_DBG((LOG_MISC, 20, "ipsec_decode_transform: transform %d chosen", GET_ISAKMP_TRANSFORM_NO(buf))); ida.msg = msg; ida.sa = sa; ida.proto = proto; /* The default IKE lifetime is 8 hours. */ if (sa->phase == 1) sa->seconds = 28800; /* Extract the attributes and stuff them into the SA. */ attribute_map(buf + ISAKMP_TRANSFORM_SA_ATTRS_OFF, GET_ISAKMP_GEN_LENGTH(buf) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, ipsec_decode_attribute, &ida); /* * If no pseudo-random function was negotiated, it's HMAC. * XXX As PRF_HMAC currently is zero, this is a no-op. */ if (!ie->prf_type) ie->prf_type = PRF_HMAC; } /* * Delete the IPsec SA represented by the INCOMING direction in protocol PROTO * of the IKE security association SA. */ static void ipsec_delete_spi(struct sa *sa, struct proto *proto, int incoming) { if (sa->phase == 1) return; /* XXX Error handling? Is it interesting? */ sysdep_ipsec_delete_spi(sa, proto, incoming); } /* * Store BUF into the g^x entry of the exchange that message MSG belongs to. * PEER is non-zero when the value is our peer's, and zero when it is ours. */ static int ipsec_g_x(struct message *msg, int peer, u_int8_t *buf) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; u_int8_t **g_x; int initiator = exchange->initiator ^ peer; char header[32]; g_x = initiator ? &ie->g_xi : &ie->g_xr; *g_x = malloc(ie->g_x_len); if (!*g_x) { log_error("ipsec_g_x: malloc (%lu) failed", (unsigned long)ie->g_x_len); return -1; } memcpy(*g_x, buf, ie->g_x_len); snprintf(header, sizeof header, "ipsec_g_x: g^x%c", initiator ? 'i' : 'r'); LOG_DBG_BUF((LOG_MISC, 80, header, *g_x, ie->g_x_len)); return 0; } /* Generate our DH value. */ int ipsec_gen_g_x(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; u_int8_t *buf; buf = malloc(ISAKMP_KE_SZ + ie->g_x_len); if (!buf) { log_error("ipsec_gen_g_x: malloc (%lu) failed", ISAKMP_KE_SZ + (unsigned long)ie->g_x_len); return -1; } if (message_add_payload(msg, ISAKMP_PAYLOAD_KEY_EXCH, buf, ISAKMP_KE_SZ + ie->g_x_len, 1)) { free(buf); return -1; } if (dh_create_exchange(ie->group, buf + ISAKMP_KE_DATA_OFF)) { log_print("ipsec_gen_g_x: dh_create_exchange failed"); free(buf); return -1; } return ipsec_g_x(msg, 0, buf + ISAKMP_KE_DATA_OFF); } /* Save the peer's DH value. */ int ipsec_save_g_x(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct payload *kep; kep = payload_first(msg, ISAKMP_PAYLOAD_KEY_EXCH); kep->flags |= PL_MARK; ie->g_x_len = GET_ISAKMP_GEN_LENGTH(kep->p) - ISAKMP_KE_DATA_OFF; /* Check that the given length matches the group's expectancy. */ if (ie->g_x_len != (size_t) dh_getlen(ie->group)) { /* XXX Is this a good notify type? */ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } return ipsec_g_x(msg, 1, kep->p + ISAKMP_KE_DATA_OFF); } /* * Get a SPI for PROTO and the transport MSG passed over. Store the * size where SZ points. NB! A zero return is OK if *SZ is zero. */ static u_int8_t * ipsec_get_spi(size_t *sz, u_int8_t proto, struct message *msg) { struct sockaddr *dst, *src; struct transport *transport = msg->transport; if (msg->exchange->phase == 1) { *sz = 0; return 0; } else { /* We are the destination in the SA we want a SPI for. */ transport->vtbl->get_src(transport, &dst); /* The peer is the source. */ transport->vtbl->get_dst(transport, &src); return sysdep_ipsec_get_spi(sz, proto, src, dst, msg->exchange->seq); } } /* * We have gotten a payload PAYLOAD of type TYPE, which did not get handled * by the logic of the exchange MSG takes part in. Now is the time to deal * with such a payload if we know how to, if we don't, return -1, otherwise * 0. */ int ipsec_handle_leftover_payload(struct message *msg, u_int8_t type, struct payload *payload) { u_int32_t spisz, nspis; struct sockaddr *dst; int reenter = 0; u_int8_t *spis, proto; struct sa *sa; switch (type) { case ISAKMP_PAYLOAD_DELETE: proto = GET_ISAKMP_DELETE_PROTO(payload->p); nspis = GET_ISAKMP_DELETE_NSPIS(payload->p); spisz = GET_ISAKMP_DELETE_SPI_SZ(payload->p); if (nspis == 0) { LOG_DBG((LOG_SA, 60, "ipsec_handle_leftover_payload: " "message specified zero SPIs, ignoring")); return -1; } /* verify proper SPI size */ if ((proto == ISAKMP_PROTO_ISAKMP && spisz != ISAKMP_HDR_COOKIES_LEN) || (proto != ISAKMP_PROTO_ISAKMP && spisz != sizeof(u_int32_t))) { log_print("ipsec_handle_leftover_payload: invalid SPI " "size %d for proto %d in DELETE payload", spisz, proto); return -1; } spis = (u_int8_t *) malloc(nspis * spisz); if (!spis) { log_error("ipsec_handle_leftover_payload: malloc " "(%d) failed", nspis * spisz); return -1; } /* extract SPI and get dst address */ memcpy(spis, payload->p + ISAKMP_DELETE_SPI_OFF, nspis * spisz); msg->transport->vtbl->get_dst(msg->transport, &dst); ipsec_delete_spi_list(dst, proto, spis, nspis, "DELETE"); free(spis); payload->flags |= PL_MARK; return 0; case ISAKMP_PAYLOAD_NOTIFY: switch (GET_ISAKMP_NOTIFY_MSG_TYPE(payload->p)) { case IPSEC_NOTIFY_INITIAL_CONTACT: /* * Permit INITIAL-CONTACT if * - this is not an AGGRESSIVE mode exchange * - it is protected by an ISAKMP SA * * XXX Instead of the first condition above, we could * XXX permit this only for phase 2. In the last * XXX packet of main-mode, this payload, while * XXX encrypted, is not part of the hash digest. As * XXX we currently send our own INITIAL-CONTACTs at * XXX this point, this too would need to be changed. */ if (msg->exchange->type == ISAKMP_EXCH_AGGRESSIVE) { log_print("ipsec_handle_leftover_payload: got " "INITIAL-CONTACT in AGGRESSIVE mode"); return -1; } if ((msg->exchange->flags & EXCHANGE_FLAG_ENCRYPT) == 0) { log_print("ipsec_handle_leftover_payload: got " "INITIAL-CONTACT without ISAKMP SA"); return -1; } if ((msg->flags & MSG_AUTHENTICATED) == 0) { log_print("ipsec_handle_leftover_payload: " "got unauthenticated INITIAL-CONTACT"); return -1; } /* * Find out who is sending this and then delete every * SA that is ready. Exchanges will timeout * themselves and then the non-ready SAs will * disappear too. */ msg->transport->vtbl->get_dst(msg->transport, &dst); while ((sa = sa_lookup_by_peer(dst, sysdep_sa_len(dst))) != 0) { /* * Don't delete the current SA -- we received * the notification over it, so it's obviously * still active. We temporarily need to remove * the SA from the list to avoid an endless * loop, but keep a reference so it won't * disappear meanwhile. */ if (sa == msg->isakmp_sa) { sa_reference(sa); sa_remove(sa); reenter = 1; continue; } LOG_DBG((LOG_SA, 30, "ipsec_handle_leftover_payload: " "INITIAL-CONTACT made us delete SA %p", sa)); sa_delete(sa, 0); } if (reenter) { sa_enter(msg->isakmp_sa); sa_release(msg->isakmp_sa); } payload->flags |= PL_MARK; return 0; } } return -1; } /* Return the encryption keylength in octets of the ESP protocol PROTO. */ int ipsec_esp_enckeylength(struct proto *proto) { struct ipsec_proto *iproto = proto->data; /* Compute the keylength to use. */ switch (proto->id) { case IPSEC_ESP_DES: case IPSEC_ESP_DES_IV32: case IPSEC_ESP_DES_IV64: return 8; case IPSEC_ESP_3DES: return 24; case IPSEC_ESP_CAST: if (!iproto->keylen) return 16; return iproto->keylen / 8; case IPSEC_ESP_AES: case IPSEC_ESP_AES_128_CTR: if (!iproto->keylen) return 16; /* Fallthrough */ default: return iproto->keylen / 8; } } /* Return the authentication keylength in octets of the ESP protocol PROTO. */ int ipsec_esp_authkeylength(struct proto *proto) { struct ipsec_proto *iproto = proto->data; switch (iproto->auth) { case IPSEC_AUTH_HMAC_MD5: return 16; case IPSEC_AUTH_HMAC_SHA: case IPSEC_AUTH_HMAC_RIPEMD: return 20; case IPSEC_AUTH_HMAC_SHA2_256: return 32; case IPSEC_AUTH_HMAC_SHA2_384: return 48; case IPSEC_AUTH_HMAC_SHA2_512: return 64; default: return 0; } } /* Return the authentication keylength in octets of the AH protocol PROTO. */ int ipsec_ah_keylength(struct proto *proto) { switch (proto->id) { case IPSEC_AH_MD5: return 16; case IPSEC_AH_SHA: case IPSEC_AH_RIPEMD: return 20; case IPSEC_AH_SHA2_256: return 32; case IPSEC_AH_SHA2_384: return 48; case IPSEC_AH_SHA2_512: return 64; default: return -1; } } /* Return the total keymaterial length of the protocol PROTO. */ int ipsec_keymat_length(struct proto *proto) { switch (proto->proto) { case IPSEC_PROTO_IPSEC_ESP: return ipsec_esp_enckeylength(proto) + ipsec_esp_authkeylength(proto); case IPSEC_PROTO_IPSEC_AH: return ipsec_ah_keylength(proto); default: return -1; } } /* Helper function for ipsec_get_id(). */ static int ipsec_get_proto_port(char *section, u_int8_t *tproto, u_int16_t *port) { struct protoent *pe = NULL; struct servent *se; char *pstr; pstr = conf_get_str(section, "Protocol"); if (!pstr) { *tproto = 0; return 0; } *tproto = (u_int8_t)atoi(pstr); if (!*tproto) { pe = getprotobyname(pstr); if (pe) *tproto = pe->p_proto; } if (!*tproto) { log_print("ipsec_get_proto_port: protocol \"%s\" unknown", pstr); return -1; } pstr = conf_get_str(section, "Port"); if (!pstr) return 0; *port = (u_int16_t)atoi(pstr); if (!*port) { se = getservbyname(pstr, pe ? pe->p_name : (pstr ? pstr : NULL)); if (se) *port = se->s_port; } if (!*port) { log_print("ipsec_get_proto_port: port \"%s\" unknown", pstr); return -1; } return 0; } /* * Out of a named section SECTION in the configuration file find out * the network address and mask as well as the ID type. Put the info * in the areas pointed to by ADDR, MASK, TPROTO, PORT, and ID respectively. * Return 0 on success and -1 on failure. */ int ipsec_get_id(char *section, int *id, struct sockaddr **addr, struct sockaddr **mask, u_int8_t *tproto, u_int16_t *port) { char *type, *address, *netmask; type = conf_get_str(section, "ID-type"); if (!type) { log_print("ipsec_get_id: section %s has no \"ID-type\" tag", section); return -1; } *id = constant_value(ipsec_id_cst, type); switch (*id) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: { int ret; address = conf_get_str(section, "Address"); if (!address) { log_print("ipsec_get_id: section %s has no " "\"Address\" tag", section); return -1; } if (text2sockaddr(address, NULL, addr)) { log_print("ipsec_get_id: invalid address %s in " "section %s", address, section); return -1; } ret = ipsec_get_proto_port(section, tproto, port); if (ret < 0) free(*addr); return ret; } #ifdef notyet case IPSEC_ID_FQDN: return -1; case IPSEC_ID_USER_FQDN: return -1; #endif case IPSEC_ID_IPV4_ADDR_SUBNET: case IPSEC_ID_IPV6_ADDR_SUBNET: { int ret; address = conf_get_str(section, "Network"); if (!address) { log_print("ipsec_get_id: section %s has no " "\"Network\" tag", section); return -1; } if (text2sockaddr(address, NULL, addr)) { log_print("ipsec_get_id: invalid section %s " "network %s", section, address); return -1; } netmask = conf_get_str(section, "Netmask"); if (!netmask) { log_print("ipsec_get_id: section %s has no " "\"Netmask\" tag", section); free(*addr); return -1; } if (text2sockaddr(netmask, NULL, mask)) { log_print("ipsec_id_build: invalid section %s " "network %s", section, netmask); free(*addr); return -1; } ret = ipsec_get_proto_port(section, tproto, port); if (ret < 0) { free(*mask); free(*addr); } return ret; } #ifdef notyet case IPSEC_ID_IPV4_RANGE: return -1; case IPSEC_ID_IPV6_RANGE: return -1; case IPSEC_ID_DER_ASN1_DN: return -1; case IPSEC_ID_DER_ASN1_GN: return -1; case IPSEC_ID_KEY_ID: return -1; #endif default: log_print("ipsec_get_id: unknown ID type \"%s\" in " "section %s", type, section); return -1; } return 0; } /* * XXX I rather want this function to return a status code, and fail if * we cannot fit the information in the supplied buffer. */ static void ipsec_decode_id(char *buf, size_t size, u_int8_t *id, size_t id_len, int isakmpform) { int id_type; char *addr = 0, *mask = 0; u_int32_t *idp; if (id) { if (!isakmpform) { /* * Exchanges and SAs dont carry the IDs in ISAKMP * form. */ id -= ISAKMP_GEN_SZ; id_len += ISAKMP_GEN_SZ; } id_type = GET_ISAKMP_ID_TYPE(id); idp = (u_int32_t *) (id + ISAKMP_ID_DATA_OFF); switch (id_type) { case IPSEC_ID_IPV4_ADDR: util_ntoa(&addr, AF_INET, id + ISAKMP_ID_DATA_OFF); snprintf(buf, size, "%08x: %s", decode_32(id + ISAKMP_ID_DATA_OFF), addr); break; case IPSEC_ID_IPV4_ADDR_SUBNET: util_ntoa(&addr, AF_INET, id + ISAKMP_ID_DATA_OFF); util_ntoa(&mask, AF_INET, id + ISAKMP_ID_DATA_OFF + 4); snprintf(buf, size, "%08x/%08x: %s/%s", decode_32(id + ISAKMP_ID_DATA_OFF), decode_32(id + ISAKMP_ID_DATA_OFF + 4), addr, mask); break; case IPSEC_ID_IPV6_ADDR: util_ntoa(&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF); snprintf(buf, size, "%08x%08x%08x%08x: %s", *idp, *(idp + 1), *(idp + 2), *(idp + 3), addr); break; case IPSEC_ID_IPV6_ADDR_SUBNET: util_ntoa(&addr, AF_INET6, id + ISAKMP_ID_DATA_OFF); util_ntoa(&mask, AF_INET6, id + ISAKMP_ID_DATA_OFF + sizeof(struct in6_addr)); snprintf(buf, size, "%08x%08x%08x%08x/%08x%08x%08x%08x: %s/%s", *idp, *(idp + 1), *(idp + 2), *(idp + 3), *(idp + 4), *(idp + 5), *(idp + 6), *(idp + 7), addr, mask); break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: /* String is not NUL terminated, be careful */ id_len -= ISAKMP_ID_DATA_OFF; id_len = MIN(id_len, size - 1); memcpy(buf, id + ISAKMP_ID_DATA_OFF, id_len); buf[id_len] = '\0'; break; #ifdef USE_X509 case IPSEC_ID_DER_ASN1_DN: addr = x509_DN_string(id + ISAKMP_ID_DATA_OFF, id_len - ISAKMP_ID_DATA_OFF); if (!addr) { snprintf(buf, size, "unparsable ASN1 DN ID"); return; } strlcpy(buf, addr, size); break; #endif default: snprintf(buf, size, "", id_type); break; } } else snprintf(buf, size, ""); if (addr) free(addr); if (mask) free(mask); } char * ipsec_decode_ids(char *fmt, u_int8_t *id1, size_t id1_len, u_int8_t *id2, size_t id2_len, int isakmpform) { static char result[1024]; char s_id1[256], s_id2[256]; ipsec_decode_id(s_id1, sizeof s_id1, id1, id1_len, isakmpform); ipsec_decode_id(s_id2, sizeof s_id2, id2, id2_len, isakmpform); snprintf(result, sizeof result, fmt, s_id1, s_id2); return result; } /* * Out of a named section SECTION in the configuration file build an * ISAKMP ID payload. Ths payload size should be stashed in SZ. * The caller is responsible for freeing the payload. */ u_int8_t * ipsec_build_id(char *section, size_t *sz) { struct sockaddr *addr, *mask; u_int8_t *p; int id, subnet = 0; u_int8_t tproto = 0; u_int16_t port = 0; if (ipsec_get_id(section, &id, &addr, &mask, &tproto, &port)) return 0; if (id == IPSEC_ID_IPV4_ADDR_SUBNET || id == IPSEC_ID_IPV6_ADDR_SUBNET) subnet = 1; *sz = ISAKMP_ID_SZ + sockaddr_addrlen(addr); if (subnet) *sz += sockaddr_addrlen(mask); p = malloc(*sz); if (!p) { log_print("ipsec_build_id: malloc(%lu) failed", (unsigned long)*sz); if (subnet) free(mask); free(addr); return 0; } SET_ISAKMP_ID_TYPE(p, id); SET_ISAKMP_ID_DOI_DATA(p, (unsigned char *)"\000\000\000"); memcpy(p + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(addr), sockaddr_addrlen(addr)); if (subnet) memcpy(p + ISAKMP_ID_DATA_OFF + sockaddr_addrlen(addr), sockaddr_addrdata(mask), sockaddr_addrlen(mask)); SET_IPSEC_ID_PROTO(p + ISAKMP_ID_DOI_DATA_OFF, tproto); SET_IPSEC_ID_PORT(p + ISAKMP_ID_DOI_DATA_OFF, port); if (subnet) free(mask); free(addr); return p; } /* * copy an ISAKMPD id */ int ipsec_clone_id(u_int8_t **did, size_t *did_len, u_int8_t *id, size_t id_len) { if (*did) free(*did); if (!id_len || !id) { *did = 0; *did_len = 0; return 0; } *did = malloc(id_len); if (!*did) { *did_len = 0; log_error("ipsec_clone_id: malloc(%lu) failed", (unsigned long)id_len); return -1; } *did_len = id_len; memcpy(*did, id, id_len); return 0; } /* * IPsec-specific PROTO initializations. SECTION is only set if we are the * initiator thus only usable there. * XXX I want to fix this later. */ void ipsec_proto_init(struct proto *proto, char *section) { struct ipsec_proto *iproto = proto->data; if (proto->sa->phase == 2 && section) iproto->replay_window = conf_get_num(section, "ReplayWindow", DEFAULT_REPLAY_WINDOW); } /* * Add a notification payload of type INITIAL CONTACT to MSG if this is * the first contact we have made to our peer. */ int ipsec_initial_contact(struct message *msg) { u_int8_t *buf; if (ipsec_contacted(msg)) return 0; buf = malloc(ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN); if (!buf) { log_error("ike_phase_1_initial_contact: malloc (%d) failed", ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN); return -1; } SET_ISAKMP_NOTIFY_DOI(buf, IPSEC_DOI_IPSEC); SET_ISAKMP_NOTIFY_PROTO(buf, ISAKMP_PROTO_ISAKMP); SET_ISAKMP_NOTIFY_SPI_SZ(buf, ISAKMP_HDR_COOKIES_LEN); SET_ISAKMP_NOTIFY_MSG_TYPE(buf, IPSEC_NOTIFY_INITIAL_CONTACT); memcpy(buf + ISAKMP_NOTIFY_SPI_OFF, msg->isakmp_sa->cookies, ISAKMP_HDR_COOKIES_LEN); if (message_add_payload(msg, ISAKMP_PAYLOAD_NOTIFY, buf, ISAKMP_NOTIFY_SZ + ISAKMP_HDR_COOKIES_LEN, 1)) { free(buf); return -1; } return ipsec_add_contact(msg); } /* * Compare the two contacts pointed to by A and B. Return negative if * *A < *B, 0 if they are equal, and positive if *A is the largest of them. */ static int addr_cmp(const void *a, const void *b) { const struct contact *x = a, *y = b; int minlen = MIN(x->len, y->len); int rv = memcmp(x->addr, y->addr, minlen); return rv ? rv : (x->len - y->len); } /* * Add the peer that MSG is bound to as an address we don't want to send * INITIAL CONTACT too from now on. Do not call this function with a * specific address duplicate times. We want fast lookup, speed of insertion * is unimportant, if this is to scale. */ static int ipsec_add_contact(struct message *msg) { struct contact *new_contacts; struct sockaddr *dst, *addr; int cnt; if (contact_cnt == contact_limit) { cnt = contact_limit ? 2 * contact_limit : 64; new_contacts = realloc(contacts, cnt * sizeof contacts[0]); if (!new_contacts) { log_error("ipsec_add_contact: " "realloc (%p, %lu) failed", contacts, cnt * (unsigned long) sizeof contacts[0]); return -1; } contact_limit = cnt; contacts = new_contacts; } msg->transport->vtbl->get_dst(msg->transport, &dst); addr = malloc(sysdep_sa_len(dst)); if (!addr) { log_error("ipsec_add_contact: malloc (%d) failed", sysdep_sa_len(dst)); return -1; } memcpy(addr, dst, sysdep_sa_len(dst)); contacts[contact_cnt].addr = addr; contacts[contact_cnt++].len = sysdep_sa_len(dst); /* * XXX There are better algorithms for already mostly-sorted data like * this, but only qsort is standard. I will someday do this inline. */ qsort(contacts, contact_cnt, sizeof *contacts, addr_cmp); return 0; } /* Return true if the recipient of MSG has already been contacted. */ static int ipsec_contacted(struct message *msg) { struct contact contact; msg->transport->vtbl->get_dst(msg->transport, &contact.addr); contact.len = sysdep_sa_len(contact.addr); return contacts ? (bsearch(&contact, contacts, contact_cnt, sizeof *contacts, addr_cmp) != 0) : 0; } /* Add a HASH for to MSG. */ u_int8_t * ipsec_add_hash_payload(struct message *msg, size_t hashsize) { u_int8_t *buf; buf = malloc(ISAKMP_HASH_SZ + hashsize); if (!buf) { log_error("ipsec_add_hash_payload: malloc (%lu) failed", ISAKMP_HASH_SZ + (unsigned long) hashsize); return 0; } if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, buf, ISAKMP_HASH_SZ + hashsize, 1)) { free(buf); return 0; } return buf; } /* Fill in the HASH payload of MSG. */ int ipsec_fill_in_hash(struct message *msg) { struct exchange *exchange = msg->exchange; struct sa *isakmp_sa = msg->isakmp_sa; struct ipsec_sa *isa = isakmp_sa->data; struct hash *hash = hash_get(isa->hash); struct prf *prf; struct payload *payload; u_int8_t *buf; u_int32_t i; char header[80]; /* If no SKEYID_a, we need not do anything. */ if (!isa->skeyid_a) return 0; payload = payload_first(msg, ISAKMP_PAYLOAD_HASH); if (!payload) { log_print("ipsec_fill_in_hash: no HASH payload found"); return -1; } buf = payload->p; /* Allocate the prf and start calculating our HASH(1). */ LOG_DBG_BUF((LOG_MISC, 90, "ipsec_fill_in_hash: SKEYID_a", isa->skeyid_a, isa->skeyid_len)); prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a, isa->skeyid_len); if (!prf) return -1; prf->Init(prf->prfctx); LOG_DBG_BUF((LOG_MISC, 90, "ipsec_fill_in_hash: message_id", exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN)); prf->Update(prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); /* Loop over all payloads after HASH(1). */ for (i = 2; i < msg->iovlen; i++) { /* XXX Misleading payload type printouts. */ snprintf(header, sizeof header, "ipsec_fill_in_hash: payload %d after HASH(1)", i - 1); LOG_DBG_BUF((LOG_MISC, 90, header, msg->iov[i].iov_base, msg->iov[i].iov_len)); prf->Update(prf->prfctx, msg->iov[i].iov_base, msg->iov[i].iov_len); } prf->Final(buf + ISAKMP_HASH_DATA_OFF, prf->prfctx); prf_free(prf); LOG_DBG_BUF((LOG_MISC, 80, "ipsec_fill_in_hash: HASH(1)", buf + ISAKMP_HASH_DATA_OFF, hash->hashsize)); return 0; } /* Add a HASH payload to MSG, if we have an ISAKMP SA we're protected by. */ static int ipsec_informational_pre_hook(struct message *msg) { struct sa *isakmp_sa = msg->isakmp_sa; struct ipsec_sa *isa; struct hash *hash; if (!isakmp_sa) return 0; isa = isakmp_sa->data; hash = hash_get(isa->hash); return ipsec_add_hash_payload(msg, hash->hashsize) == 0; } /* * Fill in the HASH payload in MSG, if we have an ISAKMP SA we're protected by. */ static int ipsec_informational_post_hook(struct message *msg) { if (!msg->isakmp_sa) return 0; return ipsec_fill_in_hash(msg); } ssize_t ipsec_id_size(char *section, u_int8_t *id) { char *type, *data; type = conf_get_str(section, "ID-type"); if (!type) { log_print("ipsec_id_size: section %s has no \"ID-type\" tag", section); return -1; } *id = constant_value(ipsec_id_cst, type); switch (*id) { case IPSEC_ID_IPV4_ADDR: return sizeof(struct in_addr); case IPSEC_ID_IPV4_ADDR_SUBNET: return 2 * sizeof(struct in_addr); case IPSEC_ID_IPV6_ADDR: return sizeof(struct in6_addr); case IPSEC_ID_IPV6_ADDR_SUBNET: return 2 * sizeof(struct in6_addr); case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: case IPSEC_ID_KEY_ID: case IPSEC_ID_DER_ASN1_DN: case IPSEC_ID_DER_ASN1_GN: data = conf_get_str(section, "Name"); if (!data) { log_print("ipsec_id_size: " "section %s has no \"Name\" tag", section); return -1; } return strlen(data); } log_print("ipsec_id_size: unrecognized/unsupported ID-type %d (%s)", *id, type); return -1; } /* * Generate a string version of the ID. */ char * ipsec_id_string(u_int8_t *id, size_t id_len) { char *buf = 0; char *addrstr = 0; size_t len, size; /* * XXX Real ugly way of making the offsets correct. Be aware that id * now will point before the actual buffer and cannot be dereferenced * without an offset larger than or equal to ISAKM_GEN_SZ. */ id -= ISAKMP_GEN_SZ; /* This is the actual length of the ID data field. */ id_len += ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF; /* * Conservative allocation. * XXX I think the ASN1 DN case can be thought through to give a better * estimate. */ size = MAX(sizeof "ipv6/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", sizeof "asn1_dn/" + id_len - ISAKMP_ID_DATA_OFF); buf = malloc(size); if (!buf) /* XXX Log? */ goto fail; switch (GET_ISAKMP_ID_TYPE(id)) { case IPSEC_ID_IPV4_ADDR: if (id_len < sizeof(struct in_addr)) goto fail; util_ntoa(&addrstr, AF_INET, id + ISAKMP_ID_DATA_OFF); if (!addrstr) goto fail; snprintf(buf, size, "ipv4/%s", addrstr); break; case IPSEC_ID_IPV6_ADDR: if (id_len < sizeof(struct in6_addr)) goto fail; util_ntoa(&addrstr, AF_INET6, id + ISAKMP_ID_DATA_OFF); if (!addrstr) goto fail; snprintf(buf, size, "ipv6/%s", addrstr); break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: strlcpy(buf, GET_ISAKMP_ID_TYPE(id) == IPSEC_ID_FQDN ? "fqdn/" : "ufqdn/", size); len = strlen(buf); memcpy(buf + len, id + ISAKMP_ID_DATA_OFF, id_len); *(buf + len + id_len) = '\0'; break; #ifdef USE_X509 case IPSEC_ID_DER_ASN1_DN: strlcpy(buf, "asn1_dn/", size); len = strlen(buf); addrstr = x509_DN_string(id + ISAKMP_ID_DATA_OFF, id_len - ISAKMP_ID_DATA_OFF); if (!addrstr) goto fail; if (size < len + strlen(addrstr) + 1) goto fail; strlcpy(buf + len, addrstr, size - len); break; #endif default: /* Unknown type. */ LOG_DBG((LOG_MISC, 10, "ipsec_id_string: unknown identity type %d\n", GET_ISAKMP_ID_TYPE(id))); goto fail; } if (addrstr) free(addrstr); return buf; fail: if (buf) free(buf); if (addrstr) free(addrstr); return 0; } isakmpd-20041012.orig/GNUmakefile0000644000175000017500000001657710133045740016647 0ustar jdivejdive00000000000000# $OpenBSD: GNUmakefile,v 1.9 2004/08/08 19:11:06 deraadt Exp $ # # Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. 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 # 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # # This makefile is a GNU makefile, which is generally available on most # systems, either as "make" or (often) "gmake". It has been converted from # a 'pmake' makefile (OpenBSDs 'make'), and some care has been taken to # produce similar behaviour. # # openbsd means 2.5 or newer, freeswan is the name for Linux with FreeS/WAN # integrated, freebsd/netbsd means FreeBSD/NetBSD with KAME IPsec. # darwin means MacOS X 10.2 and later with KAME IPsec. linux means Linux-2.5 # and later with native IPSec support. OS= openbsd #OS= netbsd #OS= freebsd #OS= freeswan #OS= darwin #OS= linux .CURDIR:= $(shell pwd) VPATH= ${.CURDIR}/sysdep/${OS} PROG= isakmpd ifndef BINDIR BINDIR= /sbin endif ifndef LDSTATIC LDSTATIC= -static endif SRCS= app.c attribute.c cert.c connection.c \ constants.c conf.c cookie.c crypto.c dh.c doi.c exchange.c \ exchange_num.c field.c gmp_util.c hash.c if.c ike_auth.c \ ike_main_mode.c ike_phase_1.c ike_quick_mode.c init.c \ ipsec.c ipsec_fld.c ipsec_num.c isakmpd.c isakmp_doi.c \ isakmp_fld.c isakmp_num.c key.c libcrypto.c log.c message.c \ math_2n.c math_group.c prf.c sa.c sysdep.c timer.c \ transport.c udp.c ui.c util.c virtual.c GENERATED= exchange_num.h ipsec_fld.h ipsec_num.h isakmp_fld.h \ isakmp_num.h CLEANFILES= exchange_num.c exchange_num.h ipsec_num.c ipsec_num.h \ isakmp_num.c isakmp_num.h ipsec_fld.c ipsec_fld.h \ isakmp_fld.c isakmp_fld.h MAN= isakmpd.8 isakmpd.conf.5 isakmpd.policy.5 CFLAGS+= -O2 ${DEBUG} -Wall -DNEED_SYSDEP_APP \ -I${.CURDIR} -I${.CURDIR}/sysdep/${OS} -I. \ # Different debugging & profiling suggestions # Include symbolic debugging info DEBUG= -g # Do execution time profiles #CFLAGS+= -pg # If you have ElectricFence available, you can spot abuses of the heap. # (/usr/ports/devel/ElectricFence) #LDADD+= -L/usr/local/lib -lefence #DPADD+= /usr/local/lib/libefence.a # If you like to use Boehm's garbage collector (/usr/ports/devel/boehm-gc). #LDADD+= -L/usr/local/lib -lgc #DPADD+= /usr/local/lib/libgc.a # You can also use Boehm's garbage collector as a means to find leaks. # XXX The defines below are GCC-specific. I think it is OK to require # XXX GCC if you are debugging isakmpd in this way. #LDADD+= -L/usr/local/lib -lleak #DPADD+= /usr/local/lib/libleak.a #CFLAGS+= -D'malloc(x)=({ \ # void *GC_debug_malloc (size_t, char *, int); \ # GC_debug_malloc ((x), __FILE__, __LINE__); \ # })' \ # -D'realloc(x,y)=({ \ # void *GC_debug_realloc (void *, size_t, char *, int); \ # GC_debug_realloc ((x), (y), __FILE__, __LINE__); \ # })' \ # -D'free(x)=({ \ # void GC_debug_free (void *); \ # GC_debug_free (x); \ # })' \ # -D'calloc(x,y)=malloc((x) * (y))' \ # -D'strdup(x)=({ \ # char *strcpy (char *, const char *); \ # const char *_x_ = (x); \ # char *_y_ = malloc (strlen (_x_) + 1); \ # strcpy (_y_, _x_); \ # })' # Ignore any files with these names... .PHONY: mksubdirs all clean cleandir cleandepend beforedepend \ afterdepend realclean realcleandepend # Default target, it needs to be the first target in makefile... :( all: ${PROG} mksubdirs ifneq ($(findstring install,$(MAKECMDGOALS)),install) # Skip 'regress' until the regress/ structure has gmake makefiles for it. #SUBDIR:= regress SUBDIR:= mksubdirs: $(foreach DIR, ${SUBDIR}, \ cd ${DIR}; ${MAKE} ${MAKEFLAGS} CFLAGS="${CFLAGS}" \ MKDEP="${MKDEP}" ${MAKECMDGOALS}) else mksubdirs: endif # DEPSRCS handling is *ugly*, I know... # What is does; keep orig SRCS in ORIGSRCS; potentially add stuff to # SRCS (include); let DEPSRCS be ORIGSRCS (sysdep.c -> sysdep//sysdep.c) # _plus_ any new sources, located either in cwd or sysdep/. Phew. ORIGSRCS:= ${SRCS} -include sysdep/${OS}/GNUmakefile.sysdep FEATURES_UC= $(shell echo ${FEATURES} | tr '[:lower:]' '[:upper:]') CFLAGS+= $(foreach F, ${FEATURES_UC}, -DUSE_${F}) -include $(foreach F, ${FEATURES}, features/${F}) ifdef USE_KEYNOTE USE_LIBCRYPTO= yes LDADD+= -lkeynote -lm DPADD+= ${LIBKEYNOTE} ${LIBM} POLICY= policy.c CFLAGS+= -DUSE_KEYNOTE endif ifdef USE_LIBCRYPTO X509= x509.c CFLAGS+= -DUSE_LIBCRYPTO LDADD+= -lcrypto DPADD+= ${LIBCRYPTO} endif ifdef USE_RAWKEY USE_LIBCRYPTO= yes CFLAGS+= -DUSE_RAWKEY endif SRCS+= ${IPSEC_SRCS} ${X509} ${POLICY} ${EC} ${AGGRESSIVE} ${DNSSEC} \ $(ISAKMP_CFG) CFLAGS+= ${IPSEC_CFLAGS} LDADD+= ${DESLIB} DPADD+= ${DESLIBDEP} DEPSRCS:= $(subst sysdep.c,${VPATH}/sysdep.c,${ORIGSRCS}) \ $(foreach FILE, $(filter-out ${ORIGSRCS},${SRCS}), \ $(wildcard ./${FILE} ${VPATH}/${FILE})) OBJS:= $(SRCS:%.c=%.o) # Generated targets exchange_num.c exchange_num.h: genconstants.sh exchange_num.cst /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/exchange_num ipsec_fld.c ipsec_fld.h: genfields.sh ipsec_fld.fld /bin/sh ${.CURDIR}/genfields.sh ${.CURDIR}/ipsec_fld ipsec_num.c ipsec_num.h: genconstants.sh ipsec_num.cst /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/ipsec_num isakmp_fld.c isakmp_fld.h: genfields.sh isakmp_fld.fld /bin/sh ${.CURDIR}/genfields.sh ${.CURDIR}/isakmp_fld isakmp_num.c isakmp_num.h: genconstants.sh isakmp_num.cst /bin/sh ${.CURDIR}/genconstants.sh ${.CURDIR}/isakmp_num # Program rules ${PROG} beforedepend: ${GENERATED} ${PROG}: ${OBJS} ${DPADD} ${CC} ${DEBUG} ${LDFLAGS} ${LDSTATIC} -o $@ ${OBJS} ${LDADD} # Depend rules depend: beforedepend .depend mksubdirs afterdepend @true # Since 'mkdep' et al maybe doesn't exist... MKDEP:= ${CC} -MM .depend: ${SRCS} @rm -f .depend ${MKDEP} ${CFLAGS} ${DEPSRCS} > .depend afterdepend: ifneq ($(findstring clean, $(MAKECMDGOALS)), clean) # This will initially fail (when .depend does not exist), continue # to create .depend, then make will automatically restart to include # the generated .depend correctly. The '-' inhibits the warning msg. -include .depend endif # Clean rules cleandir: realclean realcleandepend mksubdirs clean: realclean mksubdirs cleandepend: realcleandepend mksubdirs realclean: rm -f a.out core *.core ${PROG} ${OBJS} ${CLEANFILES} realcleandepend: rm -f .depend tags isakmpd-20041012.orig/dh.c0000644000175000017500000000535610133045740015325 0ustar jdivejdive00000000000000/* $OpenBSD: dh.c,v 1.9 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: dh.c,v 1.5 1999/04/17 23:20:22 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include "sysdep.h" #include "math_group.h" #include "dh.h" #include "log.h" /* * Returns the length of our exchange value. */ int dh_getlen(struct group *group) { return group->getlen(group); } /* * Creates the exchange value we are offering to the other party. * Each time this function is called a new value is created, that * means the application has to save the exchange value itself, * dh_create_exchange should only be called once. */ int dh_create_exchange(struct group *group, u_int8_t *buf) { if (group->setrandom(group, group->c)) return -1; if (group->operation(group, group->a, group->gen, group->c)) return -1; group->getraw(group, group->a, buf); return 0; } /* * Creates the Diffie-Hellman shared secret in 'secret', where 'exchange' * is the exchange value offered by the other party. No length verification * is done for the value, the application has to do that. */ int dh_create_shared(struct group *group, u_int8_t *secret, u_int8_t *exchange) { if (group->setraw(group, group->b, exchange, group->getlen(group))) return -1; if (group->operation(group, group->a, group->b, group->c)) return -1; group->getraw(group, group->a, secret); return 0; } isakmpd-20041012.orig/attribute.h0000644000175000017500000000375110133045740016737 0ustar jdivejdive00000000000000/* $OpenBSD: attribute.h,v 1.6 2004/05/14 08:42:56 hshoexer Exp $ */ /* $EOM: attribute.h,v 1.2 1998/09/29 21:51:07 niklas Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _ATTRIBUTE_H_ #define _ATTRIBUTE_H_ #include struct constant_map; extern int attribute_map(u_int8_t *, size_t, int (*)(u_int16_t, u_int8_t *, u_int16_t, void *), void *); extern u_int8_t *attribute_set_basic(u_int8_t *, u_int16_t, u_int16_t); extern int attribute_set_constant(char *, char *, struct constant_map *, int, u_int8_t **); extern u_int8_t *attribute_set_var(u_int8_t *, u_int16_t, u_int8_t *, u_int16_t); #endif /* _ATTRIBUTE_H_ */ isakmpd-20041012.orig/doi.h0000644000175000017500000000756710133045740015520 0ustar jdivejdive00000000000000/* $OpenBSD: doi.h,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */ /* $EOM: doi.h,v 1.29 2000/07/02 18:47:15 provos Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _DOI_H_ #define _DOI_H_ #include #include struct exchange; struct keystate; struct message; struct payload; struct proto; struct sa; /* XXX This structure needs per-field commenting. */ struct doi { LIST_ENTRY(doi) link; u_int8_t id; /* Size of DOI-specific exchange data. */ size_t exchange_size; /* Size of DOI-specific security association data. */ size_t sa_size; /* Size of DOI-specific protocol data. */ size_t proto_size; #ifdef USE_DEBUG int (*debug_attribute)(u_int16_t, u_int8_t *, u_int16_t, void *); #endif void (*delete_spi)(struct sa *, struct proto *, int); int16_t *(*exchange_script)(u_int8_t); void (*finalize_exchange)(struct message *); void (*free_exchange_data)(void *); void (*free_proto_data)(void *); void (*free_sa_data)(void *); struct keystate *(*get_keystate)(struct message *); u_int8_t *(*get_spi)(size_t *, u_int8_t, struct message *); int (*handle_leftover_payload)(struct message *, u_int8_t, struct payload *); int (*informational_post_hook)(struct message *); int (*informational_pre_hook)(struct message *); int (*is_attribute_incompatible)(u_int16_t, u_int8_t *, u_int16_t, void *); void (*proto_init)(struct proto *, char *); void (*setup_situation)(u_int8_t *); size_t (*situation_size)(void); u_int8_t (*spi_size)(u_int8_t); int (*validate_attribute)(u_int16_t, u_int8_t *, u_int16_t, void *); int (*validate_exchange)(u_int8_t); int (*validate_id_information)(u_int8_t, u_int8_t *, u_int8_t *, size_t, struct exchange *); int (*validate_key_information)(u_int8_t *, size_t); int (*validate_notification)(u_int16_t); int (*validate_proto)(u_int8_t); int (*validate_situation)(u_int8_t *, size_t *, size_t); int (*validate_transform_id)(u_int8_t, u_int8_t); int (*initiator)(struct message * msg); int (*responder)(struct message * msg); char *(*decode_ids)(char *, u_int8_t *, size_t, u_int8_t *, size_t, int); }; extern void doi_init(void); extern struct doi *doi_lookup(u_int8_t); extern void doi_register(struct doi *); #endif /* _DOI_H_ */ isakmpd-20041012.orig/ike_phase_1.h0000644000175000017500000000502510133045740017100 0ustar jdivejdive00000000000000/* $OpenBSD: ike_phase_1.h,v 1.4 2004/04/15 18:39:25 deraadt Exp $ */ /* * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _IKE_PHASE_1_H_ #define _IKE_PHASE_1_H_ struct message; extern int ike_phase_1_initiator_recv_KE_NONCE(struct message *); extern int ike_phase_1_initiator_recv_SA(struct message *); extern int ike_phase_1_initiator_send_KE_NONCE(struct message *); extern int ike_phase_1_initiator_send_SA(struct message *); extern int ike_phase_1_post_exchange_KE_NONCE(struct message *); extern int ike_phase_1_recv_AUTH(struct message *); extern int ike_phase_1_recv_ID(struct message *); extern int ike_phase_1_recv_ID_AUTH(struct message *); extern int ike_phase_1_recv_KE_NONCE(struct message *); extern int ike_phase_1_responder_recv_SA(struct message *); extern int ike_phase_1_responder_send_SA(struct message *); extern int ike_phase_1_responder_send_ID_AUTH(struct message *); extern int ike_phase_1_send_AUTH(struct message *); extern int ike_phase_1_send_ID(struct message *); extern int ike_phase_1_send_ID_AUTH(struct message *); extern int ike_phase_1_send_KE_NONCE(struct message *, size_t); #endif /* _IKE_PHASE_1_H_ */ isakmpd-20041012.orig/exchange.h0000644000175000017500000002167210133045740016520 0ustar jdivejdive00000000000000/* $OpenBSD: exchange.h,v 1.28 2004/08/23 11:13:14 ho Exp $ */ /* $EOM: exchange.h,v 1.28 2000/09/28 12:54:28 niklas Exp $ */ /* * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _EXCHANGE_H_ #define _EXCHANGE_H_ #include #include #include #include "exchange_num.h" #include "isakmp.h" /* Remove an exchange if it has not been fully negotiated in this time. */ #define EXCHANGE_MAX_TIME 120 struct crypto_xf; struct certreq_aca; struct doi; struct event; struct keystate; struct message; struct payload; struct transport; struct sa; struct exchange { /* Link to exchanges with the same hash value. */ LIST_ENTRY(exchange) link; /* A name of the SAs this exchange will result in. XXX non unique? */ char *name; /* * A name of the major policy deciding offers and acceptable * proposals. */ char *policy; /* * A function with a polymorphic argument called after the exchange * has been run to its end, successfully. The 2nd argument is true * if the finalization hook is called due to the exchange not running * to its end normally. */ void (*finalize)(struct exchange *, void *, int); void *finalize_arg; /* When several SA's are being negotiated we keep them here. */ TAILQ_HEAD(sa_head, sa) sa_list; /* * The event that will occur when it has taken too long time to try to * run the exchange and which will trigger auto-destruction. */ struct event *death; /* * Both initiator and responder cookies. * XXX For code clarity we might split this into two fields. */ u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN]; /* The message ID signifying phase 2 exchanges. */ u_int8_t message_id[ISAKMP_HDR_MESSAGE_ID_LEN]; /* The exchange type we are using. */ u_int8_t type; /* Phase is 1 for ISAKMP SA exchanges, and 2 for application ones. */ u_int8_t phase; /* The "step counter" of the exchange, starting from zero. */ u_int8_t step; /* 1 if we are the initiator, 0 if we are the responder. */ u_int8_t initiator; /* Various flags, look below for descriptions. */ u_int32_t flags; /* The DOI that is to handle DOI-specific issues for this exchange. */ struct doi *doi; /* * A "program counter" into the script that validate message contents * for this exchange. */ int16_t *exch_pc; /* The last message received, used for checking for duplicates. */ struct message *last_received; /* The last message sent, to be acked when something new is received. */ struct message *last_sent; /* * If some message is queued up for sending, we want to be able to * remove it from the queue, when the exchange is deleted. */ struct message *in_transit; /* * Initiator's & responder's nonces respectively, with lengths. * XXX Should this be in the DOI-specific parts instead? */ u_int8_t *nonce_i; size_t nonce_i_len; u_int8_t *nonce_r; size_t nonce_r_len; /* * The ID payload contents for the initiator & responder, * respectively. */ u_int8_t *id_i; size_t id_i_len; u_int8_t *id_r; size_t id_r_len; /* Policy session identifier, where applicable. */ int policy_id; /* Crypto info needed to encrypt/decrypt packets in this exchange. */ struct crypto_xf *crypto; size_t key_length; struct keystate *keystate; /* * Used only by KeyNote, to cache the key used to authenticate Phase * 1 */ char *keynote_key; /* printable format */ /* * Received certificate - used to verify signatures on packet, * stored here for later policy processing. * * The rules for the recv_* and sent_* fields are: * - recv_cert stores the credential (if any) received from the peer; * the kernel may pass us one, but we ignore it. We pass it to the * kernel so processes can peek at it. When doing passphrase * authentication in Phase 1, this is empty. * - recv_key stores the key (public or private) used by the peer * to authenticate. Otherwise, same properties as recv_cert except * that we don't tell the kernel about passphrases (so we don't * reveal system-wide passphrases). Processes that used passphrase * authentication already know the passphrase! We ignore it if/when * received from the kernel (meaningless). * - sent_cert stores the credential, if any, we used to authenticate * with the peer. It may be passed to us by the kernel, or we may * have found it in our certificate storage. In either case, there's * no point passing it to the kernel, so we don't. * - sent key stores the private key we used for authentication with * the peer (private key or passphrase). This may have been received * from the kernel, or may be a system-wide setting. In either case, * we don't pass it to the kernel, to avoid revealing such information * to processes (processes either already know it, or have no business * knowing it). */ int recv_certtype, recv_keytype; void *recv_cert; /* Certificate received from peer, * native format */ void *recv_key; /* Key peer used to authenticate, * native format */ /* Likewise, for certificates/keys we use. */ int sent_certtype, sent_keytype; void *sent_cert; /* Certificate (to be) sent to peer, * native format */ void *sent_key; /* Key we'll use to authenticate to * peer, native format */ /* ACQUIRE sequence number. */ u_int32_t seq; /* XXX This is no longer necessary, it is covered by policy. */ /* Acceptable authorities for cert requests. */ TAILQ_HEAD(aca_head, certreq_aca) aca_list; /* DOI-specific opaque data. */ void *data; }; /* The flag bits. */ #define EXCHANGE_FLAG_I_COMMITTED 0x01 #define EXCHANGE_FLAG_HE_COMMITTED 0x02 #define EXCHANGE_FLAG_COMMITTED (EXCHANGE_FLAG_I_COMMITTED \ | EXCHANGE_FLAG_HE_COMMITTED) #define EXCHANGE_FLAG_ENCRYPT 0x04 #define EXCHANGE_FLAG_NAT_T_CAP_PEER 0x08 /* Peer is NAT capable. */ #define EXCHANGE_FLAG_NAT_T_ENABLE 0x10 /* We are doing NAT-T. */ #define EXCHANGE_FLAG_NAT_T_KEEPALIVE 0x20 /* We are the NAT:ed peer. */ #define EXCHANGE_FLAG_DPD_CAP_PEER 0x40 /* Peer is DPD capable. */ extern int exchange_add_certs(struct message *); extern void exchange_finalize(struct message *); extern void exchange_free(struct exchange *); extern void exchange_free_aca_list(struct exchange *); extern void exchange_establish(char *name, void (*)(struct exchange *, void *, int), void *); extern void exchange_establish_p1(struct transport *, u_int8_t, u_int32_t, char *, void *, void (*)(struct exchange *, void *, int), void *); extern void exchange_establish_p2(struct sa *, u_int8_t, char *, void *, void (*)(struct exchange *, void *, int), void *); extern int exchange_gen_nonce(struct message *, size_t); extern void exchange_init(void); extern struct exchange *exchange_lookup(u_int8_t *, int); extern struct exchange *exchange_lookup_by_name(char *, int); extern struct exchange *exchange_lookup_from_icookie(u_int8_t *); extern void exchange_report(void); extern void exchange_run(struct message *); extern int exchange_save_nonce(struct message *); extern int exchange_save_certreq(struct message *); extern int16_t *exchange_script(struct exchange *); extern struct exchange *exchange_setup_p1(struct message *, u_int32_t); extern struct exchange *exchange_setup_p2(struct message *, u_int8_t); extern void exchange_upgrade_p1(struct message *); #endif /* _EXCHANGE_H_ */ isakmpd-20041012.orig/log.h0000644000175000017500000000705610133045740015517 0ustar jdivejdive00000000000000/* $OpenBSD: log.h,v 1.21 2004/05/23 18:17:56 hshoexer Exp $ */ /* $EOM: log.h,v 1.19 2000/03/30 14:27:23 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. * Copyright (c) 2001, 2002, 2003 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _LOG_H_ #define _LOG_H_ #include #include #include #include extern int verbose_logging; /* * We cannot do the log strings dynamically sizeable as out of memory is one * of the situations we need to report about. */ #define LOG_SIZE 200 enum log_classes { LOG_MISC, LOG_TRANSPORT, LOG_MESSAGE, LOG_CRYPTO, LOG_TIMER, LOG_SYSDEP, LOG_SA, LOG_EXCHANGE, LOG_NEGOTIATION, LOG_POLICY, LOG_UI, LOG_ENDCLASS }; #define LOG_CLASSES_TEXT \ { "Misc", "Trpt", "Mesg", "Cryp", "Timr", "Sdep", "SA ", "Exch", "Negt", \ "Plcy", "UI " } /* * "Class" LOG_REPORT will always be logged to the current log channel, * regardless of level. */ #define LOG_PRINT -1 #define LOG_REPORT -2 #ifdef USE_DEBUG #define LOG_DBG(x) log_debug x #define LOG_DBG_BUF(x) log_debug_buf x extern void log_debug(int, int, const char *,...) __attribute__((__format__(__printf__, 3, 4))); extern void log_debug_buf(int, int, const char *, const u_int8_t *, size_t); extern void log_debug_cmd(int, int); extern void log_debug_toggle(void); #define PCAP_FILE_DEFAULT "/var/run/isakmpd.pcap" extern void log_packet_init(char *); extern void log_packet_iov(struct sockaddr *, struct sockaddr *, struct iovec *, int); extern void log_packet_restart(char *); extern void log_packet_stop(void); #else /* !USE_DEBUG */ #define LOG_DBG(x) #define LOG_DBG_BUF(x) #endif /* USE_DEBUG */ extern FILE *log_current(void); extern void log_error(const char *,...) __attribute__((__format__(__printf__, 1, 2))); extern void log_fatal(const char *,...) __attribute__((__format__(__printf__, 1, 2))); extern void log_print(const char *,...) __attribute__((__format__(__printf__, 1, 2))); extern void log_verbose(const char *,...) __attribute__((__format__(__printf__, 1, 2))); extern void log_to(FILE *); extern void log_init(int); extern void log_reinit(void); #endif /* _LOG_H_ */ isakmpd-20041012.orig/QUESTIONS0000644000175000017500000000331510133045740016074 0ustar jdivejdive00000000000000$OpenBSD: QUESTIONS,v 1.5 2003/11/05 12:31:21 jmc Exp $ $EOM: QUESTIONS,v 1.12 1998/10/11 17:11:06 niklas Exp $ Does the spec limit the count of SA payloads in a message? Where if so? [ Only the specific IKE main mode does. In the IKE spec.] The message ID field of the header, can it be considered a SA identifier if used together with the cookiepair? [Yes, it is meant to be that] DOI 0, what protocols are defined for it? Where? Isn't this a potential DOS attack: Hostile user listens for ISAKMP traffic, and then extracts cookiepairs and message IDs which he uses to flood any of the peers with spoofed packets pretending to be the other one. Most probably these packets will result in error notifications which potentially result in SA tear-down? Maybe should notifications never be issued for erroneous packets which cannot be authenticated? Or should we not tear down SAs as results of notifications? Certicom claims to hold licenses for Elliptic Curve Cryptography? Does this concern us? See: http://grouper.ieee.org/groups/1363/P1363/patents.html Main mode when using public key encryption authentication does not look like an identity protection exchange to me. Must I really get rid of the generic ISAKMP payload presense tests? IV generation is not described precisely in Appendix B of -oakley-08.txt: 'Subsequent messages MUST use the last CBC encryption block from the previous message as their IV'. This probably means that we take the new IV from the last encrypted block of the last message we sent. The SSH testing site uses the last block from the last message they received. This is probably not what was meant and should be clarified on ipsec@tis.com. [ From what we have gathered this is what is meant. ] isakmpd-20041012.orig/hash.h0000644000175000017500000000504310133045740015653 0ustar jdivejdive00000000000000/* $OpenBSD: hash.h,v 1.7 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: hash.h,v 1.6 1998/07/25 22:04:36 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _HASH_H_ #define _HASH_H_ /* Normal mode hash encapsulation */ #define MD5_SIZE 16 #define SHA1_SIZE 20 #define HASH_MAX SHA1_SIZE enum hashes { HASH_MD5 = 0, HASH_SHA1 }; struct hash { enum hashes type; int id; /* ISAKMP/Oakley ID */ u_int8_t hashsize; /* Size of the hash */ void *ctx; /* Pointer to a context, for HMAC ictx */ unsigned char *digest; /* Pointer to a digest */ int ctxsize; void *ctx2; /* Pointer to a 2nd context, for HMAC octx */ void (*Init) (void *); void (*Update) (void *, unsigned char *, unsigned int); void (*Final) (unsigned char *, void *); void (*HMACInit) (struct hash *, unsigned char *, unsigned int); void (*HMACFinal) (unsigned char *, struct hash *); }; /* HMAC Hash Encapsulation */ #define HMAC_IPAD_VAL 0x36 #define HMAC_OPAD_VAL 0x5C #define HMAC_BLOCKLEN 64 extern struct hash *hash_get(enum hashes); extern void hmac_init(struct hash *, unsigned char *, unsigned int); #endif /* _HASH_H_ */ isakmpd-20041012.orig/timer.c0000644000175000017500000000750510133045740016050 0ustar jdivejdive00000000000000/* $OpenBSD: timer.c,v 1.14 2004/06/14 09:55:42 ho Exp $ */ /* $EOM: timer.c,v 1.13 2000/02/20 19:58:42 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include "sysdep.h" #include "log.h" #include "timer.h" static TAILQ_HEAD(event_list, event) events; void timer_init(void) { TAILQ_INIT(&events); } void timer_next_event(struct timeval **timeout) { struct timeval now; if (TAILQ_FIRST(&events)) { gettimeofday(&now, 0); if (timercmp(&now, &TAILQ_FIRST(&events)->expiration, >=)) timerclear(*timeout); else timersub(&TAILQ_FIRST(&events)->expiration, &now, *timeout); } else *timeout = 0; } void timer_handle_expirations(void) { struct timeval now; struct event *n; gettimeofday(&now, 0); for (n = TAILQ_FIRST(&events); n && timercmp(&now, &n->expiration, >=); n = TAILQ_FIRST(&events)) { LOG_DBG((LOG_TIMER, 10, "timer_handle_expirations: event %s(%p)", n->name, n->arg)); TAILQ_REMOVE(&events, n, link); (*n->func)(n->arg); free(n); } } struct event * timer_add_event(char *name, void (*func)(void *), void *arg, struct timeval *expiration) { struct event *ev = (struct event *) malloc(sizeof *ev); struct event *n; struct timeval now; if (!ev) return 0; ev->name = name; ev->func = func; ev->arg = arg; gettimeofday(&now, 0); memcpy(&ev->expiration, expiration, sizeof *expiration); for (n = TAILQ_FIRST(&events); n && timercmp(expiration, &n->expiration, >=); n = TAILQ_NEXT(n, link)) ; if (n) { LOG_DBG((LOG_TIMER, 10, "timer_add_event: event %s(%p) added before %s(%p), " "expiration in %lds", name, arg, n->name, n->arg, expiration->tv_sec - now.tv_sec)); TAILQ_INSERT_BEFORE(n, ev, link); } else { LOG_DBG((LOG_TIMER, 10, "timer_add_event: event %s(%p) added " "last, expiration in %lds", name, arg, expiration->tv_sec - now.tv_sec)); TAILQ_INSERT_TAIL(&events, ev, link); } return ev; } void timer_remove_event(struct event *ev) { LOG_DBG((LOG_TIMER, 10, "timer_remove_event: removing event %s(%p)", ev->name, ev->arg)); TAILQ_REMOVE(&events, ev, link); free(ev); } void timer_report(void) { struct event *ev; struct timeval now; gettimeofday(&now, 0); for (ev = TAILQ_FIRST(&events); ev; ev = TAILQ_NEXT(ev, link)) LOG_DBG((LOG_REPORT, 0, "timer_report: event %s(%p) scheduled in %d seconds", (ev->name ? ev->name : ""), ev, (int) (ev->expiration.tv_sec - now.tv_sec))); } isakmpd-20041012.orig/libcrypto.h0000644000175000017500000000374610133045740016747 0ustar jdivejdive00000000000000/* $OpenBSD: libcrypto.h,v 1.16 2004/04/15 18:39:26 deraadt Exp $ */ /* $EOM: libcrypto.h,v 1.16 2000/09/28 12:53:27 niklas Exp $ */ /* * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2000 Angelos D. Keromytis. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _LIBCRYPTO_H_ #define _LIBCRYPTO_H_ #ifdef USE_X509 #include /* XXX I want #include but we appear to not install meth.h */ #include #include #include #include #include #include #endif /* USE_X509 */ extern void libcrypto_init(void); #endif /* _LIBCRYPTO_H_ */ isakmpd-20041012.orig/BUGS0000644000175000017500000000710110133045740015237 0ustar jdivejdive00000000000000$OpenBSD: BUGS,v 1.14 2002/06/09 08:13:06 todd Exp $ $EOM: BUGS,v 1.38 2000/02/18 08:47:35 niklas Exp $ Until we have a bug-tracking system setup, we might just add bugs to this file: ------------------------------------------------------------------------------ * message_drop frees the message, this is sometimes wrong and can cause duplicate frees, for example when a proposal does not get chosen. [fixed] * Notifications should be their own exchanges, otherwise the IV gets disturbed. [fixed] * We need a death timeout on half-ready SAs just like exchanges. At the moment we leak SAs. * When we establish a phase 2 exchange we seem to get the wrong IV set, according to SSH's logs. [fixed] * If a phase 1 SA negotiation terminates with a cause that is to be sent in a NOTIFY to the peer, we get multiple free calls on the cleanup of the informational exchange. [fixed] * IKE mandates that a HASH should be added to informational exchanges in phase 2. [fixed] * Message_send requires an exchange to exist, and potentially it tries to encrypt a message multiple times when retransmitting. [fixed] * Multiple protocol proposals seems to fail. [fixed] * The initiator fails to match the responders choice of protocol suite with the correct one of its own when several are offered. [fixed] * Duplicate specified sections is not detected. [fixed] * Quick mode establishments via UI using -P bind-addr gets "Address already in use". * Not chosen proposals should be deleted from the protos list in the sa structure. [fixed] * Setting SPIs generates "Invalid argument" errors due to one tunnel endpoint being INADDR_ANY. [fixed] * ipsec_proto structs are never allocated. [fixed] * Remove SPIs of unused proposals. [fixed] * If the first proposal is turned down, the initiator gets confused. * Renegotiation after a failed phase 1 fails. * Phase 1 rekey event removal seems to be done twice. [fixed] * PF_ENCAP expirations does not find the proper phase 2 SA to remove. [fixed] * ISAKMP SA expirations should have a soft/hard timeout just like IPsec ones. The soft one should put a watchdog on the SA, and start a renegotiation as soon as something used the SA. Hard ones should just clean it up, no renegotiation at all. [fixed] * ISAKMP SAs does not get removed after rekeying. [fixed] * On-demand PF_ENCAP SAs does not get reestablished. [fixed] * Rekeying is now done automatically on expirations, it should not. The SAs should be brought up on-demand just like the first time. * Notifications regarding exchange errors seems to not have the right SPI, at least not in phase 1, in NO_PROPOSAL_CHOSEN. * Outgoing informational exchanges when we use INVALID_PAYLOAD_TYPE cause a DOI error. * In Linux select(2) of named pipes seems broken as they will return as readable even when nothing is there after one read has succeeded. * I have seen INITIAL-CONTACT sent on the second Main Mode. * When ID mismatches occur, coredumps may follow, investigate! * ESP+AH does not work properly * Looping QM seen (due to lost sendpackets from other participant?) * Teardown from UI does not remove exchanges. * Wrong error message when policy check fails. * Restransmit of QM (packet 1) after INFO/PAYLOAD_MALFORMED was received. * SIGSEGV after sa_enter: sa added to sa list, trigged by DELETE notify (Linux) * Passive connections, undefined local&remote IDs will cause IKE peer IDs to be used. * host route support in KLIPS does not work properly * When not having compiled in support for a certain crypto algorithm and the config file still tells us to propose it, we segfault. isakmpd-20041012.orig/monitor_fdpass.c0000644000175000017500000000620310133045740017751 0ustar jdivejdive00000000000000/* $OpenBSD: monitor_fdpass.c,v 1.11 2004/10/01 04:08:45 jsg Exp $ */ /* * Copyright 2001 Niels Provos * 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. * * 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 #include #include #include #include #include "log.h" #include "monitor.h" int mm_send_fd(int socket, int fd) { struct msghdr msg; char tmp[CMSG_SPACE(sizeof(int))], ch = '\0'; struct cmsghdr *cmsg; struct iovec vec; ssize_t n; memset(&msg, 0, sizeof msg); msg.msg_control = (caddr_t) tmp; msg.msg_controllen = CMSG_LEN(sizeof(int)); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsg) = fd; vec.iov_base = &ch; vec.iov_len = 1; msg.msg_iov = &vec; msg.msg_iovlen = 1; if ((n = sendmsg(socket, &msg, 0)) == -1) { log_error("mm_send_fd: sendmsg(%d)", fd); return -1; } if (n != 1) { log_error("mm_send_fd: sendmsg: expected sent 1 got %ld", (long)n); return -1; } return 0; } int mm_receive_fd(int socket) { struct msghdr msg; char tmp[CMSG_SPACE(sizeof(int))], ch; struct cmsghdr *cmsg; struct iovec vec; ssize_t n; int fd; memset(&msg, 0, sizeof msg); vec.iov_base = &ch; vec.iov_len = 1; msg.msg_iov = &vec; msg.msg_iovlen = 1; msg.msg_control = tmp; msg.msg_controllen = sizeof tmp; if ((n = recvmsg(socket, &msg, 0)) == -1) { log_error("mm_receive_fd: recvmsg"); return -1; } if (n != 1) { log_error("mm_receive_fd: recvmsg: expected received 1 got %ld", (long)n); return -1; } cmsg = CMSG_FIRSTHDR(&msg); if (cmsg == NULL) { log_error("mm_receive_fd: no message header"); return -1; } if (cmsg->cmsg_type != SCM_RIGHTS) { log_error("mm_receive_fd: expected type %d got %d", SCM_RIGHTS, cmsg->cmsg_type); return -1; } fd = (*(int *)CMSG_DATA(cmsg)); return fd; } isakmpd-20041012.orig/TO-DO0000644000175000017500000000721310133045740015325 0ustar jdivejdive00000000000000$OpenBSD: TO-DO,v 1.26 2003/08/28 14:43:35 markus Exp $ $EOM: TO-DO,v 1.45 2000/04/07 22:47:38 niklas Exp $ This file mixes small nitpicks with large projects to be done. * Add debugging messages, maybe possible to control asynchronously. [done] * Implement the local policy governing logging and notification of exceptional conditions. * A field description mechanism used for things like making packet dumps readable etc. Both Photurisd and Pluto does this. [done] * Fix the cookies. [done] * Garbage collect transports (ref-counting?). [done] * Retransmission/dup packet handling. [done] * Generic payload checks. [mostly done] * For math, speed up multiplication and division functions. * Cleanup of SAs when dropping messages. [done] * Look over message resource tracking. [done] * Retransmission timing & count adaptivity and configurability. [configurability done] * Quick mode exchanges [done] * Aggressive mode exchange. [done] * Finish main mode exchange [done] * Separation of key exchange from the IPsec DOI, i.e. factor out IKE details. * Setup the IPsec situation field in the main mode. [done] * Kernel interface for IPsec parameter passing. [done] * Notify of unsupported situations. * Set/get field macros generated from the field descriptions. [done] * SIGHUP handler with reparsing of config file. [done] * RSA signature authentication. [done] * DSS signature authentication. * RSA encryption authentication. * New group mode. * DELETE payload handling, and generation from ui. [generation done] * Deal well with incoming informational exchanges. [done] * Generate all possible SA attributes in quick mode. [done] * Validate incoming attribute according to policy, main mode. [done] * Validate incoming attribute according to policy, quick mode. [done] * Cleanup reserved SPIs on cleanup of associated SAs. [done] * Validate attribute types (i.e. that what the specs tells should be basic). * Cleanup reserved SPIs in proposals never chosen. [done] * Add time measuring and reporting to the exchange code for catching of bottlenecks. * Rescan interfaces on SIGHUP and on reception of messages on the INADDR_ANY listener socket. [done] * Validate the configuration file. * Do a soft-limit on ISAKMP SA lifetime. [done] * Let the hard-limit on ISAKMP SA lifetime destroy the SA ASAP. [done] * IPsec rekeying. [done] * Store tunnels into SPD, and handle acquire SA events. [done] * If an exchange is on-going when a rekey event happens, drop the request. [done] * INITIAL CONTACT notification sending when appropriate. [done] * INITIAL CONTACT notification handling. [done] * IPsec SAs could also do with timers protecting its lifetime, if say, someone changed the lifetime of the IPsec SA in stack under us. [done] * Handle notifications showing the peer did not want to continue this exchange. * Flexible identification. * Remove referring flows when a SPI is removed. [done] * IPCOMP. * Acknowledged notification exchange. * Tiger hash. * El-Gamal public key encryption. * Check of attributes not being changed by the responder in phase 2. * See to the commit bit will never be used in phase 1. Give INVALID-FLAGS if seeing it. * Base mode. * IKECFG [protocol done, configuration controls remain] * XAUTH framework. * PKCS#11 * XAUTH hybrid frame work. * Specify extra certificates to send somehow. * Handle CERTs anywhere in an exchange. * Add a way to do multiple configuration commands via ui. * Replace ui's fifo with a slightly more versatile interface. * Report current configuration. [done] * IPv6 [done] * AES in phase 1 [done] * x509_certreq_validate needs implementing. * Smartcard support. isakmpd-20041012.orig/math_ec2n.h0000644000175000017500000000631410133045740016572 0ustar jdivejdive00000000000000/* $OpenBSD: math_ec2n.h,v 1.7 2004/05/23 18:17:56 hshoexer Exp $ */ /* $EOM: math_ec2n.h,v 1.4 1999/04/17 23:20:37 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _MATH_EC2N_H #define _MATH_EC2N_H_ /* Definitions for points on an elliptic curve */ typedef struct { int inf; /* Are we the point at infinity ? */ b2n_t x, y; } _ec2n_point; typedef _ec2n_point *ec2np_ptr; typedef _ec2n_point ec2np_t[1]; #define EC2NP_SWAP(k,n) do \ { \ int _i_; \ \ _i_ = (k)->inf; \ (k)->inf = (n)->inf; \ (n)->inf = _i_; \ B2N_SWAP ((k)->x, (n)->x); \ B2N_SWAP ((k)->y, (n)->y); \ } \ while (0) void ec2np_init(ec2np_ptr); void ec2np_clear(ec2np_ptr); int ec2np_set(ec2np_ptr, ec2np_ptr); #define ec2np_set_x_ui(n, y) b2n_set_ui ((n)->x, y) #define ec2np_set_y_ui(n, x) b2n_set_ui ((n)->y, x) #define ec2np_set_x_str(n, y) b2n_set_str ((n)->x, y) #define ec2np_set_y_str(n, x) b2n_set_str ((n)->y, x) /* Definitions for the group to which the points to belong to. */ typedef struct { b2n_t a, b, p; } _ec2n_group; typedef _ec2n_group *ec2ng_ptr; typedef _ec2n_group ec2ng_t[1]; void ec2ng_init(ec2ng_ptr); void ec2ng_clear(ec2ng_ptr); int ec2ng_set(ec2ng_ptr, ec2ng_ptr); #define ec2ng_set_a_ui(n, x) b2n_set_ui ((n)->a, x) #define ec2ng_set_b_ui(n, x) b2n_set_ui ((n)->b, x) #define ec2ng_set_p_ui(n, x) b2n_set_ui ((n)->p, x) #define ec2ng_set_a_str(n, x) b2n_set_str ((n)->a, x) #define ec2ng_set_b_str(n, x) b2n_set_str ((n)->b, x) #define ec2ng_set_p_str(n, x) b2n_set_str ((n)->p, x) /* Functions for computing on the elliptic group. */ int ec2np_add(ec2np_ptr, ec2np_ptr, ec2np_ptr, ec2ng_ptr); int ec2np_find_y(ec2np_ptr, ec2ng_ptr); int ec2np_ison(ec2np_ptr, ec2ng_ptr); int ec2np_mul(ec2np_ptr, ec2np_ptr, b2n_ptr, ec2ng_ptr); int ec2np_right(b2n_ptr n, ec2np_ptr, ec2ng_ptr); #endif /* _MATH_2N_H_ */ isakmpd-20041012.orig/log.c0000644000175000017500000004150310133045740015505 0ustar jdivejdive00000000000000/* $OpenBSD: log.c,v 1.49 2004/08/08 19:11:06 deraadt Exp $ */ /* $EOM: log.c,v 1.30 2000/09/29 08:19:23 niklas Exp $ */ /* * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2000, 2001, 2003 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #ifdef USE_DEBUG #include #include #include #include #include #include #include #include #include #ifdef HAVE_PCAP #include #else #include "sysdep/common/pcap.h" #endif #endif /* USE_DEBUG */ #include #include #include #include #include #include #include #include "conf.h" #include "isakmp_num.h" #include "log.h" #include "monitor.h" #include "util.h" static void _log_print(int, int, const char *, va_list, int, int); static FILE *log_output; int verbose_logging = 0; #if defined (USE_DEBUG) static int log_level[LOG_ENDCLASS]; #define TCPDUMP_MAGIC 0xa1b2c3d4 #define SNAPLEN (64 * 1024) struct packhdr { struct pcap_pkthdr pcap;/* pcap file packet header */ u_int32_t sa_family; /* address family */ union { struct ip ip4; /* IPv4 header (w/o options) */ struct ip6_hdr ip6; /* IPv6 header */ } ip; }; struct isakmp_hdr { u_int8_t icookie[8], rcookie[8]; u_int8_t next, ver, type, flags; u_int32_t msgid, len; }; static char *pcaplog_file = NULL; static FILE *packet_log; static u_int8_t *packet_buf = NULL; static int udp_cksum(struct packhdr *, const struct udphdr *, u_int16_t *); static u_int16_t in_cksum(const u_int16_t *, int); #endif /* USE_DEBUG */ void log_init(int debug) { if (debug) log_output = stderr; else log_to(0); /* syslog */ } void log_reinit(void) { struct conf_list *logging; #ifdef USE_DEBUG struct conf_list_node *logclass; int class, level; #endif /* USE_DEBUG */ logging = conf_get_list("General", "Logverbose"); if (logging) { verbose_logging = 1; conf_free_list(logging); } #ifdef USE_DEBUG logging = conf_get_list("General", "Loglevel"); if (!logging) return; for (logclass = TAILQ_FIRST(&logging->fields); logclass; logclass = TAILQ_NEXT(logclass, link)) { if (sscanf(logclass->field, "%d=%d", &class, &level) != 2) { if (sscanf(logclass->field, "A=%d", &level) == 1) for (class = 0; class < LOG_ENDCLASS; class++) log_debug_cmd(class, level); else { log_print("init: invalid logging class or " "level: %s", logclass->field); continue; } } else log_debug_cmd(class, level); } conf_free_list(logging); #endif /* USE_DEBUG */ } void log_to(FILE *f) { if (!log_output && f) closelog(); log_output = f; if (!f) openlog("isakmpd", LOG_PID | LOG_CONS, LOG_DAEMON); } FILE * log_current(void) { return log_output; } static char * _log_get_class(int error_class) { /* XXX For test purposes. To be removed later on? */ static char *class_text[] = LOG_CLASSES_TEXT; if (error_class < 0) return "Dflt"; else if (error_class >= LOG_ENDCLASS) return "Unkn"; else return class_text[error_class]; } static void _log_print(int error, int syslog_level, const char *fmt, va_list ap, int class, int level) { char buffer[LOG_SIZE], nbuf[LOG_SIZE + 32]; static const char fallback_msg[] = "write to log file failed (errno %d), redirecting to syslog"; int len; struct tm *tm; struct timeval now; time_t t; len = vsnprintf(buffer, sizeof buffer, fmt, ap); if (len > 0 && len < (int) sizeof buffer - 1 && error) snprintf(buffer + len, sizeof buffer - len, ": %s", strerror(errno)); if (log_output) { gettimeofday(&now, 0); t = now.tv_sec; tm = localtime(&t); if (class >= 0) snprintf(nbuf, sizeof nbuf, "%02d%02d%02d.%06ld %s %02d ", tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec, _log_get_class(class), level); else /* LOG_PRINT (-1) or LOG_REPORT (-2) */ snprintf(nbuf, sizeof nbuf, "%02d%02d%02d.%06ld %s ", tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec, class == LOG_PRINT ? "Default" : "Report>"); strlcat(nbuf, buffer, sizeof nbuf); #if defined (USE_PRIVSEP) strlcat(nbuf, getuid() ? "" : " [priv]", LOG_SIZE + 32); #endif strlcat(nbuf, "\n", sizeof nbuf); if (fwrite(nbuf, strlen(nbuf), 1, log_output) == 0) { /* Report fallback. */ syslog(LOG_ALERT, fallback_msg, errno); fprintf(log_output, fallback_msg, errno); /* * Close log_output to prevent isakmpd from locking * the file. We may need to explicitly close stdout * to do this properly. * XXX - Figure out how to match two FILE *'s and * rewrite. */ if (fileno(log_output) != -1 && fileno(stdout) == fileno(log_output)) fclose(stdout); fclose(log_output); /* Fallback to syslog. */ log_to(0); /* (Re)send current message to syslog(). */ syslog(class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s", buffer); } } else syslog(class == LOG_REPORT ? LOG_ALERT : syslog_level, "%s", buffer); } #ifdef USE_DEBUG void log_debug(int cls, int level, const char *fmt, ...) { va_list ap; /* * If we are not debugging this class, or the level is too low, just * return. */ if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) return; va_start(ap, fmt); _log_print(0, LOG_INFO, fmt, ap, cls, level); va_end(ap); } void log_debug_buf(int cls, int level, const char *header, const u_int8_t *buf, size_t sz) { size_t i, j; char s[73]; /* * If we are not debugging this class, or the level is too low, just * return. */ if (cls >= 0 && (log_level[cls] == 0 || level > log_level[cls])) return; log_debug(cls, level, "%s:", header); for (i = j = 0; i < sz;) { snprintf(s + j, sizeof s - j, "%02x", buf[i++]); j += 2; if (i % 4 == 0) { if (i % 32 == 0) { s[j] = '\0'; log_debug(cls, level, "%s", s); j = 0; } else s[j++] = ' '; } } if (j) { s[j] = '\0'; log_debug(cls, level, "%s", s); } } void log_debug_cmd(int cls, int level) { if (cls < 0 || cls >= LOG_ENDCLASS) { log_print("log_debug_cmd: invalid debugging class %d", cls); return; } if (level < 0) { log_print("log_debug_cmd: invalid debugging level %d for " "class %d", level, cls); return; } if (level == log_level[cls]) log_print("log_debug_cmd: log level unchanged for class %d", cls); else { log_print("log_debug_cmd: log level changed from %d to %d " "for class %d", log_level[cls], level, cls); log_level[cls] = level; } } void log_debug_toggle(void) { static int log_level_copy[LOG_ENDCLASS], toggle = 0; if (!toggle) { LOG_DBG((LOG_MISC, 50, "log_debug_toggle: " "debug levels cleared")); memcpy(&log_level_copy, &log_level, sizeof log_level); memset(&log_level, 0, sizeof log_level); } else { memcpy(&log_level, &log_level_copy, sizeof log_level); LOG_DBG((LOG_MISC, 50, "log_debug_toggle: " "debug levels restored")); } toggle = !toggle; } #endif /* USE_DEBUG */ void log_print(const char *fmt, ...) { va_list ap; va_start(ap, fmt); _log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0); va_end(ap); } void log_verbose(const char *fmt, ...) { va_list ap; #ifdef USE_DEBUG int i; #endif /* USE_DEBUG */ if (verbose_logging == 0) return; #ifdef USE_DEBUG for (i = 0; i < LOG_ENDCLASS; i++) if (log_level[i] > 0) return; #endif va_start(ap, fmt); _log_print(0, LOG_NOTICE, fmt, ap, LOG_PRINT, 0); va_end(ap); } void log_error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); _log_print(1, LOG_ERR, fmt, ap, LOG_PRINT, 0); va_end(ap); } void log_fatal(const char *fmt, ...) { va_list ap; va_start(ap, fmt); _log_print(1, LOG_CRIT, fmt, ap, LOG_PRINT, 0); va_end(ap); #ifdef USE_PRIVSEP monitor_exit(1); #else exit(1); #endif } #ifdef USE_DEBUG void log_packet_init(char *newname) { struct pcap_file_header sf_hdr; struct stat st; mode_t old_umask; char *mode; /* Allocate packet buffer first time through. */ if (!packet_buf) packet_buf = malloc(SNAPLEN); if (!packet_buf) { log_error("log_packet_init: malloc (%d) failed", SNAPLEN); return; } if (pcaplog_file && strcmp(pcaplog_file, PCAP_FILE_DEFAULT) != 0) free(pcaplog_file); pcaplog_file = strdup(newname); if (!pcaplog_file) { log_error("log_packet_init: strdup (\"%s\") failed", newname); return; } /* Does the file already exist? XXX lstat() or stat()? */ #if defined (USE_PRIVSEP) /* XXX This is a fstat! */ if (monitor_stat(pcaplog_file, &st) == 0) { #else if (lstat(pcaplog_file, &st) == 0) { #endif /* Sanity checks. */ if ((st.st_mode & S_IFMT) != S_IFREG) { log_print("log_packet_init: existing capture file is " "not a regular file"); return; } if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) { log_print("log_packet_init: existing capture " "file has bad modes"); return; } /* * XXX It would be nice to check if it actually is a pcap * file... */ mode = "a"; } else mode = "w"; old_umask = umask(S_IRWXG | S_IRWXO); packet_log = monitor_fopen(pcaplog_file, mode); umask(old_umask); if (!packet_log) { log_error("log_packet_init: fopen (\"%s\", \"%s\") failed", pcaplog_file, mode); return; } log_print("log_packet_init: " "starting IKE packet capture to file \"%s\"", pcaplog_file); /* If this is a new file, we need to write a PCAP header to it. */ if (*mode == 'w') { sf_hdr.magic = TCPDUMP_MAGIC; sf_hdr.version_major = PCAP_VERSION_MAJOR; sf_hdr.version_minor = PCAP_VERSION_MINOR; sf_hdr.thiszone = 0; sf_hdr.snaplen = SNAPLEN; sf_hdr.sigfigs = 0; sf_hdr.linktype = DLT_LOOP; fwrite((char *) &sf_hdr, sizeof sf_hdr, 1, packet_log); fflush(packet_log); } } void log_packet_restart(char *newname) { if (packet_log) { log_print("log_packet_restart: capture already active on " "file \"%s\"", pcaplog_file); return; } if (newname) log_packet_init(newname); else if (!pcaplog_file) log_packet_init(PCAP_FILE_DEFAULT); else log_packet_init(pcaplog_file); } void log_packet_stop(void) { /* Stop capture. */ if (packet_log) { fclose(packet_log); log_print("log_packet_stop: stopped capture"); } packet_log = 0; } void log_packet_iov(struct sockaddr *src, struct sockaddr *dst, struct iovec *iov, int iovcnt) { struct isakmp_hdr *isakmphdr; struct packhdr hdr; struct udphdr udp; struct timeval tv; int off, datalen, hdrlen, i, add_espmarker = 0; const u_int32_t espmarker = 0; for (i = 0, datalen = 0; i < iovcnt; i++) datalen += iov[i].iov_len; if (!packet_log || datalen > SNAPLEN) return; /* copy packet into buffer */ for (i = 0, off = 0; i < iovcnt; i++) { memcpy(packet_buf + off, iov[i].iov_base, iov[i].iov_len); off += iov[i].iov_len; } memset(&hdr, 0, sizeof hdr); memset(&udp, 0, sizeof udp); /* isakmp - turn off the encryption bit in the isakmp hdr */ isakmphdr = (struct isakmp_hdr *) packet_buf; isakmphdr->flags &= ~(ISAKMP_FLAGS_ENC); /* udp */ udp.uh_sport = sockaddr_port(src); udp.uh_dport = sockaddr_port(dst); datalen += sizeof udp; #if defined (USE_NAT_TRAVERSAL) if (ntohs(udp.uh_sport) == 4500 || ntohs(udp.uh_dport) == 4500) { /* XXX Quick and dirty */ add_espmarker = 1; datalen += sizeof espmarker; } #endif udp.uh_ulen = htons(datalen); /* ip */ hdr.sa_family = htonl(src->sa_family); switch (src->sa_family) { default: /* Assume IPv4. XXX Can 'default' ever happen here? */ hdr.sa_family = htonl(AF_INET); hdr.ip.ip4.ip_src.s_addr = 0x02020202; hdr.ip.ip4.ip_dst.s_addr = 0x01010101; /* The rest of the setup is common to AF_INET. */ goto setup_ip4; case AF_INET: hdr.ip.ip4.ip_src.s_addr = ((struct sockaddr_in *)src)->sin_addr.s_addr; hdr.ip.ip4.ip_dst.s_addr = ((struct sockaddr_in *)dst)->sin_addr.s_addr; setup_ip4: hdrlen = sizeof hdr.ip.ip4; hdr.ip.ip4.ip_v = 0x4; hdr.ip.ip4.ip_hl = 0x5; hdr.ip.ip4.ip_p = IPPROTO_UDP; hdr.ip.ip4.ip_len = htons(datalen + hdrlen); /* Let's use the IP ID as a "packet counter". */ i = ntohs(hdr.ip.ip4.ip_id) + 1; hdr.ip.ip4.ip_id = htons(i); /* Calculate IP header checksum. */ hdr.ip.ip4.ip_sum = in_cksum((u_int16_t *) & hdr.ip.ip4, hdr.ip.ip4.ip_hl << 2); break; case AF_INET6: hdrlen = sizeof(hdr.ip.ip6); hdr.ip.ip6.ip6_vfc = IPV6_VERSION; hdr.ip.ip6.ip6_nxt = IPPROTO_UDP; hdr.ip.ip6.ip6_plen = udp.uh_ulen; memcpy(&hdr.ip.ip6.ip6_src, &((struct sockaddr_in6 *)src)->sin6_addr, sizeof hdr.ip.ip6.ip6_src); memcpy(&hdr.ip.ip6.ip6_dst, &((struct sockaddr_in6 *)dst)->sin6_addr, sizeof hdr.ip.ip6.ip6_dst); break; } /* Calculate UDP checksum. */ udp.uh_sum = udp_cksum(&hdr, &udp, (u_int16_t *) packet_buf); hdrlen += sizeof hdr.sa_family; /* pcap file packet header */ gettimeofday(&tv, 0); hdr.pcap.ts.tv_sec = tv.tv_sec; hdr.pcap.ts.tv_usec = tv.tv_usec; hdr.pcap.caplen = datalen + hdrlen; hdr.pcap.len = datalen + hdrlen; hdrlen += sizeof(struct pcap_pkthdr); datalen -= sizeof(struct udphdr); /* Write to pcap file. */ fwrite(&hdr, hdrlen, 1, packet_log); /* pcap + IP */ fwrite(&udp, sizeof(struct udphdr), 1, packet_log); /* UDP */ if (add_espmarker) { fwrite(&espmarker, sizeof espmarker, 1, packet_log); datalen -= sizeof espmarker; } fwrite(packet_buf, datalen, 1, packet_log); /* IKE-data */ fflush(packet_log); } /* Copied from tcpdump/print-udp.c, mostly rewritten. */ static int udp_cksum(struct packhdr *hdr, const struct udphdr *u, u_int16_t *d) { struct ip *ip4; struct ip6_hdr *ip6; int i, hdrlen, tlen = ntohs(u->uh_ulen) - sizeof(struct udphdr); union phu { struct ip4pseudo { struct in_addr src; struct in_addr dst; u_int8_t z; u_int8_t proto; u_int16_t len; } ip4p; struct ip6pseudo { struct in6_addr src; struct in6_addr dst; u_int32_t plen; u_int16_t z0; u_int8_t z1; u_int8_t nxt; } ip6p; u_int16_t pa[20]; } phu; const u_int16_t *sp; u_int32_t sum; /* Setup pseudoheader. */ memset(phu.pa, 0, sizeof phu); switch (ntohl(hdr->sa_family)) { case AF_INET: ip4 = &hdr->ip.ip4; memcpy(&phu.ip4p.src, &ip4->ip_src, sizeof(struct in_addr)); memcpy(&phu.ip4p.dst, &ip4->ip_dst, sizeof(struct in_addr)); phu.ip4p.proto = ip4->ip_p; phu.ip4p.len = u->uh_ulen; hdrlen = sizeof phu.ip4p; break; case AF_INET6: ip6 = &hdr->ip.ip6; memcpy(&phu.ip6p.src, &ip6->ip6_src, sizeof(phu.ip6p.src)); memcpy(&phu.ip6p.dst, &ip6->ip6_dst, sizeof(phu.ip6p.dst)); phu.ip6p.plen = u->uh_ulen; phu.ip6p.nxt = ip6->ip6_nxt; hdrlen = sizeof phu.ip6p; break; default: return 0; } /* IPv6 wants a 0xFFFF checksum "on error", not 0x0. */ if (tlen < 0) return (ntohl(hdr->sa_family) == AF_INET ? 0 : 0xFFFF); sum = 0; for (i = 0; i < hdrlen; i += 2) sum += phu.pa[i / 2]; sp = (u_int16_t *) u; for (i = 0; i < (int)sizeof(struct udphdr); i += 2) sum += *sp++; sp = d; for (i = 0; i < (tlen & ~1); i += 2) sum += *sp++; if (tlen & 1) sum += htons((*(const char *)sp) << 8); while (sum > 0xffff) sum = (sum & 0xffff) + (sum >> 16); sum = ~sum & 0xffff; return sum; } /* Copied from tcpdump/print-ip.c, modified. */ static u_int16_t in_cksum(const u_int16_t *w, int len) { int nleft = len, sum = 0; u_int16_t answer; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) sum += htons(*(u_char *) w << 8); sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return answer; } #endif /* USE_DEBUG */ isakmpd-20041012.orig/timer.h0000644000175000017500000000412210133045740016045 0ustar jdivejdive00000000000000/* $OpenBSD: timer.h,v 1.7 2004/05/23 18:17:56 hshoexer Exp $ */ /* $EOM: timer.h,v 1.6 1999/04/11 22:35:55 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _TIMER_H_ #define _TIMER_H_ #include #include #include struct event { TAILQ_ENTRY(event) link; char *name; void (*func) (void *); void *arg; struct timeval expiration; }; extern void timer_init(void); extern void timer_next_event(struct timeval **); extern void timer_handle_expirations(void); extern struct event *timer_add_event(char *, void (*) (void *), void *, struct timeval *); extern void timer_remove_event(struct event *); extern void timer_report(void); #endif /* _TIMER_H_ */ isakmpd-20041012.orig/constants.c0000644000175000017500000000550110133045740016736 0ustar jdivejdive00000000000000/* $OpenBSD: constants.c,v 1.9 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: constants.c,v 1.7 1999/04/02 00:57:31 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include "sysdep.h" #include "constants.h" int constant_value(struct constant_map *map, char *name) { struct constant_map *entry = map; for (entry = map; entry->name; entry++) if (strcasecmp(entry->name, name) == 0) return entry->value; return 0; } char * constant_lookup(struct constant_map *map, int value) { struct constant_map *entry = map; for (entry = map; entry->name; entry++) if (entry->value == value) return entry->name; return 0; } struct constant_map * constant_link_lookup(struct constant_map *map, int value) { struct constant_map *entry = map; for (entry = map; entry->name; entry++) if (entry->value == value) return entry->link; return 0; } char * constant_name(struct constant_map *map, int value) { static char tmp[32];/* XXX Ugly, I know. */ char *retval = constant_lookup(map, value); if (!retval) { snprintf(tmp, sizeof tmp, "", value); return tmp; } return retval; } char * constant_name_maps(struct constant_map **maps, int value) { static char tmp[32];/* XXX Ugly, I know. */ char *retval; struct constant_map **map; for (map = maps; *map; map++) { retval = constant_lookup(*map, value); if (retval) return retval; } snprintf(tmp, sizeof tmp, "", value); return tmp; } isakmpd-20041012.orig/dpd.h0000644000175000017500000000315610133045740015502 0ustar jdivejdive00000000000000/* $OpenBSD: dpd.h,v 1.2 2004/08/10 15:59:10 ho Exp $ */ /* * Copyright (c) 2004 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. * * 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. */ #ifndef _DPD_H_ #define _DPD_H_ struct message; struct payload; struct sa; int dpd_add_vendor_payload(struct message *); void dpd_check_vendor_payload(struct message *, struct payload *); void dpd_handle_notify(struct message *, struct payload *); #endif /* _DPD_H_ */ isakmpd-20041012.orig/DESIGN-NOTES0000644000175000017500000003777210133045740016357 0ustar jdivejdive00000000000000$OpenBSD: DESIGN-NOTES,v 1.22 2003/06/04 07:27:31 ho Exp $ $EOM: DESIGN-NOTES,v 1.48 1999/08/12 22:34:25 niklas Exp $ General coding conventions -------------------------- GNU indentation, Max 80 characters per line, KNF comments, mem* instead of b*, BSD copyright, one header per module specifying the API. Multiple inclusion protection like this: #ifndef _HEADERNAME_H_ #define _HEADERNAME_H_ ... Here comes the bulk of the header ... #endif /* _HEADERNAME_H_ */ Start all files with RCS ID tags. GCC -Wall clean, ANSI prototypes. System dependent facilities should be named sysdep_* and be placed in sysdep.c. Every C file should include sysdep.h as the first isakmpd include file. Primary target systems are OpenBSD and Linux, but porting to Microsoft Windows variants should not be made overly difficult. Note places which need reconsiderations with comments starting with the string "XXX", e.g. /* XXX Not implemented yet. */ TOC --- app.c Application support. attribute.c Attribute handling. cert.c Dispatching certificate related functions to the according module based on the encoding. conf.c Interface to isakmpd configuration. connection.c Handle the high-level connection concept. constants.c Value to name map of constants. cookie.c Cookie generation. crypto.c Generic cryptography. dh.c Diffie-Hellman exchange logic. dnssec.c IKE authentication using signed DNS KEY RRs. doi.c Generic handling of different DOIs. exchange.c Exchange state machinery. exchange_num.cst Some constants used for exhange scripts. field.c Generic handling of fields. genconstants.sh Generate constant files from .cst source. genfields.sh Generate field description files from .fld source. gmp_util.c Utilities to ease interfaceing to GMP. hash.c Generic hash handling. if.c Network interface details. ike_aggressive.c IKE's aggressive mode exchange logic. ike_auth.c IKE authentication method abstraction. ike_main_mode.c IKE's main mode exchange logic. ike_phase_1.c Common parts IKE's main & aggressive modes' exchange logic. ike_quick_mode.c IKE's quick mode logic. init.c Initialization of all modules (might be autogenned in the future). ipsec.c The IPsec DOI. ipsec_fld.fld Description of IPsec DOI-specific packet layouts. ipsec_num.cst Constants defined by the IPsec DOI. isakmp_doi.c The ISAKMP pseudo-DOI. isakmp_fld.fld Generic packet layout. isakmp_num.cst ISAKMP constants. isakmpd.c Main loop. key.c Generic key handling. libcrypto.c Initialize crypto (OpenSSL). log.c Logging of exceptional or informational messages. math_2n.c Polynomial math. math_ec2n.c Elliptic curve math. math_group.c Group math. message.c Generic message handling. pf_key_v2.c Interface with PF_KEY sockets (for use with IPsec). policy.c Keynote glue. prf.c Pseudo random functions. sa.c Handling of Security Associations (SAs). sysdep/*/sysdep.c System dependent stuff. timer.c Timed events. transport.c Generic transport handling. udp.c The UDP transport. ui.c The "User Interface", i.e. the FIFO command handler. util.c Miscellaneous utility functions. x509.c Encoding/Decoding X509 Certificates and related structures. Central datatypes ----------------- struct connection Persistent connections. struct constant_map A map from constants to their ASCII names. struct crypto_xf A crypto class struct doi The DOI function switch struct event An event that is to happen at some point in time. struct exchange A description of an exchange while it is performed. struct field A description of an ISAKMP field. struct group A class abstracting out Oakley group operations struct hash A hashing class struct ipsec_exch IPsec-specific exchange fields. struct ipsec_proto IPsec-specific protocol attributes. struct ipsec_sa IPsec-specific SA stuff. struct message A generic ISAKMP message. struct payload A "fat" payload reference pointing into message buffers struct prf A pseudo random function class struct proto Per-protocol attributes. struct post_send Post-send function chain node. struct sa A security association. struct transport An ISAKMP transport, i.e. a channel where ISAKMP messages are passed (not necessarily connection- oriented). This is an abstract class, serving as a superclass to the different specific transports. SAs & exchanges --------------- struct exchange Have all fields belonging to a simple exchange + a list of all the SAs being negotiated. Short-lived. struct sa Only hold SA-specific stuff. Lives longer. In order to recognize exchanges and SAs it is good to know what constitutes their identities: Phase 1 exchange Cookie pair (apart from the first message of course, where the responder cookie is zero. ISAKMP SA Cookie pair. I.e. there exists a one-to-one mapping to the negotiation in this case. Phase 2 exchange Cookie pair + message ID. Generic SA Cookie pair + message ID + SPI. However it would be really nice to have a name of any SA that is natural to use for human beings, for things like deleting SAs manually. The simplest ID would be the struct sa address. Another idea would be some kind of sequence number, either global or per-destination. Right now I have introduced a name for SAs, non-unique, that binds together SAs and their configuration parameters. This means both manual exchange runs and rekeying are simpler. Both struct exchange and struct sa does hold a reference count, but this is not entirely like a reference count in the traditional meaning where every reference gets counted. Perhaps it will be in the future, but for now we increment the count at allocation time and at times we schedule events tha might happen sometime in the future where we will need the structure. These events then realeases its reference when done. This way intermediate deallocation of these structures are OK. The basic idea of control flow ------------------------------ The main loop just waits for events of any kind. Supposedly a message comes in, then the daemon looks to see if the cookies describes an existing ISAKMP SA, if they don't and the rcookie is zero, it triggers a setup of a new ISAKMP SA. An exhaustive validation phase of the message is gone through at this stage. If anything goes wrong, we drop the packet and probably send some notification back. After the SA is found we try to locate the exchange object and advance its state, else we try to create a new exchange. Need exchanges be an abstraction visible in the code? If so an exchange is roughly a very simple FSM (only timeouts and retransmissions are events that does not just advance the state through a sequential single path). The informational exchange is such a special case, I am not sure it's interesting to treat as an exchange in the logic of the implementation. The only reason to do so would be to keep the implementation tightly coupled to the specification for ease of understanding. As the code looks now, exchanges *are* an abstraction in the code, and it has proven to be a rather nice way of having things. When the exchange has been found the exchange engine "runs" a script which steps forward for each incoming message, and on each reply to them. Payload parsing details ----------------------- After the generic header has been validated, we do a generic payload parsing pass over the message and sort out the payloads into buckets indexed by the payload type. Note that proposals and transforms are part of the SA payloads. We then pass over them once more validating each payload in numeric payload type order. This makes SA payloads come naturally first. Messages -------- I am not sure there is any use in sharing the message structure for both incoming and outgoing messages but I do it anyhow. Specifically there are certain fields which only makes sense in one direction. Incoming messages only use one segment in the iovec vector, while outgoing has one segment per payload as well as one for the ISAKMP header. The iovec vector is reallocated for each payload added, maybe we should do it in chunks of a number of payloads instead, like 10 or so. Design "errors" --------------- Currently there are two "errors" in our design. The first one is that the coupling between the IPsec DOI and IKE is tight. It should be separated by a clean interface letting other key exchange models fit in instead of IKE. The second problem is that we need a protocol-specific opaque SA part in the DOI specific one. Now both IPsec ESP attributes takes place even in ISAKMP SA structures. User control ------------ In order to control the daemon you send commands through a FIFO called isakmpd.fifo. The commands are one-letter codes followed by arguments. For now, eleven such commands are implemented: c connect Establish a connection with a peer C configure Add or remove configuration entries d delete Delete an SA given cookies and message-IDs D debug Change logging level for a debug class p packet capture Enable/disable packet capture feature r report Report status information of the daemon t teardown Teardown a connection Q quit Quit the isakmpd process R reinitialize Reinitialize isakmpd (re-read configuration file) S report SA Report SA information to file /var/run/isakmp_sa T teardown all Teardown all Phase 2 connections For example you can do: c ISAKMP-peer In order to delete an SA you use the 'd' command. However this is not yet supported. To alter the level of debugging in the "LOG_MISC" logging class to 99 you do: D 0 99 The report command is just an "r", and results in a list of active exchanges and security associations. The "C" command takes 3 subcommands: set, rm and rms, for adding and removing entries + remove complete sections respectively. Examples: C set [Net-A]:Address=192.168.0.0 C rm [Net-A]:Address C rms [Net-A] All these commands are atomic, i.e. they are not collected into larger transactions, which there should be a way to do, but currently isn't. The FIFO UI is also described in the isakmpd(8) man page. In addition to giving commands over the FIFO, you may send signals to the daemon. Currently two such signals are implemented: SIGHUP Re-initialize isakmpd (not fully implemented yet) SIGUSR1 Generate a report, much as the "r" FIFO command. For example, to generate a report, you do: unix# kill -USR1 The constant descriptions ------------------------- We have invented a simple constant description language, for the sake of easily getting textual representations of manifest constants. The syntax is best described by an example: GROUP CONSTANT_A 1 CONSTANT_B 2 . This defines a constant map "group" with the following two defines: #define GROUP_CONSTANT_A 1 #define GROUP_CONSTANT_B 2 We can now get the textual representation by: cp = constant_name (group, foo); Here foo is an integer with either of the two constants as a value. The field descriptions ---------------------- There is language for describing header and payload layouts too, similar to the constant descriptions. Here too I just show an example: RECORD_A FIELD_A raw 4 FIELD_B num 2 FIELD_C mask 1 group_c_cst FIELD_D ign 1 FIELD_E cst 2 group_e1_cst,group_e2_cst . RECORD_B : RECORD_A FIELD_F raw . This creates some utility constants like RECORD_A_SZ, RECORD_A_FIELD_A_LEN, RECORD_A_FIELD_A_OFF, RECORD_A_FIELD_B_LEN etc. The *_OFF contains the octet offset into the record and the *_LEN constants are the lengths. The type fields can be: raw, num, mask, ign & cst. Raw are used for octet buffers, num for (unsigned) numbers of 1, 2 or 4 octet's length in network byteorder, mask is a bitmask where the bit values have symbols coupled to them via the constant maps given after the length in octets (also 1, 2 or 4). Ign is just a filler type, ot padding and lastly cst denotes constants whose values can be found in the given constant map(s). The last field in a record can be a raw, without a length, then just an _OFF symbol will be generated. You can offset the first symbol to the size of another record, like is done above for RECORD_B, i.e. in that case RECORD_A_SZ == RECORD_B_FIELD_F_OFF. All this data are collected in struct field arrays which makes it possible to symbolically print out entire payloads in readable form via field_dump_payload. Configuration ------------- Internally isakmpd uses a section-tag-value triplet database for configuration. Currently this happen to map really well to the configuration file format, which on the other hand does not map equally well to humans. It is envisioned that the configuration database should be dynamically modifiable, and through a lot of differnet mechanisms. Therefore we have designed an API for this purpose. int conf_begin (); int conf_set (int transaction, char *section, char *tag, char *value, int override); int conf_remove (int transaction, char *section, char *tag); int conf_remove_section (int transaction, char *section); int conf_end (int transaction, int commit); The caller will always be responsible for the memory management of the passed strings, conf_set will copy the values, and not use the original strings after it has returned. Return value will be zero on success and non-zero otherwise. Note that the conf_remove* functions consider not finding anything to remove as failure. Identification -------------- ISAKMP supports a lot of identity types, and we should too of course. * Phase 1, Main mode or Aggressive mode Today when we connect we do it based on the peer's IP address. That does not automatically mean we should do policy decision based on IPs, rather we should look at the ID the peer provide and get policy info keyed on that. Perhaps we get an ID saying the peer is FQDN niklas.hallqvist.se, then our policy rules might look like: [IQ_FQDN] # If commented, internal verification is used #Verificator= verify_fqdn Accept= no [ID_FQDN niklas.hallqvist.se] Policy= MY_POLICY_001 [MY_POLICY_001] # Whatever policy rules we might have. Accept= yes Which means niklas.hallqvist.se is allowed to negotiate SAs with us, but noone else. * Phase 2, Quick mode In quick mode the identities are implicitly the IP addresses of the peers, which must mean the IP addresses actually used for the ISAKMP tunnel. Otherwise we today support IPV4_ADDR & IPV4_ADDR_SUBNET as ID types. X509-Certificates ----------------- To use RSA Signature mode you are required to generate certificates. This can be done with ssleay, see man ssl. But the X509 certificates require a subjectAltname extension that can either be an IPV4 address, a User-FQDN or just FQDN. ssleay can not create those extension, insead use the x509test program in regress/x509 to modify an existing certificate. It will insert the subjectAltname extension and sign it with the provided private Key. The resulting certificate then needs to be stored in the directory pointed to by "Certs-directory" in section "X509-certificates". License to use -------------- /* * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ isakmpd-20041012.orig/conf.h0000644000175000017500000000774510133045740015670 0ustar jdivejdive00000000000000/* $OpenBSD: conf.h,v 1.30 2004/06/25 20:25:34 hshoexer Exp $ */ /* $EOM: conf.h,v 1.13 2000/09/18 00:01:47 ho Exp $ */ /* * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2000, 2003 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _CONF_H_ #define _CONF_H_ #include #include #include #include #define ISAKMPD_ROOT "/etc/isakmpd/" #define CONFIG_FILE ISAKMPD_ROOT "isakmpd.conf" /* Default values for autogenerated part of our configuration. */ #define CONF_DFLT_TAG_LIFE_MAIN_MODE "LIFE_MAIN_MODE" #define CONF_DFLT_TYPE_LIFE_MAIN_MODE "SECONDS" #define CONF_DFLT_VAL_LIFE_MAIN_MODE "3600,60:86400" #define CONF_DFLT_TAG_LIFE_QUICK_MODE "LIFE_QUICK_MODE" #define CONF_DFLT_TYPE_LIFE_QUICK_MODE "SECONDS" #define CONF_DFLT_VAL_LIFE_QUICK_MODE "1200,60:86400" #define CONF_DFLT_VAL_BLF_KEYLEN "128,96:192" #define CONF_DFLT_VAL_AES_KEYLEN "128,128:256" #define CONF_DFLT_RETRANSMITS "3" #define CONF_DFLT_EXCH_MAX_TIME "120" #define CONF_DFLT_USE_KEYNOTE "yes" #define CONF_DFLT_POLICY_FILE ISAKMPD_ROOT "isakmpd.policy" #define CONF_DFLT_X509_CA_DIR ISAKMPD_ROOT "ca/" #define CONF_DFLT_X509_CERT_DIR ISAKMPD_ROOT "certs/" #define CONF_DFLT_X509_PRIVATE_KEY ISAKMPD_ROOT "private/local.key" #define CONF_DFLT_X509_CRL_DIR ISAKMPD_ROOT "crls/" #define CONF_DFLT_PUBKEY_DIR ISAKMPD_ROOT "pubkeys/" #define CONF_DFLT_KEYNOTE_CRED_DIR ISAKMPD_ROOT "keynote/" #define CONF_DFLT_TAG_PHASE1_CONFIG "Default-phase-1-configuration" #define CONF_DFLT_PHASE1_EXCH_TYPE "ID_PROT" #define CONF_DFLT_PHASE1_TRANSFORMS "3DES-SHA-RSA_SIG" struct conf_list_node { TAILQ_ENTRY(conf_list_node) link; char *field; }; struct conf_list { size_t cnt; TAILQ_HEAD(conf_list_fields_head, conf_list_node) fields; }; extern char *conf_path; extern int conf_begin(void); extern int conf_decode_base64(u_int8_t *, u_int32_t *, u_char *); extern int conf_end(int, int); extern void conf_free_list(struct conf_list *); extern struct sockaddr *conf_get_address(char *, char *); extern struct conf_list *conf_get_list(char *, char *); extern struct conf_list *conf_get_tag_list(char *); extern int conf_get_num(char *, char *, int); extern char *conf_get_str(char *, char *); extern void conf_init(void); extern int conf_match_num(char *, char *, int); extern void conf_reinit(void); extern int conf_remove(int, char *, char *); extern int conf_remove_section(int, char *); extern int conf_set(int, char *, char *, char *, int, int); extern void conf_report(void); #endif /* _CONF_H_ */ isakmpd-20041012.orig/prf.c0000644000175000017500000001054610133045740015516 0ustar jdivejdive00000000000000/* $OpenBSD: prf.c,v 1.14 2004/05/23 18:17:56 hshoexer Exp $ */ /* $EOM: prf.c,v 1.7 1999/05/02 12:50:29 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include "sysdep.h" #include "hash.h" #include "log.h" #include "prf.h" void prf_hash_init(struct prf_hash_ctx *); void prf_hash_update(struct prf_hash_ctx *, unsigned char *, unsigned int); void prf_hash_final(unsigned char *, struct prf_hash_ctx *); /* PRF behaves likes a hash */ void prf_hash_init(struct prf_hash_ctx *ctx) { memcpy(ctx->hash->ctx, ctx->ctx, ctx->hash->ctxsize); memcpy(ctx->hash->ctx2, ctx->ctx2, ctx->hash->ctxsize); } void prf_hash_update(struct prf_hash_ctx *ctx, unsigned char *data, unsigned int len) { ctx->hash->Update(ctx->hash->ctx, data, len); } void prf_hash_final(unsigned char *digest, struct prf_hash_ctx *ctx) { ctx->hash->HMACFinal(digest, ctx->hash); } /* * Obtain a Pseudo-Random Function for us. At the moment this is * the HMAC version of a hash. See RFC-2104 for reference. */ struct prf * prf_alloc(enum prfs type, int subtype, unsigned char *shared, unsigned int sharedsize) { struct hash *hash; struct prf *prf; struct prf_hash_ctx *prfctx; switch (type) { case PRF_HMAC: hash = hash_get(subtype); if (!hash) { log_print("prf_alloc: unknown hash type %d", subtype); return 0; } break; default: log_print("prf_alloc: unknown PRF type %d", type); return 0; } prf = malloc(sizeof *prf); if (!prf) { log_error("prf_alloc: malloc (%lu) failed", (unsigned long)sizeof *prf); return 0; } if (type == PRF_HMAC) { /* Obtain needed memory. */ prfctx = malloc(sizeof *prfctx); if (!prfctx) { log_error("prf_alloc: malloc (%lu) failed", (unsigned long)sizeof *prfctx); goto cleanprf; } prf->prfctx = prfctx; prfctx->ctx = malloc(hash->ctxsize); if (!prfctx->ctx) { log_error("prf_alloc: malloc (%d) failed", hash->ctxsize); goto cleanprfctx; } prfctx->ctx2 = malloc(hash->ctxsize); if (!prfctx->ctx2) { log_error("prf_alloc: malloc (%d) failed", hash->ctxsize); free(prfctx->ctx); goto cleanprfctx; } prf->type = PRF_HMAC; prf->blocksize = hash->hashsize; prfctx->hash = hash; /* Use the correct function pointers. */ prf->Init = (void(*)(void *))prf_hash_init; prf->Update = (void(*)(void *, unsigned char *, unsigned int))prf_hash_update; prf->Final = (void(*)(unsigned char *, void *))prf_hash_final; /* Init HMAC contexts. */ hash->HMACInit(hash, shared, sharedsize); /* Save contexts. */ memcpy(prfctx->ctx, hash->ctx, hash->ctxsize); memcpy(prfctx->ctx2, hash->ctx2, hash->ctxsize); } return prf; cleanprfctx: free(prf->prfctx); cleanprf: free(prf); return 0; } /* Deallocate the PRF pointed to by PRF. */ void prf_free(struct prf *prf) { struct prf_hash_ctx *prfctx = prf->prfctx; if (prf->type == PRF_HMAC) { free(prfctx->ctx2); free(prfctx->ctx); } free(prf->prfctx); free(prf); } isakmpd-20041012.orig/genconstants.sh0000644000175000017500000000537310133045740017627 0ustar jdivejdive00000000000000# $OpenBSD: genconstants.sh,v 1.12 2004/04/15 18:39:25 deraadt Exp $ # $EOM: genconstants.sh,v 1.6 1999/04/02 01:15:53 niklas Exp $ # # Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # base=`basename $1` upcased_name=`echo $base |tr a-z A-Z` awk=${AWK:-awk} locase_function='function locase (str) { cmd = "echo " str " |tr A-Z a-z" cmd | getline retval; close (cmd); return retval; }' $awk " $locase_function "' BEGIN { print "/* DO NOT EDIT-- this file is automatically generated. */\n" print "#ifndef _'$upcased_name'_H_" print "#define _'$upcased_name'_H_\n" print "#include \"sysdep.h\"\n" print "#include \"constants.h\"\n" } /^[#.]/ { next } /^[^ ]/ { prefix = $1 printf ("extern struct constant_map %s_cst[];\n\n", locase(prefix)); next } /^[ ]/ && $1 { printf ("#define %s_%s %s\n", prefix, $1, $2) next } { print } END { printf ("\n") print "#endif /* _'$upcased_name'_H_ */" } ' <$1.cst >$base.h $awk " $locase_function "' BEGIN { print "/* DO NOT EDIT-- this file is automatically generated. */\n" print "#include \"sysdep.h\"\n" print "#include \"constants.h\"" print "#include \"'$base'.h\"\n" } /^#/ { next } /^\./ { print " { 0, 0 }\n};\n" next } /^[^ ]/ { prefix = $1 printf ("struct constant_map %s_cst[] = {\n", locase(prefix)) next } /^[ ]/ && $1 { printf (" { %s_%s, \"%s\", %s },\n", prefix, $1, $1, ($3 && substr($3,1,1) != "#") ? $3 : 0) next } { print } ' <$1.cst >$base.c isakmpd-20041012.orig/ipsec_doi.h0000644000175000017500000000342410133045740016667 0ustar jdivejdive00000000000000/* $OpenBSD: ipsec_doi.h,v 1.8 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: ipsec_doi.h,v 1.10 1999/04/02 00:57:51 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _IPSEC_DOI_H_ #define _IPSEC_DOI_H_ #include "ipsec_fld.h" #include "ipsec_num.h" /* The SPI size of all IPsec protocols. XXX Correct? */ #define IPSEC_SPI_SIZE 4 /* The low limit if valid SPI values. */ #define IPSEC_SPI_LOW 0x100 #endif /* _IPSEC_DOI_H_ */ isakmpd-20041012.orig/if.h0000644000175000017500000000332210133045740015324 0ustar jdivejdive00000000000000/* $OpenBSD: if.h,v 1.7 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: if.h,v 1.2 1998/07/07 23:35:58 niklas Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _IF_H_ #define _IF_H_ #include struct ifreq; struct ifconf; extern int if_map(int (*) (char *, struct sockaddr *, void *), void *); extern int siocgifconf(struct ifconf *); #endif /* _IF_H_ */ isakmpd-20041012.orig/virtual.h0000644000175000017500000000352410133045740016420 0ustar jdivejdive00000000000000/* $OpenBSD: virtual.h,v 1.1 2004/06/20 15:24:05 ho Exp $ */ /* * Copyright (c) 2004 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. * * 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. */ #ifndef _TRP_VIRTUAL_H_ #define _TRP_VIRTUAL_H_ struct virtual_transport { struct transport transport; struct transport *main; /* Normally this transport is used. */ struct transport *encap; /* Or this, depending on 'encap_is_active'. */ int encap_is_active; LIST_ENTRY (virtual_transport) link; }; void virtual_init(void); struct virtual_transport *virtual_get_default(sa_family_t); struct virtual_transport *virtual_listen_lookup(struct sockaddr *); #endif /* _TRP_VIRTUAL_H_ */ isakmpd-20041012.orig/ike_quick_mode.c0000644000175000017500000016247110133045740017704 0ustar jdivejdive00000000000000/* $OpenBSD: ike_quick_mode.c,v 1.87 2004/09/17 13:53:08 ho Exp $ */ /* $EOM: ike_quick_mode.c,v 1.139 2001/01/26 10:43:17 niklas Exp $ */ /* * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2000, 2001, 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #if defined (USE_POLICY) || defined (USE_KEYNOTE) #include #include #include #endif #include "sysdep.h" #include "attribute.h" #include "conf.h" #include "connection.h" #include "dh.h" #include "doi.h" #include "exchange.h" #include "hash.h" #include "ike_quick_mode.h" #include "ipsec.h" #include "log.h" #include "math_group.h" #include "message.h" #include "policy.h" #include "prf.h" #include "sa.h" #include "transport.h" #include "util.h" #include "key.h" #ifdef USE_X509 #include "x509.h" #endif static void gen_g_xy(struct message *); static int initiator_send_HASH_SA_NONCE(struct message *); static int initiator_recv_HASH_SA_NONCE(struct message *); static int initiator_send_HASH(struct message *); static void post_quick_mode(struct message *); static int responder_recv_HASH_SA_NONCE(struct message *); static int responder_send_HASH_SA_NONCE(struct message *); static int responder_recv_HASH(struct message *); #ifdef USE_POLICY static int check_policy(struct exchange *, struct sa *, struct sa *); #endif int (*ike_quick_mode_initiator[])(struct message *) = { initiator_send_HASH_SA_NONCE, initiator_recv_HASH_SA_NONCE, initiator_send_HASH }; int (*ike_quick_mode_responder[])(struct message *) = { responder_recv_HASH_SA_NONCE, responder_send_HASH_SA_NONCE, responder_recv_HASH }; #ifdef USE_POLICY /* How many return values will policy handle -- true/false for now */ #define RETVALUES_NUM 2 /* * Given an exchange and our policy, check whether the SA and IDs are * acceptable. */ static int check_policy(struct exchange *exchange, struct sa *sa, struct sa *isakmp_sa) { char *return_values[RETVALUES_NUM]; char **principal = 0; int i, len, result = 0, nprinc = 0; int *x509_ids = 0, *keynote_ids = 0; unsigned char hashbuf[20]; /* Set to the largest digest result */ #ifdef USE_X509 struct keynote_deckey dc; X509_NAME *subject; #endif /* Do we want to use keynote policies? */ if (ignore_policy || strncmp("yes", conf_get_str("General", "Use-Keynote"), 3)) return 1; /* Initialize if necessary -- e.g., if pre-shared key auth was used */ if (isakmp_sa->policy_id < 0) { if ((isakmp_sa->policy_id = kn_init()) == -1) { log_print("check_policy: " "failed to initialize policy session"); return 0; } } /* Add the callback that will handle attributes. */ if (kn_add_action(isakmp_sa->policy_id, ".*", (char *)policy_callback, ENVIRONMENT_FLAG_FUNC | ENVIRONMENT_FLAG_REGEX) == -1) { log_print("check_policy: " "kn_add_action (%d, \".*\", %p, FUNC | REGEX) failed", isakmp_sa->policy_id, policy_callback); kn_close(isakmp_sa->policy_id); isakmp_sa->policy_id = -1; return 0; } if (policy_asserts_num) { keynote_ids = calloc(policy_asserts_num, sizeof *keynote_ids); if (!keynote_ids) { log_error("check_policy: calloc (%d, %lu) failed", policy_asserts_num, (unsigned long)sizeof *keynote_ids); return 0; } } /* Add the policy assertions */ for (i = 0; i < policy_asserts_num; i++) keynote_ids[i] = kn_add_assertion(isakmp_sa->policy_id, policy_asserts[i], strlen(policy_asserts[i]), ASSERT_FLAG_LOCAL); /* Initialize -- we'll let the callback do all the work. */ policy_exchange = exchange; policy_sa = sa; policy_isakmp_sa = isakmp_sa; /* Set the return values; true/false for now at least. */ return_values[0] = "false"; /* Order of values in array is * important. */ return_values[1] = "true"; /* Create a principal (authorizer) for the SA/ID request. */ switch (isakmp_sa->recv_certtype) { case ISAKMP_CERTENC_NONE: /* * For shared keys, just duplicate the passphrase with the * appropriate prefix tag. */ nprinc = 3; principal = calloc(nprinc, sizeof *principal); if (!principal) { log_error("check_policy: calloc (%d, %lu) failed", nprinc, (unsigned long)sizeof *principal); goto policydone; } len = strlen(isakmp_sa->recv_key) + sizeof "passphrase:"; principal[0] = calloc(len, sizeof(char)); if (!principal[0]) { log_error("check_policy: calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto policydone; } /* * XXX Consider changing the magic hash lengths with * constants. */ strlcpy(principal[0], "passphrase:", len); memcpy(principal[0] + sizeof "passphrase:" - 1, isakmp_sa->recv_key, strlen(isakmp_sa->recv_key)); len = sizeof "passphrase-md5-hex:" + 2 * 16; principal[1] = calloc(len, sizeof(char)); if (!principal[1]) { log_error("check_policy: calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto policydone; } strlcpy(principal[1], "passphrase-md5-hex:", len); MD5(isakmp_sa->recv_key, strlen(isakmp_sa->recv_key), hashbuf); for (i = 0; i < 16; i++) snprintf(principal[1] + 2 * i + sizeof "passphrase-md5-hex:" - 1, 3, "%02x", hashbuf[i]); len = sizeof "passphrase-sha1-hex:" + 2 * 20; principal[2] = calloc(len, sizeof(char)); if (!principal[2]) { log_error("check_policy: calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto policydone; } strlcpy(principal[2], "passphrase-sha1-hex:", len); SHA1(isakmp_sa->recv_key, strlen(isakmp_sa->recv_key), hashbuf); for (i = 0; i < 20; i++) snprintf(principal[2] + 2 * i + sizeof "passphrase-sha1-hex:" - 1, 3, "%02x", hashbuf[i]); break; case ISAKMP_CERTENC_KEYNOTE: #ifdef USE_KEYNOTE nprinc = 1; principal = calloc(nprinc, sizeof *principal); if (!principal) { log_error("check_policy: calloc (%d, %lu) failed", nprinc, (unsigned long)sizeof *principal); goto policydone; } /* Dup the keys */ principal[0] = strdup(isakmp_sa->keynote_key); if (!principal[0]) { log_error("check_policy: calloc (%lu, %lu) failed", (unsigned long)strlen(isakmp_sa->keynote_key), (unsigned long)sizeof(char)); goto policydone; } #endif break; case ISAKMP_CERTENC_X509_SIG: #ifdef USE_X509 principal = calloc(2, sizeof *principal); if (!principal) { log_error("check_policy: calloc (2, %lu) failed", (unsigned long)sizeof *principal); goto policydone; } if (isakmp_sa->recv_keytype == ISAKMP_KEY_RSA) dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; else { log_error("check_policy: " "unknown/unsupported public key algorithm %d", isakmp_sa->recv_keytype); goto policydone; } dc.dec_key = isakmp_sa->recv_key; principal[0] = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX, KEYNOTE_PUBLIC_KEY); if (keynote_errno == ERROR_MEMORY) { log_print("check_policy: " "failed to get memory for public key"); goto policydone; } if (!principal[0]) { log_print("check_policy: " "failed to allocate memory for principal"); goto policydone; } len = strlen(principal[0]) + sizeof "rsa-hex:"; principal[1] = calloc(len, sizeof(char)); if (!principal[1]) { log_error("check_policy: calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto policydone; } snprintf(principal[1], len, "rsa-hex:%s", principal[0]); free(principal[0]); principal[0] = principal[1]; principal[1] = 0; /* Generate a "DN:" principal. */ subject = X509_get_subject_name(isakmp_sa->recv_cert); if (subject) { principal[1] = calloc(259, sizeof(char)); if (!principal[1]) { log_error("check_policy: " "calloc (259, %lu) failed", (unsigned long)sizeof(char)); goto policydone; } strlcpy(principal[1], "DN:", 259); X509_NAME_oneline(subject, principal[1] + 3, 256); nprinc = 2; } else { nprinc = 1; } break; #endif /* XXX Eventually handle these. */ case ISAKMP_CERTENC_PKCS: case ISAKMP_CERTENC_PGP: case ISAKMP_CERTENC_DNS: case ISAKMP_CERTENC_X509_KE: case ISAKMP_CERTENC_KERBEROS: case ISAKMP_CERTENC_CRL: case ISAKMP_CERTENC_ARL: case ISAKMP_CERTENC_SPKI: case ISAKMP_CERTENC_X509_ATTR: default: log_print("check_policy: " "unknown/unsupported certificate/authentication method %d", isakmp_sa->recv_certtype); goto policydone; } /* * Add the authorizer (who is requesting the SA/ID); * this may be a public or a secret key, depending on * what mode of authentication we used in Phase 1. */ for (i = 0; i < nprinc; i++) { LOG_DBG((LOG_POLICY, 40, "check_policy: " "adding authorizer [%s]", principal[i])); if (kn_add_authorizer(isakmp_sa->policy_id, principal[i]) == -1) { int j; for (j = 0; j < i; j++) kn_remove_authorizer(isakmp_sa->policy_id, principal[j]); log_print("check_policy: kn_add_authorizer failed"); goto policydone; } } /* Ask policy */ result = kn_do_query(isakmp_sa->policy_id, return_values, RETVALUES_NUM); LOG_DBG((LOG_POLICY, 40, "check_policy: kn_do_query returned %d", result)); /* Cleanup environment */ kn_cleanup_action_environment(isakmp_sa->policy_id); /* Remove authorizers from the session */ for (i = 0; i < nprinc; i++) { kn_remove_authorizer(isakmp_sa->policy_id, principal[i]); free(principal[i]); } free(principal); principal = 0; nprinc = 0; /* Check what policy said. */ if (result < 0) { LOG_DBG((LOG_POLICY, 40, "check_policy: proposal refused")); result = 0; goto policydone; } policydone: for (i = 0; i < nprinc; i++) if (principal && principal[i]) free(principal[i]); if (principal) free(principal); /* Remove the policies */ for (i = 0; i < policy_asserts_num; i++) { if (keynote_ids[i] != -1) kn_remove_assertion(isakmp_sa->policy_id, keynote_ids[i]); } if (keynote_ids) free(keynote_ids); if (x509_ids) free(x509_ids); /* * XXX Currently, check_policy() is only called from * message_negotiate_sa(), and so this log message reflects this. * Change to something better? */ if (result == 0) log_print("check_policy: negotiated SA failed policy check"); /* * Given that we have only 2 return values from policy (true/false) * we can just return the query result directly (no pre-processing * needed). */ return result; } #endif /* USE_POLICY */ /* * Offer several sets of transforms to the responder. * XXX Split this huge function up and look for common code with main mode. */ static int initiator_send_HASH_SA_NONCE(struct message *msg) { struct exchange *exchange = msg->exchange; struct doi *doi = exchange->doi; struct ipsec_exch *ie = exchange->data; u_int8_t ***transform = 0, ***new_transform; u_int8_t **proposal = 0, **new_proposal; u_int8_t *sa_buf = 0, *attr, *saved_nextp_sa, *saved_nextp_prop, *id, *spi; size_t spi_sz, sz; size_t proposal_len = 0, proposals_len = 0, sa_len; size_t **transform_len = 0, **new_transform_len; size_t *transforms_len = 0, *new_transforms_len; u_int32_t *transform_cnt = 0, *new_transform_cnt; u_int32_t suite_no, prop_no, prot_no, xf_no, prop_cnt = 0; u_int32_t i; int value, update_nextp, protocol_num, proto_id; struct proto *proto; struct conf_list *suite_conf, *prot_conf = 0, *xf_conf = 0, *life_conf; struct conf_list_node *suite, *prot, *xf, *life; struct constant_map *id_map; char *protocol_id, *transform_id; char *local_id, *remote_id; int group_desc = -1, new_group_desc; struct ipsec_sa *isa = msg->isakmp_sa->data; struct hash *hash = hash_get(isa->hash); struct sockaddr *src; struct proto_attr *pa; if (!ipsec_add_hash_payload(msg, hash->hashsize)) return -1; /* Get the list of protocol suites. */ suite_conf = conf_get_list(exchange->policy, "Suites"); if (!suite_conf) return -1; for (suite = TAILQ_FIRST(&suite_conf->fields), suite_no = prop_no = 0; suite_no < suite_conf->cnt; suite_no++, suite = TAILQ_NEXT(suite, link)) { /* Now get each protocol in this specific protocol suite. */ prot_conf = conf_get_list(suite->field, "Protocols"); if (!prot_conf) goto bail_out; for (prot = TAILQ_FIRST(&prot_conf->fields), prot_no = 0; prot_no < prot_conf->cnt; prot_no++, prot = TAILQ_NEXT(prot, link)) { /* Make sure we have a proposal/transform vectors. */ if (prop_no >= prop_cnt) { /* * This resize algorithm is completely * arbitrary. */ prop_cnt = 2 * prop_cnt + 10; new_proposal = realloc(proposal, prop_cnt * sizeof *proposal); if (!new_proposal) { log_error( "initiator_send_HASH_SA_NONCE: " "realloc (%p, %lu) failed", proposal, prop_cnt * (unsigned long)sizeof *proposal); goto bail_out; } proposal = new_proposal; new_transforms_len = realloc(transforms_len, prop_cnt * sizeof *transforms_len); if (!new_transforms_len) { log_error( "initiator_send_HASH_SA_NONCE: " "realloc (%p, %lu) failed", transforms_len, prop_cnt * (unsigned long)sizeof *transforms_len); goto bail_out; } transforms_len = new_transforms_len; new_transform = realloc(transform, prop_cnt * sizeof *transform); if (!new_transform) { log_error( "initiator_send_HASH_SA_NONCE: " "realloc (%p, %lu) failed", transform, prop_cnt * (unsigned long)sizeof *transform); goto bail_out; } transform = new_transform; new_transform_cnt = realloc(transform_cnt, prop_cnt * sizeof *transform_cnt); if (!new_transform_cnt) { log_error( "initiator_send_HASH_SA_NONCE: " "realloc (%p, %lu) failed", transform_cnt, prop_cnt * (unsigned long)sizeof *transform_cnt); goto bail_out; } transform_cnt = new_transform_cnt; new_transform_len = realloc(transform_len, prop_cnt * sizeof *transform_len); if (!new_transform_len) { log_error( "initiator_send_HASH_SA_NONCE: " "realloc (%p, %lu) failed", transform_len, prop_cnt * (unsigned long)sizeof *transform_len); goto bail_out; } transform_len = new_transform_len; } protocol_id = conf_get_str(prot->field, "PROTOCOL_ID"); if (!protocol_id) goto bail_out; proto_id = constant_value(ipsec_proto_cst, protocol_id); switch (proto_id) { case IPSEC_PROTO_IPSEC_AH: id_map = ipsec_ah_cst; break; case IPSEC_PROTO_IPSEC_ESP: id_map = ipsec_esp_cst; break; case IPSEC_PROTO_IPCOMP: id_map = ipsec_ipcomp_cst; break; default: { log_print("initiator_send_HASH_SA_NONCE: " "invalid PROTCOL_ID: %s", protocol_id); goto bail_out; } } /* Now get each transform we offer for this protocol.*/ xf_conf = conf_get_list(prot->field, "Transforms"); if (!xf_conf) goto bail_out; transform_cnt[prop_no] = xf_conf->cnt; transform[prop_no] = calloc(transform_cnt[prop_no], sizeof **transform); if (!transform[prop_no]) { log_error("initiator_send_HASH_SA_NONCE: " "calloc (%d, %lu) failed", transform_cnt[prop_no], (unsigned long)sizeof **transform); goto bail_out; } transform_len[prop_no] = calloc(transform_cnt[prop_no], sizeof **transform_len); if (!transform_len[prop_no]) { log_error("initiator_send_HASH_SA_NONCE: " "calloc (%d, %lu) failed", transform_cnt[prop_no], (unsigned long)sizeof **transform_len); goto bail_out; } transforms_len[prop_no] = 0; for (xf = TAILQ_FIRST(&xf_conf->fields), xf_no = 0; xf_no < transform_cnt[prop_no]; xf_no++, xf = TAILQ_NEXT(xf, link)) { /* XXX The sizing needs to be dynamic. */ transform[prop_no][xf_no] = calloc(ISAKMP_TRANSFORM_SA_ATTRS_OFF + 9 * ISAKMP_ATTR_VALUE_OFF, 1); if (!transform[prop_no][xf_no]) { log_error( "initiator_send_HASH_SA_NONCE: " "calloc (%d, 1) failed", ISAKMP_TRANSFORM_SA_ATTRS_OFF + 9 * ISAKMP_ATTR_VALUE_OFF); goto bail_out; } SET_ISAKMP_TRANSFORM_NO(transform[prop_no][xf_no], xf_no + 1); transform_id = conf_get_str(xf->field, "TRANSFORM_ID"); if (!transform_id) goto bail_out; SET_ISAKMP_TRANSFORM_ID(transform[prop_no][xf_no], constant_value(id_map, transform_id)); SET_ISAKMP_TRANSFORM_RESERVED(transform[prop_no][xf_no], 0); attr = transform[prop_no][xf_no] + ISAKMP_TRANSFORM_SA_ATTRS_OFF; /* * Life durations are special, we should be * able to specify several, one per type. */ life_conf = conf_get_list(xf->field, "Life"); if (life_conf) { for (life = TAILQ_FIRST(&life_conf->fields); life; life = TAILQ_NEXT(life, link)) { attribute_set_constant( life->field, "LIFE_TYPE", ipsec_duration_cst, IPSEC_ATTR_SA_LIFE_TYPE, &attr); /* * XXX Deals with 16 and 32 * bit lifetimes only */ value = conf_get_num(life->field, "LIFE_DURATION", 0); if (value) { if (value <= 0xffff) attr = attribute_set_basic( attr, IPSEC_ATTR_SA_LIFE_DURATION, value); else { value = htonl(value); attr = attribute_set_var( attr, IPSEC_ATTR_SA_LIFE_DURATION, (u_int8_t *)&value, sizeof value); } } } conf_free_list(life_conf); } attribute_set_constant(xf->field, "ENCAPSULATION_MODE", ipsec_encap_cst, IPSEC_ATTR_ENCAPSULATION_MODE, &attr); if (proto_id != IPSEC_PROTO_IPCOMP) { attribute_set_constant(xf->field, "AUTHENTICATION_ALGORITHM", ipsec_auth_cst, IPSEC_ATTR_AUTHENTICATION_ALGORITHM, &attr); attribute_set_constant(xf->field, "GROUP_DESCRIPTION", ike_group_desc_cst, IPSEC_ATTR_GROUP_DESCRIPTION, &attr); value = conf_get_num(xf->field, "KEY_LENGTH", 0); if (value) attr = attribute_set_basic( attr, IPSEC_ATTR_KEY_LENGTH, value); value = conf_get_num(xf->field, "KEY_ROUNDS", 0); if (value) attr = attribute_set_basic( attr, IPSEC_ATTR_KEY_ROUNDS, value); } else { value = conf_get_num(xf->field, "COMPRESS_DICTIONARY_SIZE", 0); if (value) attr = attribute_set_basic( attr, IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE, value); value = conf_get_num(xf->field, "COMPRESS_PRIVATE_ALGORITHM", 0); if (value) attr = attribute_set_basic( attr, IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM, value); } value = conf_get_num(xf->field, "ECN_TUNNEL", 0); if (value) attr = attribute_set_basic(attr, IPSEC_ATTR_ECN_TUNNEL, value); /* Record the real transform size. */ transforms_len[prop_no] += (transform_len[prop_no][xf_no] = attr - transform[prop_no][xf_no]); if (proto_id != IPSEC_PROTO_IPCOMP) { /* * Make sure that if a group * description is specified, it is * specified for all transforms * equally. */ attr = (u_int8_t *)conf_get_str(xf->field, "GROUP_DESCRIPTION"); new_group_desc = attr ? constant_value(ike_group_desc_cst, (char *)attr) : 0; if (group_desc == -1) group_desc = new_group_desc; else if (group_desc != new_group_desc) { log_print("initiator_send_HASH_SA_NONCE: " "differing group descriptions in a proposal"); goto bail_out; } } } conf_free_list(xf_conf); xf_conf = 0; /* * Get SPI from application. * XXX Should we care about unknown constants? */ protocol_num = constant_value(ipsec_proto_cst, protocol_id); spi = doi->get_spi(&spi_sz, protocol_num, msg); if (spi_sz && !spi) { log_print("initiator_send_HASH_SA_NONCE: " "doi->get_spi failed"); goto bail_out; } proposal_len = ISAKMP_PROP_SPI_OFF + spi_sz; proposals_len += proposal_len + transforms_len[prop_no]; proposal[prop_no] = malloc(proposal_len); if (!proposal[prop_no]) { log_error("initiator_send_HASH_SA_NONCE: " "malloc (%lu) failed", (unsigned long)proposal_len); goto bail_out; } SET_ISAKMP_PROP_NO(proposal[prop_no], suite_no + 1); SET_ISAKMP_PROP_PROTO(proposal[prop_no], protocol_num); /* XXX I would like to see this factored out. */ proto = calloc(1, sizeof *proto); if (!proto) { log_error("initiator_send_HASH_SA_NONCE: " "calloc (1, %lu) failed", (unsigned long)sizeof *proto); goto bail_out; } if (doi->proto_size) { proto->data = calloc(1, doi->proto_size); if (!proto->data) { log_error( "initiator_send_HASH_SA_NONCE: " "calloc (1, %lu) failed", (unsigned long)doi->proto_size); goto bail_out; } } proto->no = suite_no + 1; proto->proto = protocol_num; proto->sa = TAILQ_FIRST(&exchange->sa_list); proto->xf_cnt = transform_cnt[prop_no]; TAILQ_INIT(&proto->xfs); for (xf_no = 0; xf_no < proto->xf_cnt; xf_no++) { pa = (struct proto_attr *)calloc(1, sizeof *pa); if (!pa) goto bail_out; pa->len = transform_len[prop_no][xf_no]; pa->attrs = (u_int8_t *)malloc(pa->len); if (!pa->attrs) { free(pa); goto bail_out; } memcpy(pa->attrs, transform[prop_no][xf_no], pa->len); TAILQ_INSERT_TAIL(&proto->xfs, pa, next); } TAILQ_INSERT_TAIL(&TAILQ_FIRST(&exchange->sa_list)->protos, proto, link); /* Setup the incoming SPI. */ SET_ISAKMP_PROP_SPI_SZ(proposal[prop_no], spi_sz); memcpy(proposal[prop_no] + ISAKMP_PROP_SPI_OFF, spi, spi_sz); proto->spi_sz[1] = spi_sz; proto->spi[1] = spi; /* * Let the DOI get at proto for initializing its own * data. */ if (doi->proto_init) doi->proto_init(proto, prot->field); SET_ISAKMP_PROP_NTRANSFORMS(proposal[prop_no], transform_cnt[prop_no]); prop_no++; } conf_free_list(prot_conf); prot_conf = 0; } sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN; sa_buf = malloc(sa_len); if (!sa_buf) { log_error("initiator_send_HASH_SA_NONCE: malloc (%lu) failed", (unsigned long)sa_len); goto bail_out; } SET_ISAKMP_SA_DOI(sa_buf, IPSEC_DOI_IPSEC); SET_IPSEC_SIT_SIT(sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY); /* * Add the payloads. As this is a SA, we need to recompute the * lengths of the payloads containing others. We also need to * reset these payload's "next payload type" field. */ if (message_add_payload(msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1)) goto bail_out; SET_ISAKMP_GEN_LENGTH(sa_buf, sa_len + proposals_len); sa_buf = 0; update_nextp = 0; saved_nextp_sa = msg->nextp; for (i = 0; i < prop_no; i++) { if (message_add_payload(msg, ISAKMP_PAYLOAD_PROPOSAL, proposal[i], proposal_len, update_nextp)) goto bail_out; SET_ISAKMP_GEN_LENGTH(proposal[i], proposal_len + transforms_len[i]); proposal[i] = 0; update_nextp = 0; saved_nextp_prop = msg->nextp; for (xf_no = 0; xf_no < transform_cnt[i]; xf_no++) { if (message_add_payload(msg, ISAKMP_PAYLOAD_TRANSFORM, transform[i][xf_no], transform_len[i][xf_no], update_nextp)) goto bail_out; update_nextp = 1; transform[i][xf_no] = 0; } msg->nextp = saved_nextp_prop; update_nextp = 1; } msg->nextp = saved_nextp_sa; /* * Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len. */ ie->sa_i_b = message_copy(msg, ISAKMP_GEN_SZ, &ie->sa_i_b_len); if (!ie->sa_i_b) goto bail_out; /* * Generate a nonce, and add it to the message. * XXX I want a better way to specify the nonce's size. */ if (exchange_gen_nonce(msg, 16)) return -1; /* Generate optional KEY_EXCH payload. */ if (group_desc > 0) { ie->group = group_get(group_desc); ie->g_x_len = dh_getlen(ie->group); if (ipsec_gen_g_x(msg)) { group_free(ie->group); ie->group = 0; return -1; } } /* Generate optional client ID payloads. XXX Share with responder. */ local_id = conf_get_str(exchange->name, "Local-ID"); remote_id = conf_get_str(exchange->name, "Remote-ID"); if (local_id && remote_id) { id = ipsec_build_id(local_id, &sz); if (!id) return -1; LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH_SA_NONCE: IDic", id, sz)); if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { free(id); return -1; } id = ipsec_build_id(remote_id, &sz); if (!id) return -1; LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH_SA_NONCE: IDrc", id, sz)); if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { free(id); return -1; } } /* XXX I do not judge these as errors, are they? */ else if (local_id) log_print("initiator_send_HASH_SA_NONCE: " "Local-ID given without Remote-ID for \"%s\"", exchange->name); else if (remote_id) /* * This code supports the "road warrior" case, where the * initiator doesn't have a fixed IP address, but wants to * specify a particular remote network to talk to. -- Adrian * Close */ { log_print("initiator_send_HASH_SA_NONCE: " "Remote-ID given without Local-ID for \"%s\"", exchange->name); /* * If we're here, then we are the initiator, so use initiator * address for local ID */ msg->transport->vtbl->get_src(msg->transport, &src); sz = ISAKMP_ID_SZ + sockaddr_addrlen(src); id = calloc(sz, sizeof(char)); if (!id) { log_error("initiator_send_HASH_SA_NONCE: " "calloc (%lu, %lu) failed", (unsigned long)sz, (unsigned long)sizeof(char)); return -1; } switch (src->sa_family) { case AF_INET6: SET_ISAKMP_ID_TYPE(id, IPSEC_ID_IPV6_ADDR); break; case AF_INET: SET_ISAKMP_ID_TYPE(id, IPSEC_ID_IPV4_ADDR); break; default: log_error("initiator_send_HASH_SA_NONCE: " "unknown sa_family %d", src->sa_family); free(id); return -1; } memcpy(id + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src), sockaddr_addrlen(src)); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH_SA_NONCE: IDic", id, sz)); if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { free(id); return -1; } /* Send supplied remote_id */ id = ipsec_build_id(remote_id, &sz); if (!id) return -1; LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH_SA_NONCE: IDrc", id, sz)); if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { free(id); return -1; } } if (ipsec_fill_in_hash(msg)) goto bail_out; conf_free_list(suite_conf); for (i = 0; i < prop_no; i++) { free(transform[i]); free(transform_len[i]); } free(proposal); free(transform); free(transforms_len); free(transform_len); free(transform_cnt); return 0; bail_out: if (sa_buf) free(sa_buf); if (proposal) { for (i = 0; i < prop_no; i++) { if (proposal[i]) free(proposal[i]); if (transform[i]) { for (xf_no = 0; xf_no < transform_cnt[i]; xf_no++) if (transform[i][xf_no]) free(transform[i][xf_no]); free(transform[i]); } if (transform_len[i]) free(transform_len[i]); } free(proposal); free(transforms_len); free(transform); free(transform_len); free(transform_cnt); } if (xf_conf) conf_free_list(xf_conf); if (prot_conf) conf_free_list(prot_conf); conf_free_list(suite_conf); return -1; } /* Figure out what transform the responder chose. */ static int initiator_recv_HASH_SA_NONCE(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct sa *sa; struct proto *proto, *next_proto; struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA); struct payload *xf, *idp; struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH); struct payload *kep = payload_first(msg, ISAKMP_PAYLOAD_KEY_EXCH); struct prf *prf; struct sa *isakmp_sa = msg->isakmp_sa; struct ipsec_sa *isa = isakmp_sa->data; struct hash *hash = hash_get(isa->hash); size_t hashsize = hash->hashsize; u_int8_t *rest; size_t rest_len; struct sockaddr *src, *dst; /* Allocate the prf and start calculating our HASH(1). XXX Share? */ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_recv_HASH_SA_NONCE: " "SKEYID_a", (u_int8_t *)isa->skeyid_a, isa->skeyid_len)); prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a, isa->skeyid_len); if (!prf) return -1; prf->Init(prf->prfctx); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_recv_HASH_SA_NONCE: message_id", exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN)); prf->Update(prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_recv_HASH_SA_NONCE: " "NONCE_I_b", exchange->nonce_i, exchange->nonce_i_len)); prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len); rest = hashp->p + GET_ISAKMP_GEN_LENGTH(hashp->p); rest_len = (GET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base) - (rest - (u_int8_t *)msg->iov[0].iov_base)); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_recv_HASH_SA_NONCE: payloads after HASH(2)", rest, rest_len)); prf->Update(prf->prfctx, rest, rest_len); prf->Final(hash->digest, prf->prfctx); prf_free(prf); LOG_DBG_BUF((LOG_NEGOTIATION, 80, "initiator_recv_HASH_SA_NONCE: computed HASH(2)", hash->digest, hashsize)); if (memcmp(hashp->p + ISAKMP_HASH_DATA_OFF, hash->digest, hashsize) != 0) { message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 0); return -1; } /* Mark the HASH as handled. */ hashp->flags |= PL_MARK; /* Mark message as authenticated. */ msg->flags |= MSG_AUTHENTICATED; /* * As we are getting an answer on our transform offer, only one * transform should be given. * * XXX Currently we only support negotiating one SA per quick mode run. */ if (TAILQ_NEXT(sa_p, link)) { log_print("initiator_recv_HASH_SA_NONCE: " "multiple SA payloads in quick mode not supported yet"); return -1; } sa = TAILQ_FIRST(&exchange->sa_list); /* This is here for the policy check */ if (kep) ie->pfs = 1; /* Handle optional client ID payloads. */ idp = payload_first(msg, ISAKMP_PAYLOAD_ID); if (idp) { /* If IDci is there, IDcr must be too. */ if (!TAILQ_NEXT(idp, link)) { /* XXX Is this a good notify type? */ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } /* XXX We should really compare, not override. */ ie->id_ci_sz = GET_ISAKMP_GEN_LENGTH(idp->p); ie->id_ci = malloc(ie->id_ci_sz); if (!ie->id_ci) { log_error("initiator_recv_HASH_SA_NONCE: " "malloc (%lu) failed", (unsigned long)ie->id_ci_sz); return -1; } memcpy(ie->id_ci, idp->p, ie->id_ci_sz); idp->flags |= PL_MARK; LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_recv_HASH_SA_NONCE: IDci", ie->id_ci + ISAKMP_GEN_SZ, ie->id_ci_sz - ISAKMP_GEN_SZ)); idp = TAILQ_NEXT(idp, link); ie->id_cr_sz = GET_ISAKMP_GEN_LENGTH(idp->p); ie->id_cr = malloc(ie->id_cr_sz); if (!ie->id_cr) { log_error("initiator_recv_HASH_SA_NONCE: " "malloc (%lu) failed", (unsigned long)ie->id_cr_sz); return -1; } memcpy(ie->id_cr, idp->p, ie->id_cr_sz); idp->flags |= PL_MARK; LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_recv_HASH_SA_NONCE: IDcr", ie->id_cr + ISAKMP_GEN_SZ, ie->id_cr_sz - ISAKMP_GEN_SZ)); } else { /* * If client identifiers are not present in the exchange, * we fake them. RFC 2409 states: * The identities of the SAs negotiated in Quick Mode are * implicitly assumed to be the IP addresses of the ISAKMP * peers, without any constraints on the protocol or port * numbers allowed, unless client identifiers are specified * in Quick Mode. * * -- Michael Paddon (mwp@aba.net.au) */ ie->flags = IPSEC_EXCH_FLAG_NO_ID; /* Get initiator and responder addresses. */ msg->transport->vtbl->get_src(msg->transport, &src); msg->transport->vtbl->get_dst(msg->transport, &dst); ie->id_ci_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(src); ie->id_cr_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(dst); ie->id_ci = calloc(ie->id_ci_sz, sizeof(char)); ie->id_cr = calloc(ie->id_cr_sz, sizeof(char)); if (!ie->id_ci || !ie->id_cr) { log_error("initiator_recv_HASH_SA_NONCE: " "calloc (%lu, %lu) failed", (unsigned long)ie->id_cr_sz, (unsigned long)sizeof(char)); if (ie->id_ci) { free(ie->id_ci); ie->id_ci = 0; } if (ie->id_cr) { free(ie->id_cr); ie->id_cr = 0; } return -1; } if (src->sa_family != dst->sa_family) { log_error("initiator_recv_HASH_SA_NONCE: " "sa_family mismatch"); free(ie->id_ci); ie->id_ci = 0; free(ie->id_cr); ie->id_cr = 0; return -1; } switch (src->sa_family) { case AF_INET: SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV4_ADDR); SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV4_ADDR); break; case AF_INET6: SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV6_ADDR); SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV6_ADDR); break; default: log_error("initiator_recv_HASH_SA_NONCE: " "unknown sa_family %d", src->sa_family); free(ie->id_ci); ie->id_ci = 0; free(ie->id_cr); ie->id_cr = 0; return -1; } memcpy(ie->id_ci + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src), sockaddr_addrlen(src)); memcpy(ie->id_cr + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(dst), sockaddr_addrlen(dst)); } /* Build the protection suite in our SA. */ for (xf = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM); xf; xf = TAILQ_NEXT(xf, link)) { /* * XXX We could check that the proposal each transform * belongs to is unique. */ if (sa_add_transform(sa, xf, exchange->initiator, &proto)) return -1; /* XXX Check that the chosen transform matches an offer. */ ipsec_decode_transform(msg, sa, proto, xf->p); } /* Now remove offers that we don't need anymore. */ for (proto = TAILQ_FIRST(&sa->protos); proto; proto = next_proto) { next_proto = TAILQ_NEXT(proto, link); if (!proto->chosen) proto_free(proto); } #ifdef USE_POLICY if (!check_policy(exchange, sa, msg->isakmp_sa)) { message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); log_print("initiator_recv_HASH_SA_NONCE: policy check failed"); return -1; } #endif /* Mark the SA as handled. */ sa_p->flags |= PL_MARK; isa = sa->data; if ((isa->group_desc && (!ie->group || ie->group->id != isa->group_desc)) || (!isa->group_desc && ie->group)) { log_print("initiator_recv_HASH_SA_NONCE: disagreement on PFS"); return -1; } /* Copy out the initiator's nonce. */ if (exchange_save_nonce(msg)) return -1; /* Handle the optional KEY_EXCH payload. */ if (kep && ipsec_save_g_x(msg)) return -1; return 0; } static int initiator_send_HASH(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct sa *isakmp_sa = msg->isakmp_sa; struct ipsec_sa *isa = isakmp_sa->data; struct prf *prf; u_int8_t *buf; struct hash *hash = hash_get(isa->hash); size_t hashsize = hash->hashsize; /* * We want a HASH payload to start with. XXX Share with * ike_main_mode.c? */ buf = malloc(ISAKMP_HASH_SZ + hashsize); if (!buf) { log_error("initiator_send_HASH: malloc (%lu) failed", ISAKMP_HASH_SZ + (unsigned long)hashsize); return -1; } if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, buf, ISAKMP_HASH_SZ + hashsize, 1)) { free(buf); return -1; } /* Allocate the prf and start calculating our HASH(3). XXX Share? */ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH: SKEYID_a", isa->skeyid_a, isa->skeyid_len)); prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, isa->skeyid_len); if (!prf) return -1; prf->Init(prf->prfctx); prf->Update(prf->prfctx, (unsigned char *)"\0", 1); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH: message_id", exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN)); prf->Update(prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH: NONCE_I_b", exchange->nonce_i, exchange->nonce_i_len)); prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH: NONCE_R_b", exchange->nonce_r, exchange->nonce_r_len)); prf->Update(prf->prfctx, exchange->nonce_r, exchange->nonce_r_len); prf->Final(buf + ISAKMP_GEN_SZ, prf->prfctx); prf_free(prf); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "initiator_send_HASH: HASH(3)", buf + ISAKMP_GEN_SZ, hashsize)); if (ie->group) message_register_post_send(msg, gen_g_xy); message_register_post_send(msg, post_quick_mode); return 0; } static void post_quick_mode(struct message *msg) { struct sa *isakmp_sa = msg->isakmp_sa; struct ipsec_sa *isa = isakmp_sa->data; struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct prf *prf; struct sa *sa; struct proto *proto; struct ipsec_proto *iproto; u_int8_t *keymat; int i; /* * Loop over all SA negotiations and do both an in- and an outgoing SA * per protocol. */ for (sa = TAILQ_FIRST(&exchange->sa_list); sa; sa = TAILQ_NEXT(sa, next)) { for (proto = TAILQ_FIRST(&sa->protos); proto; proto = TAILQ_NEXT(proto, link)) { if (proto->proto == IPSEC_PROTO_IPCOMP) continue; iproto = proto->data; /* * There are two SAs for each SA negotiation, * incoming and outcoing. */ for (i = 0; i < 2; i++) { prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_d, isa->skeyid_len); if (!prf) { /* XXX What to do? */ continue; } ie->keymat_len = ipsec_keymat_length(proto); /* * We need to roundup the length of the key * material buffer to a multiple of the PRF's * blocksize as it is generated in chunks of * that blocksize. */ iproto->keymat[i] = malloc(((ie->keymat_len + prf->blocksize - 1) / prf->blocksize) * prf->blocksize); if (!iproto->keymat[i]) { log_error("post_quick_mode: " "malloc (%lu) failed", (((unsigned long)ie->keymat_len + prf->blocksize - 1) / prf->blocksize) * prf->blocksize); /* XXX What more to do? */ free(prf); continue; } for (keymat = iproto->keymat[i]; keymat < iproto->keymat[i] + ie->keymat_len; keymat += prf->blocksize) { prf->Init(prf->prfctx); if (keymat != iproto->keymat[i]) { /* * Hash in last round's * KEYMAT. */ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "post_quick_mode: " "last KEYMAT", keymat - prf->blocksize, prf->blocksize)); prf->Update(prf->prfctx, keymat - prf->blocksize, prf->blocksize); } /* If PFS is used hash in g^xy. */ if (ie->g_xy) { LOG_DBG_BUF((LOG_NEGOTIATION, 90, "post_quick_mode: " "g^xy", ie->g_xy, ie->g_x_len)); prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len); } LOG_DBG((LOG_NEGOTIATION, 90, "post_quick_mode: " "suite %d proto %d", proto->no, proto->proto)); prf->Update(prf->prfctx, &proto->proto, 1); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "post_quick_mode: SPI", proto->spi[i], proto->spi_sz[i])); prf->Update(prf->prfctx, proto->spi[i], proto->spi_sz[i]); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "post_quick_mode: Ni_b", exchange->nonce_i, exchange->nonce_i_len)); prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "post_quick_mode: Nr_b", exchange->nonce_r, exchange->nonce_r_len)); prf->Update(prf->prfctx, exchange->nonce_r, exchange->nonce_r_len); prf->Final(keymat, prf->prfctx); } prf_free(prf); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "post_quick_mode: KEYMAT", iproto->keymat[i], ie->keymat_len)); } } } log_verbose("isakmpd: quick mode done: %s", !msg->isakmp_sa || !msg->isakmp_sa->transport ? "" : msg->isakmp_sa->transport->vtbl->decode_ids (msg->isakmp_sa->transport)); } /* * Accept a set of transforms offered by the initiator and chose one we can * handle. * XXX Describe in more detail. */ static int responder_recv_HASH_SA_NONCE(struct message *msg) { struct payload *hashp, *kep, *idp; struct sa *sa; struct sa *isakmp_sa = msg->isakmp_sa; struct ipsec_sa *isa = isakmp_sa->data; struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct prf *prf; u_int8_t *hash, *my_hash = 0; size_t hash_len; u_int8_t *pkt = msg->iov[0].iov_base; u_int8_t group_desc = 0; int retval = -1; struct proto *proto; struct sockaddr *src, *dst; char *name; hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH); hash = hashp->p; hashp->flags |= PL_MARK; /* The HASH payload should be the first one. */ if (hash != pkt + ISAKMP_HDR_SZ) { /* XXX Is there a better notification type? */ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); goto cleanup; } hash_len = GET_ISAKMP_GEN_LENGTH(hash); my_hash = malloc(hash_len - ISAKMP_GEN_SZ); if (!my_hash) { log_error("responder_recv_HASH_SA_NONCE: malloc (%lu) failed", (unsigned long)hash_len - ISAKMP_GEN_SZ); goto cleanup; } /* * Check the payload's integrity. * XXX Share with ipsec_fill_in_hash? */ LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH_SA_NONCE: " "SKEYID_a", isa->skeyid_a, isa->skeyid_len)); prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, isa->skeyid_len); if (!prf) goto cleanup; prf->Init(prf->prfctx); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH_SA_NONCE: message_id", exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN)); prf->Update(prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH_SA_NONCE: message after HASH", hash + hash_len, msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len)); prf->Update(prf->prfctx, hash + hash_len, msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len); prf->Final(my_hash, prf->prfctx); prf_free(prf); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH_SA_NONCE: computed HASH(1)", my_hash, hash_len - ISAKMP_GEN_SZ)); if (memcmp(hash + ISAKMP_GEN_SZ, my_hash, hash_len - ISAKMP_GEN_SZ) != 0) { message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 0); goto cleanup; } free(my_hash); my_hash = 0; /* Mark message as authenticated. */ msg->flags |= MSG_AUTHENTICATED; kep = payload_first(msg, ISAKMP_PAYLOAD_KEY_EXCH); if (kep) ie->pfs = 1; /* Handle optional client ID payloads. */ idp = payload_first(msg, ISAKMP_PAYLOAD_ID); if (idp) { /* If IDci is there, IDcr must be too. */ if (!TAILQ_NEXT(idp, link)) { /* XXX Is this a good notify type? */ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); goto cleanup; } ie->id_ci_sz = GET_ISAKMP_GEN_LENGTH(idp->p); ie->id_ci = malloc(ie->id_ci_sz); if (!ie->id_ci) { log_error("responder_recv_HASH_SA_NONCE: " "malloc (%lu) failed", (unsigned long)ie->id_ci_sz); goto cleanup; } memcpy(ie->id_ci, idp->p, ie->id_ci_sz); idp->flags |= PL_MARK; LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH_SA_NONCE: IDci", ie->id_ci + ISAKMP_GEN_SZ, ie->id_ci_sz - ISAKMP_GEN_SZ)); idp = TAILQ_NEXT(idp, link); ie->id_cr_sz = GET_ISAKMP_GEN_LENGTH(idp->p); ie->id_cr = malloc(ie->id_cr_sz); if (!ie->id_cr) { log_error("responder_recv_HASH_SA_NONCE: " "malloc (%lu) failed", (unsigned long)ie->id_cr_sz); goto cleanup; } memcpy(ie->id_cr, idp->p, ie->id_cr_sz); idp->flags |= PL_MARK; LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH_SA_NONCE: IDcr", ie->id_cr + ISAKMP_GEN_SZ, ie->id_cr_sz - ISAKMP_GEN_SZ)); } else { /* * If client identifiers are not present in the exchange, * we fake them. RFC 2409 states: * The identities of the SAs negotiated in Quick Mode are * implicitly assumed to be the IP addresses of the ISAKMP * peers, without any constraints on the protocol or port * numbers allowed, unless client identifiers are specified * in Quick Mode. * * -- Michael Paddon (mwp@aba.net.au) */ ie->flags = IPSEC_EXCH_FLAG_NO_ID; /* Get initiator and responder addresses. */ msg->transport->vtbl->get_src(msg->transport, &src); msg->transport->vtbl->get_dst(msg->transport, &dst); ie->id_ci_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(src); ie->id_cr_sz = ISAKMP_ID_DATA_OFF + sockaddr_addrlen(dst); ie->id_ci = calloc(ie->id_ci_sz, sizeof(char)); ie->id_cr = calloc(ie->id_cr_sz, sizeof(char)); if (!ie->id_ci || !ie->id_cr) { log_error("responder_recv_HASH_SA_NONCE: " "calloc (%lu, %lu) failed", (unsigned long)ie->id_ci_sz, (unsigned long)sizeof(char)); goto cleanup; } if (src->sa_family != dst->sa_family) { log_error("initiator_recv_HASH_SA_NONCE: " "sa_family mismatch"); goto cleanup; } switch (src->sa_family) { case AF_INET: SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV4_ADDR); SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV4_ADDR); break; case AF_INET6: SET_ISAKMP_ID_TYPE(ie->id_ci, IPSEC_ID_IPV6_ADDR); SET_ISAKMP_ID_TYPE(ie->id_cr, IPSEC_ID_IPV6_ADDR); break; default: log_error("initiator_recv_HASH_SA_NONCE: " "unknown sa_family %d", src->sa_family); goto cleanup; } memcpy(ie->id_cr + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src), sockaddr_addrlen(src)); memcpy(ie->id_ci + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(dst), sockaddr_addrlen(dst)); } #ifdef USE_POLICY #ifdef USE_KEYNOTE if (message_negotiate_sa(msg, check_policy)) goto cleanup; #else if (message_negotiate_sa(msg, 0)) goto cleanup; #endif #else if (message_negotiate_sa(msg, 0)) goto cleanup; #endif /* USE_POLICY */ for (sa = TAILQ_FIRST(&exchange->sa_list); sa; sa = TAILQ_NEXT(sa, next)) { for (proto = TAILQ_FIRST(&sa->protos); proto; proto = TAILQ_NEXT(proto, link)) { /* * XXX we need to have some attributes per proto, not * all per SA. */ ipsec_decode_transform(msg, sa, proto, proto->chosen->p); if (proto->proto == IPSEC_PROTO_IPSEC_AH && !((struct ipsec_proto *)proto->data)->auth) { log_print("responder_recv_HASH_SA_NONCE: " "AH proposed without an algorithm " "attribute"); message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); goto next_sa; } } isa = sa->data; /* * The group description is mandatory if we got a KEY_EXCH * payload. */ if (kep) { if (!isa->group_desc) { log_print("responder_recv_HASH_SA_NONCE: " "KEY_EXCH payload without a group " "desc. attribute"); message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); continue; } /* Also, all SAs must have equal groups. */ if (!group_desc) group_desc = isa->group_desc; else if (group_desc != isa->group_desc) { log_print("responder_recv_HASH_SA_NONCE: " "differing group descriptions in one QM"); message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); continue; } } /* At least one SA was accepted. */ retval = 0; next_sa: ; /* XXX gcc3 wants this. */ } if (kep) { ie->group = group_get(group_desc); if (!ie->group) { /* * XXX If the error was due to an out-of-range group * description we should notify our peer, but this * should probably be done by the attribute * validation. Is it? */ goto cleanup; } } /* Copy out the initiator's nonce. */ if (exchange_save_nonce(msg)) goto cleanup; /* Handle the optional KEY_EXCH payload. */ if (kep && ipsec_save_g_x(msg)) goto cleanup; /* * Try to find and set the connection name on the exchange. */ /* * Check for accepted identities as well as lookup the connection * name and set it on the exchange. * * When not using policies make sure the peer proposes sane IDs. * Otherwise this is done by KeyNote. */ name = connection_passive_lookup_by_ids(ie->id_ci, ie->id_cr); if (name) { exchange->name = strdup(name); if (!exchange->name) { log_error("responder_recv_HASH_SA_NONCE: " "strdup (\"%s\") failed", name); goto cleanup; } } else if ( #ifdef USE_X509 ignore_policy || #endif strncmp("yes", conf_get_str("General", "Use-Keynote"), 3)) { log_print("responder_recv_HASH_SA_NONCE: peer proposed " "invalid phase 2 IDs: %s", (exchange->doi->decode_ids("initiator id %s, responder" " id %s", ie->id_ci, ie->id_ci_sz, ie->id_cr, ie->id_cr_sz, 1))); message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); goto cleanup; } return retval; cleanup: /* Remove all potential protocols that have been added to the SAs. */ for (sa = TAILQ_FIRST(&exchange->sa_list); sa; sa = TAILQ_NEXT(sa, next)) while ((proto = TAILQ_FIRST(&sa->protos)) != 0) proto_free(proto); if (my_hash) free(my_hash); if (ie->id_ci) { free(ie->id_ci); ie->id_ci = 0; } if (ie->id_cr) { free(ie->id_cr); ie->id_cr = 0; } return -1; } /* Reply with the transform we chose. */ static int responder_send_HASH_SA_NONCE(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct sa *isakmp_sa = msg->isakmp_sa; struct ipsec_sa *isa = isakmp_sa->data; struct prf *prf; struct hash *hash = hash_get(isa->hash); size_t hashsize = hash->hashsize; size_t nonce_sz = exchange->nonce_i_len; u_int8_t *buf; int initiator = exchange->initiator; char header[80]; u_int32_t i; u_int8_t *id; size_t sz; /* * We want a HASH payload to start with. XXX Share with * ike_main_mode.c? */ buf = malloc(ISAKMP_HASH_SZ + hashsize); if (!buf) { log_error("responder_send_HASH_SA_NONCE: malloc (%lu) failed", ISAKMP_HASH_SZ + (unsigned long)hashsize); return -1; } if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, buf, ISAKMP_HASH_SZ + hashsize, 1)) { free(buf); return -1; } /* Add the SA payload(s) with the transform(s) that was/were chosen. */ if (message_add_sa_payload(msg)) return -1; /* Generate a nonce, and add it to the message. */ if (exchange_gen_nonce(msg, nonce_sz)) return -1; /* Generate optional KEY_EXCH payload. This is known as PFS. */ if (ie->group && ipsec_gen_g_x(msg)) return -1; /* * If the initiator client ID's were acceptable, just mirror them * back. */ if (!(ie->flags & IPSEC_EXCH_FLAG_NO_ID)) { sz = ie->id_ci_sz; id = malloc(sz); if (!id) { log_error("responder_send_HASH_SA_NONCE: " "malloc (%lu) failed", (unsigned long)sz); return -1; } memcpy(id, ie->id_ci, sz); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_send_HASH_SA_NONCE: IDic", id, sz)); if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { free(id); return -1; } sz = ie->id_cr_sz; id = malloc(sz); if (!id) { log_error("responder_send_HASH_SA_NONCE: " "malloc (%lu) failed", (unsigned long)sz); return -1; } memcpy(id, ie->id_cr, sz); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_send_HASH_SA_NONCE: IDrc", id, sz)); if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, id, sz, 1)) { free(id); return -1; } } /* Allocate the prf and start calculating our HASH(2). XXX Share? */ LOG_DBG((LOG_NEGOTIATION, 90, "responder_recv_HASH: " "isakmp_sa %p isa %p", isakmp_sa, isa)); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_send_HASH_SA_NONCE: " "SKEYID_a", isa->skeyid_a, isa->skeyid_len)); prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a, isa->skeyid_len); if (!prf) return -1; prf->Init(prf->prfctx); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_send_HASH_SA_NONCE: message_id", exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN)); prf->Update(prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_send_HASH_SA_NONCE: " "NONCE_I_b", exchange->nonce_i, exchange->nonce_i_len)); prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len); /* Loop over all payloads after HASH(2). */ for (i = 2; i < msg->iovlen; i++) { /* XXX Misleading payload type printouts. */ snprintf(header, sizeof header, "responder_send_HASH_SA_NONCE: payload %d after HASH(2)", i - 1); LOG_DBG_BUF((LOG_NEGOTIATION, 90, header, msg->iov[i].iov_base, msg->iov[i].iov_len)); prf->Update(prf->prfctx, msg->iov[i].iov_base, msg->iov[i].iov_len); } prf->Final(buf + ISAKMP_HASH_DATA_OFF, prf->prfctx); prf_free(prf); snprintf(header, sizeof header, "responder_send_HASH_SA_NONCE: " "HASH_%c", initiator ? 'I' : 'R'); LOG_DBG_BUF((LOG_NEGOTIATION, 80, header, buf + ISAKMP_HASH_DATA_OFF, hashsize)); if (ie->group) message_register_post_send(msg, gen_g_xy); return 0; } static void gen_g_xy(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; /* Compute Diffie-Hellman shared value. */ ie->g_xy = malloc(ie->g_x_len); if (!ie->g_xy) { log_error("gen_g_xy: malloc (%lu) failed", (unsigned long)ie->g_x_len); return; } if (dh_create_shared(ie->group, ie->g_xy, exchange->initiator ? ie->g_xr : ie->g_xi)) { log_print("gen_g_xy: dh_create_shared failed"); return; } LOG_DBG_BUF((LOG_NEGOTIATION, 80, "gen_g_xy: g^xy", ie->g_xy, ie->g_x_len)); } static int responder_recv_HASH(struct message *msg) { struct exchange *exchange = msg->exchange; struct sa *isakmp_sa = msg->isakmp_sa; struct ipsec_sa *isa = isakmp_sa->data; struct prf *prf; u_int8_t *hash, *my_hash = 0; size_t hash_len; struct payload *hashp; /* Find HASH(3) and create our own hash, just as big. */ hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH); hash = hashp->p; hashp->flags |= PL_MARK; hash_len = GET_ISAKMP_GEN_LENGTH(hash); my_hash = malloc(hash_len - ISAKMP_GEN_SZ); if (!my_hash) { log_error("responder_recv_HASH: malloc (%lu) failed", (unsigned long)hash_len - ISAKMP_GEN_SZ); goto cleanup; } /* Allocate the prf and start calculating our HASH(3). XXX Share? */ LOG_DBG((LOG_NEGOTIATION, 90, "responder_recv_HASH: " "isakmp_sa %p isa %p", isakmp_sa, isa)); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH: SKEYID_a", isa->skeyid_a, isa->skeyid_len)); prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, isa->skeyid_len); if (!prf) goto cleanup; prf->Init(prf->prfctx); prf->Update(prf->prfctx, (unsigned char *)"\0", 1); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH: message_id", exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN)); prf->Update(prf->prfctx, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH: NONCE_I_b", exchange->nonce_i, exchange->nonce_i_len)); prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH: NONCE_R_b", exchange->nonce_r, exchange->nonce_r_len)); prf->Update(prf->prfctx, exchange->nonce_r, exchange->nonce_r_len); prf->Final(my_hash, prf->prfctx); prf_free(prf); LOG_DBG_BUF((LOG_NEGOTIATION, 90, "responder_recv_HASH: computed HASH(3)", my_hash, hash_len - ISAKMP_GEN_SZ)); if (memcmp(hash + ISAKMP_GEN_SZ, my_hash, hash_len - ISAKMP_GEN_SZ) != 0) { message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 0); goto cleanup; } free(my_hash); /* Mark message as authenticated. */ msg->flags |= MSG_AUTHENTICATED; post_quick_mode(msg); return 0; cleanup: if (my_hash) free(my_hash); return -1; } isakmpd-20041012.orig/samples/0000755000175000017500000000000010133045740016221 5ustar jdivejdive00000000000000isakmpd-20041012.orig/samples/Makefile0000644000175000017500000000314410133045740017663 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.2 2003/06/03 14:39:50 ho Exp $ # $EOM: Makefile,v 1.1 2000/05/01 20:04:53 niklas Exp $ # # Copyright (c) 2000 Niklas Hallqvist. 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. # # 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. # FILES= VPN-* policy singlehost-* TARGETDIR= /usr/share/ipsec/isakmpd # The mkdir below is for installation on OpenBSD pre 2.7 install: @-mkdir -p ${DESTDIR}${TARGETDIR} $(INSTALL) -c -m 0444 ${FILES} ${DESTDIR}${TARGETDIR} isakmpd-20041012.orig/samples/singlehost-west.gdb0000644000175000017500000000013510133045740022035 0ustar jdivejdive00000000000000r -d -D0=99 -D1=99 -D2=99 -D3=99 -D4=99 -D5=99 -fwest.fifo -c../samples/singlehost-west.conf isakmpd-20041012.orig/samples/VPN-3way-template.conf0000644000175000017500000000535310133045740022233 0ustar jdivejdive00000000000000# $OpenBSD: VPN-3way-template.conf,v 1.11 2004/02/11 08:55:22 jmc Exp $ # $EOM: VPN-3way-template.conf,v 1.8 2000/10/09 22:08:30 angelos Exp $ # # A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. # # This is a template file of a VPN setup between three nodes in # a fully meshed 'three-way' configuration. Suggested use is to copy # this file to all three nodes and then edit them accordingly. # # These nodes are initially called XXX, YYY and ZZZ. # # In pseudographics: XXX --- YYY # \ / # ZZZ # # In cases where IP/network addresses should be defined values like # 192.168.XXX.nnn have been used. # # Incoming phase 1 negotiations are multiplexed on the source IP # address. In the three-way VPN, we have two possible peers. [Phase 1] 192.168.YYY.nnn= ISAKMP-peer-node-YYY 192.168.ZZZ.nnn= ISAKMP-peer-node-ZZZ # These connections are walked over after config file parsing and # told to the application layer so that it will inform us when # traffic wants to pass over them. This means we can do on-demand # keying. In the three-way VPN, each node knows two connections. [Phase 2] Connections= IPsec-Conn-XXX-YYY,IPsec-Conn-XXX-ZZZ # ISAKMP Phase 1 peer sections ############################## [ISAKMP-peer-node-YYY] Phase= 1 Transport= udp Address= 192.168.YYY.nnn Configuration= Default-main-mode Authentication= yoursharedsecretwithYYY [ISAKMP-peer-node-ZZZ] Phase= 1 Transport= udp Address= 192.168.ZZZ.nnn Configuration= Default-main-mode Authentication= yoursharedsecretwithZZZ # IPsec Phase 2 sections ######################## [IPsec-Conn-XXX-YYY] Phase= 2 ISAKMP-peer= ISAKMP-peer-node-YYY Configuration= Default-quick-mode Local-ID= MyNet-XXX Remote-ID= OtherNet-YYY [IPsec-Conn-XXX-ZZZ] Phase= 2 ISAKMP-peer= ISAKMP-peer-node-ZZZ Configuration= Default-quick-mode Local-ID= MyNet-XXX Remote-ID= OtherNet-ZZZ # Client ID sections #################### [MyNet-XXX] ID-type= IPV4_ADDR_SUBNET Network= 192.168.XXX.0 Netmask= 255.255.255.0 [OtherNet-YYY] ID-type= IPV4_ADDR_SUBNET Network= 192.168.YYY.0 Netmask= 255.255.255.0 [OtherNet-ZZZ] ID-type= IPV4_ADDR_SUBNET Network= 192.168.ZZZ.0 Netmask= 255.255.255.0 # # There is no more node-specific configuration below this point. # # Main mode descriptions [Default-main-mode] DOI= IPSEC EXCHANGE_TYPE= ID_PROT Transforms= 3DES-SHA,3DES-MD5 [Blowfish-main-mode] DOI= IPSEC EXCHANGE_TYPE= ID_PROT Transforms= BLF-SHA-M1024 # Quick mode description ######################## [Default-quick-mode] DOI= IPSEC EXCHANGE_TYPE= QUICK_MODE Suites= QM-ESP-AES-SHA-PFS-SUITE [Blowfish-quick-mode] DOI= IPSEC EXCHANGE_TYPE= QUICK_MODE Suites= QM-ESP-BLF-SHA-PFS-SUITE #Suites= QM-ESP-BLF-SHA-SUITE isakmpd-20041012.orig/samples/singlehost-setup.sh0000644000175000017500000000433610133045740022100 0ustar jdivejdive00000000000000#!/bin/sh # $OpenBSD: singlehost-setup.sh,v 1.5 2003/08/18 09:41:40 markus Exp $ # $EOM: singlehost-setup.sh,v 1.3 2000/11/23 12:24:43 niklas Exp $ # A script to test single-host VPNs # For the 'pf' variable . /etc/rc.conf # Default paths PFCTL=/sbin/pfctl ISAKMPD=/sbin/isakmpd do_routes() { /sbin/route $1 -net 192.168.11.0/24 192.168.11.1 -iface >/dev/null /sbin/route $1 -net 192.168.12.0/24 192.168.12.1 -iface >/dev/null /sbin/route $1 -net 10.1.0.0/16 10.1.0.11 -iface >/dev/null } # Called on script exit cleanup () { if [ "x${pf}" = "xYES" -a -f ${pf_rules} ]; then ${PFCTL} -R -f ${pf_rules} else ${PFCTL} -qd fi USER=`id -p | grep ^login | cut -f2` chown $USER singlehost-east.conf singlehost-west.conf policy chmod 644 singlehost-east.conf singlehost-west.conf policy [ -p east.fifo ] && echo "Q" >> east.fifo [ -p west.fifo ] && echo "Q" >> west.fifo rm -f east.fifo west.fifo do_routes delete } # Start by initializing interfaces /sbin/ifconfig lo2 192.168.11.1 netmask 0xffffff00 up /sbin/ifconfig lo3 192.168.12.1 netmask 0xffffff00 up /sbin/ifconfig lo4 10.1.0.11 netmask 0xffff0000 up /sbin/ifconfig lo5 10.1.0.12 netmask 0xffff0000 up # ... and by adding the required routes do_routes add # Add rules ( cat </dev/null fi ) | pfctl -R -f - trap cleanup 1 2 3 15 # The configuration files needs proper owners and modes USER=`id -p | grep ^uid | cut -f2` chown $USER singlehost-east.conf singlehost-west.conf policy chmod 600 singlehost-east.conf singlehost-west.conf policy # Start the daemons rm -f east.fifo west.fifo ${ISAKMPD} -c singlehost-east.conf -f east.fifo "$@" ${ISAKMPD} -c singlehost-west.conf -f west.fifo "$@" # Give them some time to negotiate their stuff... SECS=3 echo "Waiting $SECS seconds..." sleep $SECS echo "Running 'ping', using the tunnel..." ping -I 192.168.11.1 -c 5 192.168.12.1 cleanup isakmpd-20041012.orig/samples/policy0000644000175000017500000000065710133045740017453 0ustar jdivejdive00000000000000KeyNote-Version: 2 Comment: This policy accepts ESP SAs from a remote that uses the right password $OpenBSD: policy,v 1.6 2001/06/20 16:36:19 angelos Exp $ $EOM: policy,v 1.6 2000/10/09 22:08:30 angelos Exp $ Authorizer: "POLICY" Licensees: "passphrase:mekmitasdigoat" Conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg == "aes" && esp_auth_alg == "hmac-sha" -> "true"; isakmpd-20041012.orig/samples/VPN-east.conf0000644000175000017500000000213510133045740020466 0ustar jdivejdive00000000000000# $OpenBSD: VPN-east.conf,v 1.13 2003/03/16 08:13:02 matthieu Exp $ # $EOM: VPN-east.conf,v 1.12 2000/10/09 22:08:30 angelos Exp $ # A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. # # The network topology of the example net is like this: # # 192.168.11.0/24 - west [.11] - 10.1.0.0/24 - [.12] east - 192.168.12.0/24 # # "west" and "east" are the respective security gateways (aka VPN-nodes). [Phase 1] 10.1.0.11= ISAKMP-peer-west [Phase 2] Connections= IPsec-east-west [ISAKMP-peer-west] Phase= 1 Transport= udp Address= 10.1.0.11 Configuration= Default-main-mode Authentication= mekmitasdigoat [IPsec-east-west] Phase= 2 ISAKMP-peer= ISAKMP-peer-west Configuration= Default-quick-mode Local-ID= Net-east Remote-ID= Net-west [Net-west] ID-type= IPV4_ADDR_SUBNET Network= 192.168.11.0 Netmask= 255.255.255.0 [Net-east] ID-type= IPV4_ADDR_SUBNET Network= 192.168.12.0 Netmask= 255.255.255.0 [Default-main-mode] DOI= IPSEC EXCHANGE_TYPE= ID_PROT Transforms= 3DES-SHA [Default-quick-mode] DOI= IPSEC EXCHANGE_TYPE= QUICK_MODE Suites= QM-ESP-AES-SHA-PFS-SUITE isakmpd-20041012.orig/samples/VPN-west.conf0000644000175000017500000000213510133045740020514 0ustar jdivejdive00000000000000# $OpenBSD: VPN-west.conf,v 1.14 2003/03/16 08:13:02 matthieu Exp $ # $EOM: VPN-west.conf,v 1.13 2000/10/09 22:08:30 angelos Exp $ # A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. # # The network topology of the example net is like this: # # 192.168.11.0/24 - west [.11] - 10.1.0.0/24 - [.12] east - 192.168.12.0/24 # # "west" and "east" are the respective security gateways (aka VPN-nodes). [Phase 1] 10.1.0.12= ISAKMP-peer-east [Phase 2] Connections= IPsec-west-east [ISAKMP-peer-east] Phase= 1 Transport= udp Address= 10.1.0.12 Configuration= Default-main-mode Authentication= mekmitasdigoat [IPsec-west-east] Phase= 2 ISAKMP-peer= ISAKMP-peer-east Configuration= Default-quick-mode Local-ID= Net-west Remote-ID= Net-east [Net-west] ID-type= IPV4_ADDR_SUBNET Network= 192.168.11.0 Netmask= 255.255.255.0 [Net-east] ID-type= IPV4_ADDR_SUBNET Network= 192.168.12.0 Netmask= 255.255.255.0 [Default-main-mode] DOI= IPSEC EXCHANGE_TYPE= ID_PROT Transforms= 3DES-SHA [Default-quick-mode] DOI= IPSEC EXCHANGE_TYPE= QUICK_MODE Suites= QM-ESP-AES-SHA-PFS-SUITE isakmpd-20041012.orig/samples/singlehost-west.conf0000644000175000017500000000245110133045740022231 0ustar jdivejdive00000000000000# $OpenBSD: singlehost-west.conf,v 1.11 2003/08/20 14:43:36 ho Exp $ # $EOM: singlehost-west.conf,v 1.10 2000/11/23 12:24:43 niklas Exp $ # A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. [General] Listen-on= 10.1.0.11 Shared-SADB= Defined Policy-File= policy [Phase 1] 10.1.0.12= ISAKMP-peer-east Default= ISAKMP-peer-east-aggressive [Phase 2] Connections= IPsec-west-east [ISAKMP-peer-east] Phase= 1 Transport= udp Local-address= 10.1.0.11 Address= 10.1.0.12 Configuration= Default-main-mode Authentication= mekmitasdigoat [ISAKMP-peer-east-aggressive] Phase= 1 Transport= udp Local-address= 10.1.0.11 Address= 10.1.0.12 Configuration= Default-aggressive-mode Authentication= mekmitasdigoat [IPsec-west-east] Phase= 2 ISAKMP-peer= ISAKMP-peer-east Configuration= Default-quick-mode Local-ID= Net-west Remote-ID= Net-east [Net-west] ID-type= IPV4_ADDR_SUBNET Network= 192.168.11.0 Netmask= 255.255.255.0 [Net-east] ID-type= IPV4_ADDR_SUBNET Network= 192.168.12.0 Netmask= 255.255.255.0 [Default-main-mode] DOI= IPSEC EXCHANGE_TYPE= ID_PROT Transforms= 3DES-SHA [Default-aggressive-mode] DOI= IPSEC EXCHANGE_TYPE= AGGRESSIVE Transforms= 3DES-SHA-RSA [Default-quick-mode] DOI= IPSEC EXCHANGE_TYPE= QUICK_MODE Suites= QM-ESP-AES-SHA-PFS-SUITE isakmpd-20041012.orig/samples/CVS/0000755000175000017500000000000010133045751016656 5ustar jdivejdive00000000000000isakmpd-20041012.orig/samples/singlehost-east.conf0000644000175000017500000000245510133045740022207 0ustar jdivejdive00000000000000# $OpenBSD: singlehost-east.conf,v 1.10 2000/11/23 12:56:25 niklas Exp $ # $EOM: singlehost-east.conf,v 1.10 2000/11/23 12:24:43 niklas Exp $ # A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. [General] Listen-on= 10.1.0.12 Shared-SADB= Defined Policy-File= policy [Phase 1] 10.1.0.11= ISAKMP-peer-west Default= ISAKMP-peer-west-aggressive [Phase 2] Connections= IPsec-east-west [ISAKMP-peer-west] Phase= 1 Transport= udp Local-address= 10.1.0.12 Address= 10.1.0.11 Configuration= Default-main-mode Authentication= mekmitasdigoat [ISAKMP-peer-west-aggressive] Phase= 1 Transport= udp Local-address= 10.1.0.12 Address= 10.1.0.11 Configuration= Default-aggressive-mode Authentication= mekmitasdigoat [IPsec-east-west] Phase= 2 ISAKMP-peer= ISAKMP-peer-west Configuration= Default-quick-mode Local-ID= Net-east Remote-ID= Net-west [Net-west] ID-type= IPV4_ADDR_SUBNET Network= 192.168.11.0 Netmask= 255.255.255.0 [Net-east] ID-type= IPV4_ADDR_SUBNET Network= 192.168.12.0 Netmask= 255.255.255.0 [Default-main-mode] DOI= IPSEC EXCHANGE_TYPE= ID_PROT Transforms= 3DES-SHA [Default-aggressive-mode] DOI= IPSEC EXCHANGE_TYPE= AGGRESSIVE Transforms= 3DES-SHA-RSA [Default-quick-mode] DOI= IPSEC EXCHANGE_TYPE= QUICK_MODE Suites= QM-ESP-AES-SHA-PFS-SUITE isakmpd-20041012.orig/samples/singlehost-east.gdb0000644000175000017500000000013510133045740022007 0ustar jdivejdive00000000000000r -d -D0=99 -D1=99 -D2=99 -D3=99 -D4=99 -D5=99 -feast.fifo -c../samples/singlehost-east.conf isakmpd-20041012.orig/doi.c0000644000175000017500000000361110133045740015475 0ustar jdivejdive00000000000000/* $OpenBSD: doi.c,v 1.9 2004/07/09 16:06:48 deraadt Exp $ */ /* $EOM: doi.c,v 1.4 1999/04/02 00:57:36 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include "sysdep.h" #include "doi.h" static LIST_HEAD(doi_list, doi) doi_tab; void doi_init(void) { LIST_INIT(&doi_tab); } struct doi * doi_lookup(u_int8_t doi_id) { struct doi *doi; for (doi = LIST_FIRST(&doi_tab); doi && doi->id != doi_id; doi = LIST_NEXT(doi, link)); return doi; } void doi_register(struct doi *doi) { LIST_INSERT_HEAD(&doi_tab, doi, link); } isakmpd-20041012.orig/ike_quick_mode.h0000644000175000017500000000337010133045740017701 0ustar jdivejdive00000000000000/* $OpenBSD: ike_quick_mode.h,v 1.6 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: ike_quick_mode.h,v 1.1 1998/08/02 20:22:44 niklas Exp $ */ /* * Copyright (c) 1998, 2001 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _IKE_QUICK_MODE_H_ #define _IKE_QUICK_MODE_H_ struct message; extern int (*ike_quick_mode_initiator[]) (struct message *); extern int (*ike_quick_mode_responder[]) (struct message *); #endif /* _IKE_QUICK_MODE_H_ */ isakmpd-20041012.orig/README.PKI0000644000175000017500000000475210133045740016067 0ustar jdivejdive00000000000000$OpenBSD: README.PKI,v 1.7 1999/10/01 14:10:45 niklas Exp $ $EOM: README.PKI,v 1.7 1999/09/30 13:40:38 niklas Exp $ 1 Make sure you have an RSA-enabled isakmpd. An easy way to do this is to install a dynamically linkable version of libcrypto from OpenSSL and install it where the run-time linker can find it. 2 Create your own CA as root. openssl genrsa -out /etc/ssl/private/ca.key 1024 openssl req -new -key /etc/ssl/private/ca.key \ -out /etc/ssl/private/ca.csr You are now being asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank. For some fields there will be a default value, if you enter '.', the field will be left blank. openssl x509 -req -days 365 -in /etc/ssl/private/ca.csr \ -signkey /etc/ssl/private/ca.key \ -out /etc/ssl/ca.crt 3 Create keys and certificates for your isakmpd peers. This step as well as the next one, needs to be done for every peer. Furthermore the last step will need to be done once for each ID you want the peer to have. The 10.0.0.1 below symbolizes that ID, and should be changed for each invocation. You will be asked for a DN for each run too. See to encode the ID in the common name too, so it gets unique. openssl genrsa -out /etc/isakmpd/private/local.key 1024 openssl req -new -key /etc/isakmpd/private/local.key \ -out /etc/isakmpd/private/10.0.0.1.csr Now take these certificate signing requests to your CA and process them like below. You have to add some extensions to the certificate in order to make it usable for isakmpd, which is why you will need to run certpatch. Replace 10.0.0.1 with the IP-address which isakmpd will be using for identity. openssl x509 -req -days 365 -in 10.0.0.1.csr -CA /etc/ssl/ca.crt \ -CAkey /etc/ssl/private/ca.key -CAcreateserial \ -out 10.0.0.1.crt certpatch -i 10.0.0.1 -k /etc/ssl/private/ca.key \ 10.0.0.1.crt 10.0.0.1.crt Put the certificate (the file ending in .crt) in /etc/isakmpd/certs/ on your local system. Also carry over the CA cert /etc/ssl/ca.crt and put it in /etc/isakmpd/ca/. 4 See to that your config files will point out the directories where you keep certificates. I.e. add something like this to /etc/isakmpd/isakmpd.conf: # Certificates stored in PEM format [X509-certificates] CA-directory= /etc/isakmpd/ca/ Cert-directory= /etc/isakmpd/certs/ Private-key= /etc/isakmpd/private/local.key isakmpd-20041012.orig/exchange_num.cst0000644000175000017500000000340710133045740017735 0ustar jdivejdive00000000000000# $OpenBSD: exchange_num.cst,v 1.4 2003/06/03 14:28:16 ho Exp $ # $EOM: exchange_num.cst,v 1.1 1998/08/05 09:23:32 niklas Exp $ # # Copyright (c) 1998 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # Special exchange script symbols. EXCHANGE_SCRIPT # Special type signifying PAYLOAD_HASH or PALOAD_SIG must be present. AUTH -1 # Special type signifying PAYLOAD_NOTIFY or PALOAD_DELETE must be present. INFO -2 # Switch roles at this point in the exchange. SWITCH -3 # End of script END -4 . isakmpd-20041012.orig/cookie.h0000644000175000017500000000334110133045740016200 0ustar jdivejdive00000000000000/* $OpenBSD: cookie.h,v 1.7 2004/05/14 08:42:56 hshoexer Exp $ */ /* $EOM: cookie.h,v 1.5 1998/08/05 09:21:43 niklas Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _COOKIE_H_ #define _COOKIE_H_ #include #include struct exchange; struct transport; extern void cookie_gen(struct transport *, struct exchange *, u_int8_t *, size_t); #endif /* _COOKIE_H_ */ isakmpd-20041012.orig/ike_main_mode.h0000644000175000017500000000336210133045740017512 0ustar jdivejdive00000000000000/* $OpenBSD: ike_main_mode.h,v 1.6 2004/05/23 18:17:56 hshoexer Exp $ */ /* $EOM: ike_main_mode.h,v 1.1 1998/07/25 11:22:07 niklas Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _IKE_MAIN_MODE_H_ #define _IKE_MAIN_MODE_H_ struct message; extern int (*ike_main_mode_initiator[]) (struct message *msg); extern int (*ike_main_mode_responder[]) (struct message *msg); #endif /* _IKE_MAIN_MODE_H_ */ isakmpd-20041012.orig/nat_traversal.c0000644000175000017500000002723010133045740017572 0ustar jdivejdive00000000000000/* $OpenBSD: nat_traversal.c,v 1.7 2004/08/08 19:11:06 deraadt Exp $ */ /* * Copyright (c) 2004 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. * * 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 #include #include #include "sysdep.h" #include "conf.h" #include "exchange.h" #include "hash.h" #include "ipsec.h" #include "isakmp_fld.h" #include "isakmp_num.h" #include "ipsec_num.h" #include "hash.h" #include "log.h" #include "message.h" #include "nat_traversal.h" #include "prf.h" #include "sa.h" #include "timer.h" #include "transport.h" #include "util.h" #include "virtual.h" /* * XXX According to draft-ietf-ipsec-nat-t-ike-07.txt, the NAT-T * capability of the other peer is determined by a particular vendor ID * sent as the first message. This vendor ID string is supposed to be a * MD5 hash of "RFC XXXX", where XXXX is the future RFC number. * * These seem to be the "well" known variants of this string in use by * products today. */ static const char *isakmp_nat_t_cap_text[] = { "draft-ietf-ipsec-nat-t-ike-00", /* V1 (XXX: may be obsolete) */ "draft-ietf-ipsec-nat-t-ike-02\n", /* V2 */ "draft-ietf-ipsec-nat-t-ike-03", /* V3 */ #ifdef notyet "RFC XXXX", #endif }; /* In seconds. Recommended in draft-ietf-ipsec-udp-encaps-09. */ #define NAT_T_KEEPALIVE_INTERVAL 20 /* The MD5 hashes of the above strings is put in this array. */ static char **nat_t_hashes; static size_t nat_t_hashsize; static int nat_t_setup_hashes(void); static int nat_t_add_vendor_payload(struct message *, char *); static int nat_t_add_nat_d(struct message *, struct sockaddr *); static int nat_t_match_nat_d_payload(struct message *, struct sockaddr *); void nat_t_init(void) { nat_t_hashes = (char **)NULL; } /* Generate the NAT-T capability marker hashes. Executed only once. */ static int nat_t_setup_hashes(void) { struct hash *hash; int n = sizeof isakmp_nat_t_cap_text / sizeof isakmp_nat_t_cap_text[0]; int i; /* The draft says to use MD5. */ hash = hash_get(HASH_MD5); if (!hash) { /* Should never happen. */ log_print("nat_t_setup_hashes: " "could not find MD5 hash structure!"); return -1; } nat_t_hashsize = hash->hashsize; /* Allocate one more than is necessary, i.e NULL terminated. */ nat_t_hashes = (char **)calloc((size_t)(n + 1), sizeof(char *)); if (!nat_t_hashes) { log_error("nat_t_setup_hashes: calloc (%lu,%lu) failed", (unsigned long)n, (unsigned long)sizeof(char *)); return -1; } /* Populate with hashes. */ for (i = 0; i < n; i++) { nat_t_hashes[i] = (char *)malloc(nat_t_hashsize); if (!nat_t_hashes[i]) { log_error("nat_t_setup_hashes: malloc (%lu) failed", (unsigned long)nat_t_hashsize); goto errout; } hash->Init(hash->ctx); hash->Update(hash->ctx, (unsigned char *)isakmp_nat_t_cap_text[i], strlen(isakmp_nat_t_cap_text[i])); hash->Final(nat_t_hashes[i], hash->ctx); LOG_DBG((LOG_EXCHANGE, 50, "nat_t_setup_hashes: " "MD5(\"%s\") (%lu bytes)", isakmp_nat_t_cap_text[i], (unsigned long)nat_t_hashsize)); LOG_DBG_BUF((LOG_EXCHANGE, 50, "nat_t_setup_hashes", nat_t_hashes[i], nat_t_hashsize)); } return 0; errout: for (i = 0; i < n; i++) if (nat_t_hashes[i]) free(nat_t_hashes[i]); free(nat_t_hashes); nat_t_hashes = NULL; return -1; } /* Add one NAT-T VENDOR payload. */ static int nat_t_add_vendor_payload(struct message *msg, char *hash) { size_t buflen = nat_t_hashsize + ISAKMP_GEN_SZ; u_int8_t *buf; buf = malloc(buflen); if (!buf) { log_error("nat_t_add_vendor_payload: malloc (%lu) failed", (unsigned long)buflen); return -1; } SET_ISAKMP_GEN_LENGTH(buf, buflen); memcpy(buf + ISAKMP_VENDOR_ID_OFF, hash, nat_t_hashsize); if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) { free(buf); return -1; } return 0; } /* Add the NAT-T capability markers (VENDOR payloads). */ int nat_t_add_vendor_payloads(struct message *msg) { int i = 0; if (!nat_t_hashes) if (nat_t_setup_hashes()) return 0; /* XXX should this be an error? */ while (nat_t_hashes[i]) if (nat_t_add_vendor_payload(msg, nat_t_hashes[i++])) return -1; return 0; } /* * Check an incoming message for NAT-T capability markers. */ void nat_t_check_vendor_payload(struct message *msg, struct payload *p) { u_int8_t *pbuf = p->p; size_t vlen; int i = 0; /* Already checked? */ if (p->flags & PL_MARK || msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER) return; if (!nat_t_hashes) if (nat_t_setup_hashes()) return; vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ; if (vlen != nat_t_hashsize) { LOG_DBG((LOG_EXCHANGE, 50, "nat_t_check_vendor_payload: " "bad size %lu != %lu", (unsigned long)vlen, (unsigned long)nat_t_hashsize)); return; } while (nat_t_hashes[i]) if (memcmp(nat_t_hashes[i++], pbuf + ISAKMP_GEN_SZ, vlen) == 0) { /* This peer is NAT-T capable. */ msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER; LOG_DBG((LOG_EXCHANGE, 10, "nat_t_check_vendor_payload: " "NAT-T capable peer detected")); p->flags |= PL_MARK; return; } return; } /* Generate the NAT-D payload hash : HASH(CKY-I | CKY-R | IP | Port). */ static u_int8_t * nat_t_generate_nat_d_hash(struct message *msg, struct sockaddr *sa, size_t *hashlen) { struct ipsec_exch *ie = (struct ipsec_exch *)msg->exchange->data; struct hash *hash; struct prf *prf; u_int8_t *res; in_port_t port; int prf_type = PRF_HMAC; /* XXX */ hash = hash_get(ie->hash->type); if (hash == NULL) { log_print ("nat_t_generate_nat_d_hash: no hash"); return NULL; } prf = prf_alloc(prf_type, hash->type, msg->exchange->cookies, ISAKMP_HDR_COOKIES_LEN); if(!prf) { log_print("nat_t_generate_nat_d_hash: prf_alloc failed"); return NULL; } *hashlen = prf->blocksize; res = (u_int8_t *)malloc((unsigned long)*hashlen); if (!res) { log_print("nat_t_generate_nat_d_hash: malloc (%lu) failed", (unsigned long)*hashlen); prf_free(prf); *hashlen = 0; return NULL; } port = sockaddr_port(sa); memset(res, 0, *hashlen); prf->Update(prf->prfctx, sockaddr_addrdata(sa), sockaddr_addrlen(sa)); prf->Update(prf->prfctx, (unsigned char *)&port, sizeof port); prf->Final(res, prf->prfctx); prf_free (prf); return res; } /* Add a NAT-D payload to our message. */ static int nat_t_add_nat_d(struct message *msg, struct sockaddr *sa) { u_int8_t *hbuf, *buf; size_t hbuflen, buflen; hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen); if (!hbuf) { log_print("nat_t_add_nat_d: NAT-D hash gen failed"); return -1; } buflen = ISAKMP_NAT_D_DATA_OFF + hbuflen; buf = malloc(buflen); if (!buf) { log_error("nat_t_add_nat_d: malloc (%lu) failed", (unsigned long)buflen); free(hbuf); return -1; } SET_ISAKMP_GEN_LENGTH(buf, buflen); memcpy(buf + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen); free(hbuf); if (message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D, buf, buflen, 1)) { free(buf); return -1; } return 0; } /* We add two NAT-D payloads, one each for src and dst. */ int nat_t_exchange_add_nat_d(struct message *msg) { struct sockaddr *sa; msg->transport->vtbl->get_src(msg->transport, &sa); if (nat_t_add_nat_d(msg, sa)) return -1; msg->transport->vtbl->get_dst(msg->transport, &sa); if (nat_t_add_nat_d(msg, sa)) return -1; return 0; } /* Generate and match a NAT-D hash against the NAT-D payload (pl.) data. */ static int nat_t_match_nat_d_payload(struct message *msg, struct sockaddr *sa) { struct payload *p; u_int8_t *hbuf; size_t hbuflen; int found = 0; /* * If there are no NAT-D payloads in the message, return "found" * as this will avoid NAT-T (see nat_t_exchange_check_nat_d()). */ p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D); if (!p) return 1; hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen); if (!hbuf) return 0; while (p) { if (GET_ISAKMP_GEN_LENGTH (p->p) != hbuflen + ISAKMP_NAT_D_DATA_OFF) continue; if (memcmp(p->p + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen) == 0) { found++; break; } p = TAILQ_NEXT(p, link); } free(hbuf); return found; } /* * Check if we need to activate NAT-T, and if we need to send keepalive * messages to the other side, i.e if we are a nat:ed peer. */ int nat_t_exchange_check_nat_d(struct message *msg) { struct sockaddr *sa; int outgoing_path_is_clear, incoming_path_is_clear; /* Assume trouble, i.e NAT-boxes in our path. */ outgoing_path_is_clear = incoming_path_is_clear = 0; msg->transport->vtbl->get_src(msg->transport, &sa); if (nat_t_match_nat_d_payload(msg, sa)) outgoing_path_is_clear = 1; msg->transport->vtbl->get_dst(msg->transport, &sa); if (nat_t_match_nat_d_payload(msg, sa)) incoming_path_is_clear = 1; if (outgoing_path_is_clear && incoming_path_is_clear) { LOG_DBG((LOG_EXCHANGE, 40, "nat_t_exchange_check_nat_d: " "no NAT")); return 0; /* No NAT-T required. */ } /* NAT-T handling required. */ msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE; if (!outgoing_path_is_clear) { msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE; LOG_DBG((LOG_EXCHANGE, 10, "nat_t_exchange_check_nat_d: " "NAT detected, we're behind it")); } else LOG_DBG ((LOG_EXCHANGE, 10, "nat_t_exchange_check_nat_d: NAT detected")); return 1; } static void nat_t_send_keepalive(void *v_arg) { struct sa *sa = (struct sa *)v_arg; struct transport *t; struct timeval now; int interval; /* Send the keepalive message. */ t = ((struct virtual_transport *)sa->transport)->encap; t->vtbl->send_message(NULL, t); /* Set new timer. */ interval = conf_get_num("General", "NAT-T-Keepalive", 0); if (interval < 1) interval = NAT_T_KEEPALIVE_INTERVAL; gettimeofday(&now, 0); now.tv_sec += interval; sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive", nat_t_send_keepalive, v_arg, &now); if (!sa->nat_t_keepalive) log_print("nat_t_send_keepalive: " "timer_add_event() failed, will send no more keepalives"); } void nat_t_setup_keepalive(struct sa *sa) { struct sockaddr *src; struct timeval now; if (sa->initiator) sa->transport->vtbl->get_src(sa->transport, &src); else sa->transport->vtbl->get_dst(sa->transport, &src); if (!virtual_listen_lookup(src)) return; gettimeofday(&now, 0); now.tv_sec += NAT_T_KEEPALIVE_INTERVAL; sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive", nat_t_send_keepalive, sa, &now); if (!sa->nat_t_keepalive) log_print("nat_t_setup_keepalive: " "timer_add_event() failed, will not send keepalives"); LOG_DBG((LOG_TRANSPORT, 50, "nat_t_setup_keepalive: " "added event for phase 1 SA %p", sa)); } isakmpd-20041012.orig/README0000644000175000017500000000640610133045740015443 0ustar jdivejdive00000000000000$OpenBSD: README,v 1.19 2003/02/22 06:57:07 kjell Exp $ $EOM: README,v 1.28 1999/10/10 22:53:24 angelos Exp $ This is isakmpd, a BSD-licensed ISAKMP/Oakley (a.k.a. IKE) implementation. It's written by Niklas Hallqvist and Niels Provos, funded by Ericsson Radio Systems AB. Isakmpd's home is in the OpenBSD main source tree under src/sbin/isakmpd. Look at http://www.openbsd.org/ for details on how to get OpenBSD source. Isakmpd is being developed under OpenBSD, with OpenBSD as its primary target, however, it is ported to Linux with FreeS/WAN IPsec. The makefile support assumes a BSD environment nonetheless as it is not too hard to get such an environment to work under other operating systems. For example, Red Hat 5.2 shipped with pmake installed. Read sysdep/README for further details about this issue. Other systems isakmpd has been ported to, but no code has been made available for, includes Solaris and Win32s. I mention this just because it shows that the code is fairly portable. First edit the Makefile in a manner you see fit. Specifically the OS define is important to get right of course. Assuming you have an OpenBSD /usr/share/mk and use the OpenBSD (or similar) make(1), you build isakmpd this way: make obj && make depend && make Then obj/isakmpd will be the daemon. I suggest you try it by running under gdb with args similar to: -d -n -p5000 -DA=99 -f/tmp/isakmpd.fifo -csamples/VPN-east.conf That will run isakmpd in the foreground, not connected to any application (like an IPsec implementation) logging to stderr with full debugging output, listening on UDP port 5000, accepting control commands via the named pipe called /tmp/isakmpd.fifo and reading its configuration from the VPN-east.conf file (found in the isakmpd/samples directory). If you are root you can try to run without -n -p5000 thus getting it to talk to your IPsec stack and use the standard port 500 instead. The logging classes are Miscellaneous = 0, Transports = 1, Messages = 2, Crypto = 3, Timers = 4, System Dependencies = 5, Security Associations = 6, and Exchanges = 7. The debug levels increase in verbosity from 0 (off) to 99 (max). Read log.[ch] and ui.c to see how to alter the debugging levels. Now you have setup your daemon and can watch incoming negotiations. But how do you get such? Either use http://isakmp-test.ssh.fi/, there's an excellent service, just waiting for you. Or you can try to start another isakmpd on another port (say -p5001 or so, instead) and another fifo (let's say /tmp/other.fifo). Then edit the config file to have some peer descriptions that fit your need and issue a command like this: $ echo "c IPsec-east-west" >/tmp/other.fifo and watch. You can turn on debugging on that isakmpd too of course, for greater fun. This rudimentary user interface is slightly described in DESIGN-NOTES. If you are going to look at the config file, don't be scared, the man page isakmpd.conf(5) covers every detail, and the flexibility will be hidden under a userfriendlier layer in a later release. I did this first config-file syntax just because it should be easy to parse. The man page isakmpd.policy(5) describes the policy model used in conjunction with KeyNote. Happy IKEing! Niklas Hallqvist Niels Provos Håkan Olsson isakmpd-20041012.orig/message.h0000644000175000017500000001466710133045740016370 0ustar jdivejdive00000000000000/* $OpenBSD: message.h,v 1.22 2004/08/10 15:59:10 ho Exp $ */ /* $EOM: message.h,v 1.51 2000/10/10 12:36:39 provos Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2001, 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _MESSAGE_H_ #define _MESSAGE_H_ #include #include #include #include #include "isakmp.h" struct event; struct message; struct proto; struct sa; struct transport; struct payload { /* Link all payloads of the same type through here. */ TAILQ_ENTRY(payload) link; /* The pointer to the actual payload data. */ u_int8_t *p; /* * A pointer to the parent payload, used for proposal and transform * payloads. */ struct payload *context; /* Payload flags described below. */ int flags; }; /* Payload flags. */ /* * Set this when a payload has been handled, so we later can sweep over * unhandled ones. */ #define PL_MARK 1 /* A post-send chain of functions to be called. */ struct post_send { /* Link to the next function in the chain. */ TAILQ_ENTRY(post_send) link; /* The actual function. */ void (*func) (struct message *); }; struct message { /* Link message in send queues via this link. */ TAILQ_ENTRY(message) link; /* Message flags described below. */ u_int flags; /* * This is the transport the message either arrived on or will be sent * to. */ struct transport *transport; /* * This is the ISAKMP SA protecting this message. * XXX Needs to be redone to some keystate pointer or something. */ struct sa *isakmp_sa; /* This is the exchange where this message appears. */ struct exchange *exchange; /* * A segmented buffer structure holding the messages raw contents. On * input only segment 0 will be filled, holding all of the message. * On output, as long as the message body is unencrypted each segment * will be one payload, after encryption segment 0 will be the * unencrypted header, and segment 1 will be the encrypted payloads, * all of them. */ struct iovec *iov; /* The segment count. */ u_int iovlen; /* Pointer to the last "next payload" field. */ u_int8_t *nextp; /* "Smart" pointers to each payload, sorted by type. */ TAILQ_HEAD(payload_head, payload) *payload; /* Number of times this message has been sent. */ int xmits; /* The timeout event causing retransmission of this message. */ struct event *retrans; /* The (possibly encrypted) message text, used for duplicate testing. */ u_int8_t *orig; size_t orig_sz; /* * Extra baggage needed to travel with the message. Used transiently * in context sensitive ways. */ void *extra; /* * Hooks for stuff needed to be done after the message has gone out to * the wire. */ TAILQ_HEAD(post_send_head, post_send) post_send; }; /* Message flags. */ /* * This is the last message of an exchange, meaning it should not be * retransmitted other than if we see duplicates from our peer's last * message. */ #define MSG_LAST 0x01 /* The message has already been encrypted. */ #define MSG_ENCRYPTED 0x02 /* The message is on the send queue. */ #define MSG_IN_TRANSIT 0x04 /* This message should be kept on the prioritized sendq. */ #define MSG_PRIORITIZED 0x08 /* This message has successfully been authenticated. */ #define MSG_AUTHENTICATED 0x10 TAILQ_HEAD(msg_head, message); /* The number of different ISAKMP payloads supported. */ extern u_int8_t payload_index_max; extern int message_add_payload(struct message *, u_int8_t, u_int8_t *, size_t, int); extern int message_add_sa_payload(struct message *); extern struct message *message_alloc(struct transport *, u_int8_t *, size_t); extern struct message *message_alloc_reply(struct message *); extern u_int8_t *message_copy(struct message *, size_t, size_t *); extern void message_drop(struct message *, int, struct proto *, int, int); extern void message_dump_raw(char *, struct message *, int); extern void message_free(struct message *); extern void message_init(void); extern int message_negotiate_sa(struct message *, int (*)(struct exchange *, struct sa *, struct sa *)); extern int message_recv(struct message *); extern int message_register_post_send(struct message *, void (*) (struct message *)); extern void message_post_send(struct message *); extern void message_send(struct message *); extern void message_send_expire(struct message *); extern void message_send_delete(struct sa *); extern int message_send_info(struct message *); extern void message_send_notification(struct message *, struct sa *, u_int16_t, struct proto *, int); extern void message_setup_header(struct message *, u_int8_t, u_int8_t, u_int8_t *); struct payload *payload_first(struct message *, u_int8_t); struct payload *payload_last(struct message *, u_int8_t); #if defined (USE_DPD) extern void message_send_dpd_notify(struct sa*, u_int16_t, u_int32_t); #endif #endif /* _MESSAGE_H_ */ isakmpd-20041012.orig/attribute.c0000644000175000017500000000710210133045740016724 0ustar jdivejdive00000000000000/* $OpenBSD: attribute.c,v 1.11 2004/05/14 08:42:56 hshoexer Exp $ */ /* $EOM: attribute.c,v 1.10 2000/02/20 19:58:36 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include "sysdep.h" #include "attribute.h" #include "conf.h" #include "log.h" #include "isakmp.h" #include "util.h" u_int8_t * attribute_set_basic(u_int8_t *buf, u_int16_t type, u_int16_t value) { SET_ISAKMP_ATTR_TYPE(buf, ISAKMP_ATTR_MAKE(1, type)); SET_ISAKMP_ATTR_LENGTH_VALUE(buf, value); return buf + ISAKMP_ATTR_VALUE_OFF; } u_int8_t * attribute_set_var(u_int8_t *buf, u_int16_t type, u_int8_t *value, u_int16_t len) { SET_ISAKMP_ATTR_TYPE(buf, ISAKMP_ATTR_MAKE(0, type)); SET_ISAKMP_ATTR_LENGTH_VALUE(buf, len); memcpy(buf + ISAKMP_ATTR_VALUE_OFF, value, len); return buf + ISAKMP_ATTR_VALUE_OFF + len; } /* * Execute a function FUNC taking an attribute type, value, length and ARG * as arguments for each attribute in the area of ISAKMP attributes located * at BUF, sized SZ. If any invocation fails, the processing aborts with a * -1 return value. If all goes well return zero. */ int attribute_map(u_int8_t *buf, size_t sz, int (*func)(u_int16_t, u_int8_t *, u_int16_t, void *), void *arg) { u_int8_t *attr; int fmt; u_int16_t type; u_int8_t *value; u_int16_t len; for (attr = buf; attr < buf + sz; attr = value + len) { if (attr + ISAKMP_ATTR_VALUE_OFF > buf + sz) return -1; type = GET_ISAKMP_ATTR_TYPE(attr); fmt = ISAKMP_ATTR_FORMAT(type); type = ISAKMP_ATTR_TYPE(type); value = attr + (fmt ? ISAKMP_ATTR_LENGTH_VALUE_OFF : ISAKMP_ATTR_VALUE_OFF); len = (fmt ? ISAKMP_ATTR_LENGTH_VALUE_LEN : GET_ISAKMP_ATTR_LENGTH_VALUE(attr)); if (value + len > buf + sz) return -1; if (func(type, value, len, arg)) return -1; } return 0; } int attribute_set_constant(char *section, char *tag, struct constant_map *map, int attr_class, u_int8_t **attr) { char *name; int value; name = conf_get_str(section, tag); if (!name) { LOG_DBG((LOG_MISC, 70, "attribute_set_constant: no %s in the %s section", tag, section)); return -1; } value = constant_value(map, name); *attr = attribute_set_basic(*attr, attr_class, value); return 0; } isakmpd-20041012.orig/field.c0000644000175000017500000001455510133045740016016 0ustar jdivejdive00000000000000/* $OpenBSD: field.c,v 1.16 2004/06/14 09:55:41 ho Exp $ */ /* $EOM: field.c,v 1.11 2000/02/20 19:58:37 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include "sysdep.h" #include "constants.h" #include "field.h" #include "log.h" #include "util.h" static char *field_debug_raw(u_int8_t *, size_t, struct constant_map **); static char *field_debug_num(u_int8_t *, size_t, struct constant_map **); static char *field_debug_mask(u_int8_t *, size_t, struct constant_map **); static char *field_debug_ign(u_int8_t *, size_t, struct constant_map **); static char *field_debug_cst(u_int8_t *, size_t, struct constant_map **); /* Contents must match the enum in struct field. */ static char *(*decode_field[]) (u_int8_t *, size_t, struct constant_map **) = { field_debug_raw, field_debug_num, field_debug_mask, field_debug_ign, field_debug_cst }; /* * Return a string showing the hexadecimal contents of the LEN-sized buffer * BUF. MAPS should be zero and is only here because the API requires it. */ static char * field_debug_raw(u_int8_t *buf, size_t len, struct constant_map **maps) { char *retval, *p; if (len == 0) return 0; retval = malloc(3 + len * 2); if (!retval) return 0; strlcpy(retval, "0x", 3 + len * 2); p = retval + 2; for (; len > 0; len--) { snprintf(p, 1 + len * 2, "%02x", *buf++); p += 2; } return retval; } /* * Convert the unsigned LEN-sized number at BUF of network byteorder to a * 32-bit unsigned integer of host byteorder pointed to by VAL. */ static int extract_val(u_int8_t *buf, size_t len, u_int32_t *val) { switch (len) { case 1: *val = *buf; break; case 2: *val = decode_16(buf); break; case 4: *val = decode_32(buf); break; default: return -1; } return 0; } /* * Return a textual representation of the unsigned number pointed to by BUF * which is LEN octets long. MAPS should be zero and is only here because * the API requires it. */ static char * field_debug_num(u_int8_t *buf, size_t len, struct constant_map **maps) { char *retval; u_int32_t val; if (extract_val(buf, len, &val)) return 0; /* 3 decimal digits are enough to represent each byte. */ retval = malloc(3 * len); snprintf(retval, 3 * len, "%u", val); return retval; } /* * Return the symbolic names of the flags pointed to by BUF which is LEN * octets long, using the constant maps MAPS. */ static char * field_debug_mask(u_int8_t *buf, size_t len, struct constant_map **maps) { u_int32_t val; u_int32_t bit; char *retval, *new_buf, *name; size_t buf_sz; if (extract_val(buf, len, &val)) return 0; /* Size for brackets, two spaces and a NUL terminator. */ buf_sz = 4; retval = malloc(buf_sz); if (!retval) return 0; strlcpy(retval, "[ ", buf_sz); for (bit = 1; bit; bit <<= 1) { if (val & bit) { name = constant_name_maps(maps, bit); buf_sz += strlen(name) + 1; new_buf = realloc(retval, buf_sz); if (!new_buf) { free(retval); return 0; } retval = new_buf; strlcat(retval, name, buf_sz); strlcat(retval, " ", buf_sz); } } strlcat(retval, "]", buf_sz); return retval; } /* * Just a dummy needed to skip the unused LEN sized space at BUF. MAPS * should be zero and is only here because the API requires it. */ static char * field_debug_ign(u_int8_t *buf, size_t len, struct constant_map **maps) { return 0; } /* * Return the symbolic name of a constant pointed to by BUF which is LEN * octets long, using the constant maps MAPS. */ static char * field_debug_cst(u_int8_t *buf, size_t len, struct constant_map **maps) { u_int32_t val; if (extract_val(buf, len, &val)) return 0; return strdup(constant_name_maps(maps, val)); } /* Pretty-print a field from BUF as described by F. */ void field_dump_field(struct field *f, u_int8_t *buf) { char *value; value = decode_field[(int) f->type] (buf + f->offset, f->len, f->maps); if (value) { LOG_DBG((LOG_MESSAGE, 70, "%s: %s", f->name, value)); free(value); } } /* Pretty-print all the fields of BUF as described in FIELDS. */ void field_dump_payload(struct field *fields, u_int8_t *buf) { struct field *field; for (field = fields; field->name; field++) field_dump_field(field, buf); } /* Return the numeric value of the field F of BUF. */ u_int32_t field_get_num(struct field *f, u_int8_t *buf) { u_int32_t val; if (extract_val(buf + f->offset, f->len, &val)) return 0; return val; } /* Stash the number VAL into BUF's field F. */ void field_set_num(struct field *f, u_int8_t *buf, u_int32_t val) { switch (f->len) { case 1: buf[f->offset] = val; break; case 2: encode_16(buf + f->offset, val); break; case 4: encode_32(buf + f->offset, val); break; } } /* Stash BUF's raw field F into VAL. */ void field_get_raw(struct field *f, u_int8_t *buf, u_int8_t *val) { memcpy(val, buf + f->offset, f->len); } /* Stash the buffer VAL into BUF's field F. */ void field_set_raw(struct field *f, u_int8_t *buf, u_int8_t *val) { memcpy(buf + f->offset, val, f->len); } isakmpd-20041012.orig/udp_encap.c0000644000175000017500000003016210133045740016661 0ustar jdivejdive00000000000000/* $OpenBSD: udp_encap.c,v 1.8 2004/09/24 13:31:04 ho Exp $ */ /* * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2000 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2004 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. * * 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 #include #include #ifndef linux #include #endif #include #include #include #include #include #include #include #include #include #include #include "sysdep.h" #include "conf.h" #include "if.h" #include "ipsec_doi.h" #include "isakmp.h" #include "log.h" #include "message.h" #include "monitor.h" #include "sysdep.h" #include "transport.h" #include "udp.h" #include "udp_encap.h" #include "util.h" #include "virtual.h" #define UDP_SIZE 65536 /* If a system doesn't have SO_REUSEPORT, SO_REUSEADDR will have to do. */ #ifndef SO_REUSEPORT #define SO_REUSEPORT SO_REUSEADDR #endif /* Reused, from udp.c */ struct transport *udp_clone(struct transport *, struct sockaddr *); int udp_fd_set(struct transport *, fd_set *, int); int udp_fd_isset(struct transport *, fd_set *); void udp_get_dst(struct transport *, struct sockaddr **); void udp_get_src(struct transport *, struct sockaddr **); char *udp_decode_ids(struct transport *); void udp_remove(struct transport *); static struct transport *udp_encap_create(char *); static void udp_encap_report(struct transport *); static void udp_encap_handle_message(struct transport *); static struct transport *udp_encap_make(struct sockaddr *); static int udp_encap_send_message(struct message *, struct transport *); static struct transport_vtbl udp_encap_transport_vtbl = { { 0 }, "udp_encap", udp_encap_create, 0, udp_remove, udp_encap_report, udp_fd_set, udp_fd_isset, udp_encap_handle_message, udp_encap_send_message, udp_get_dst, udp_get_src, udp_decode_ids, udp_clone, 0 }; char *udp_encap_default_port = 0; char *udp_encap_bind_port = 0; void udp_encap_init(void) { transport_method_add(&udp_encap_transport_vtbl); } /* Create a UDP transport structure bound to LADDR just for listening. */ static struct transport * udp_encap_make(struct sockaddr *laddr) { struct udp_transport *t = 0; int s, on, wildcardaddress = 0; char *tstr; t = calloc(1, sizeof *t); if (!t) { log_print("udp_encap_make: malloc (%lu) failed", (unsigned long)sizeof *t); return 0; } s = socket(laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP); if (s == -1) { log_error("udp_encap_make: socket (%d, %d, %d)", laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP); goto err; } /* Make sure we don't get our traffic encrypted. */ if (sysdep_cleartext(s, laddr->sa_family) == -1) goto err; /* Wildcard address ? */ switch (laddr->sa_family) { case AF_INET: if (((struct sockaddr_in *)laddr)->sin_addr.s_addr == INADDR_ANY) wildcardaddress = 1; break; case AF_INET6: if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)laddr)->sin6_addr)) wildcardaddress = 1; break; } /* * In order to have several bound specific address-port combinations * with the same port SO_REUSEADDR is needed. * If this is a wildcard socket and we are not listening there, but * only sending from it make sure it is entirely reuseable with * SO_REUSEPORT. */ on = 1; if (setsockopt(s, SOL_SOCKET, wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR, (void *)&on, sizeof on) == -1) { log_error("udp_encap_make: setsockopt (%d, %d, %d, %p, %lu)", s, SOL_SOCKET, wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR, &on, (unsigned long)sizeof on); goto err; } t->transport.vtbl = &udp_encap_transport_vtbl; t->src = laddr; if (monitor_bind(s, t->src, sysdep_sa_len (t->src))) { if (sockaddr2text(t->src, &tstr, 0)) log_error("udp_encap_make: bind (%d, %p, %lu)", s, &t->src, (unsigned long)sizeof t->src); else { log_error("udp_encap_make: bind (%d, %s, %lu)", s, tstr, (unsigned long)sizeof t->src); free(tstr); } goto err; } t->s = s; if (sockaddr2text(t->src, &tstr, 0)) LOG_DBG((LOG_MISC, 20, "udp_encap_make: " "transport %p socket %d family %d", t, s, t->src->sa_family == AF_INET ? 4 : 6)); else { LOG_DBG((LOG_MISC, 20, "udp_encap_make: " "transport %p socket %d ip %s port %d", t, s, tstr, ntohs(sockaddr_port(t->src)))); free(tstr); } transport_setup(&t->transport, 0); t->transport.flags |= TRANSPORT_LISTEN; return &t->transport; err: if (s >= 0) close (s); if (t) { /* Already closed. */ t->s = -1; udp_remove(&t->transport); } return 0; } /* * Initialize an object of the UDP transport class. Fill in the local * IP address and port information and create a server socket bound to * that specific port. Add the polymorphic transport structure to the * system-wide pools of known ISAKMP transports. */ struct transport * udp_encap_bind(const struct sockaddr *addr) { struct sockaddr *src = malloc(sysdep_sa_len((struct sockaddr *)addr)); if (!src) return 0; memcpy(src, addr, sysdep_sa_len((struct sockaddr *)addr)); return udp_encap_make(src); } /* * NAME is a section name found in the config database. Setup and return * a transport useable to talk to the peer specified by that name. */ static struct transport * udp_encap_create(char *name) { struct virtual_transport *v; struct udp_transport *u; struct transport *rv, *t; struct sockaddr *dst, *addr; struct conf_list *addr_list = 0; struct conf_list_node *addr_node; char *addr_str, *port_str; port_str = conf_get_str(name, "Port"); /* XXX "Encap-port" ? */ if (!port_str) port_str = udp_encap_default_port; if (!port_str) port_str = UDP_ENCAP_DEFAULT_PORT_STR; addr_str = conf_get_str(name, "Address"); if (!addr_str) { log_print("udp_encap_create: no address configured " "for \"%s\"", name); return 0; } if (text2sockaddr(addr_str, port_str, &dst)) { log_print("udp_encap_create: address \"%s\" not understood", addr_str); return 0; } addr_str = conf_get_str(name, "Local-address"); if (!addr_str) addr_list = conf_get_list("General", "Listen-on"); if (!addr_str && !addr_list) { v = virtual_get_default(dst->sa_family); u = (struct udp_transport *)v->encap; if (!u) { log_print("udp_encap_create: no default transport"); rv = 0; goto ret; } else { rv = udp_clone((struct transport *)u, dst); if (rv) rv->vtbl = &udp_encap_transport_vtbl; goto ret; } } if (addr_list) { for (addr_node = TAILQ_FIRST(&addr_list->fields); addr_node; addr_node = TAILQ_NEXT(addr_node, link)) if (text2sockaddr(addr_node->field, port_str, &addr) == 0) { v = virtual_listen_lookup(addr); free(addr); if (v) { addr_str = addr_node->field; break; } } if (!addr_str) { log_print("udp_encap_create: " "no matching listener found"); rv = 0; goto ret; } } if (text2sockaddr(addr_str, port_str, &addr)) { log_print("udp_encap_create: " "address \"%s\" not understood", addr_str); rv = 0; goto ret; } v = virtual_listen_lookup(addr); free(addr); if (!v) { log_print("udp_encap_create: " "%s:%s must exist as a listener too", addr_str, port_str); rv = 0; goto ret; } t = (struct transport *)v; rv = udp_clone(v->encap, dst); if (rv) rv->vtbl = &udp_encap_transport_vtbl; ret: if (addr_list) conf_free_list(addr_list); free(dst); return rv; } /* Report transport-method specifics of the T transport. */ void udp_encap_report(struct transport *t) { struct udp_transport *u = (struct udp_transport *)t; char *src, *dst; in_port_t sport, dport; if (sockaddr2text(u->src, &src, 0)) goto ret; sport = sockaddr_port(u->src); if (!u->dst || sockaddr2text(u->dst, &dst, 0)) dst = 0; dport = dst ? sockaddr_port(u->dst) : 0; LOG_DBG ((LOG_REPORT, 0, "udp_encap_report: fd %d src %s:%u dst %s:%u", u->s, src, ntohs(sport), dst ? dst : "*", ntohs(dport))); ret: if (dst) free(dst); if (src) free(src); } /* * A message has arrived on transport T's socket. If T is single-ended, * clone it into a double-ended transport which we will use from now on. * Package the message as we want it and continue processing in the message * module. */ static void udp_encap_handle_message(struct transport *t) { struct udp_transport *u = (struct udp_transport *)t; struct sockaddr_storage from; struct message *msg; u_int32_t len = sizeof from; ssize_t n; u_int8_t buf[UDP_SIZE]; n = recvfrom(u->s, buf, UDP_SIZE, 0, (struct sockaddr *)&from, &len); if (n == -1) { log_error("recvfrom (%d, %p, %d, %d, %p, %p)", u->s, buf, UDP_SIZE, 0, &from, &len); return; } /* * Make a specialized UDP transport structure out of the incoming * transport and the address information we got from recvfrom(2). */ t = t->virtual->vtbl->clone(t->virtual, (struct sockaddr *)&from); if (!t) return; /* Check NULL-ESP marker. */ if (n < (ssize_t)sizeof(u_int32_t) || *(u_int32_t *)buf != 0) { /* Should never happen. */ log_print("udp_encap_handle_message: " "Null-ESP marker not NULL or short message"); return; } /* NAT-Keepalive messages should not be processed further. */ n -= sizeof(u_int32_t); if (n == 1 && buf[sizeof(u_int32_t)] == 0xFF) return; msg = message_alloc(t, buf + sizeof (u_int32_t), n); if (!msg) { log_error("failed to allocate message structure, dropping " "packet received on transport %p", u); return; } message_recv(msg); } /* * Physically send the message MSG over its associated transport. * Special: if 'msg' is NULL, send a NAT-T keepalive message. */ static int udp_encap_send_message(struct message *msg, struct transport *t) { struct udp_transport *u = (struct udp_transport *)t; struct msghdr m; struct iovec *new_iov = 0, keepalive; ssize_t n; u_int32_t marker = 0; /* NULL-ESP Marker */ if (msg) { /* Construct new iov array, prefixing NULL-ESP Marker. */ new_iov = (struct iovec *)calloc (msg->iovlen + 1, sizeof *new_iov); if (!new_iov) { log_error ("udp_encap_send_message: " "calloc (%lu, %lu) failed", (unsigned long)msg->iovlen + 1, (unsigned long)sizeof *new_iov); return -1; } new_iov[0].iov_base = ▮ new_iov[0].iov_len = IPSEC_SPI_SIZE; memcpy (new_iov + 1, msg->iov, msg->iovlen * sizeof *new_iov); } else { marker = ~marker; keepalive.iov_base = ▮ keepalive.iov_len = 1; } /* * Sending on connected sockets requires that no destination address is * given, or else EISCONN will occur. */ m.msg_name = (caddr_t)u->dst; m.msg_namelen = sysdep_sa_len (u->dst); m.msg_iov = msg ? new_iov : &keepalive; m.msg_iovlen = msg ? msg->iovlen + 1 : 1; m.msg_control = 0; m.msg_controllen = 0; m.msg_flags = 0; n = sendmsg (u->s, &m, 0); if (msg) free (new_iov); if (n == -1) { /* XXX We should check whether the address has gone away */ log_error ("sendmsg (%d, %p, %d)", u->s, &m, 0); return -1; } return 0; } isakmpd-20041012.orig/apps/0000755000175000017500000000000010133045740015520 5ustar jdivejdive00000000000000isakmpd-20041012.orig/apps/Makefile0000644000175000017500000000275710133045740017173 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.2 2003/06/03 14:35:00 ho Exp $ # $EOM: Makefile,v 1.2 1999/07/17 20:44:12 niklas Exp $ # # Copyright (c) 1999 Niels Provos. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # SUBDIR= certpatch .include isakmpd-20041012.orig/apps/certpatch/0000755000175000017500000000000010133045740017475 5ustar jdivejdive00000000000000isakmpd-20041012.orig/apps/certpatch/Makefile0000644000175000017500000000443510133045740021143 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.7 2003/06/03 14:35:00 ho Exp $ # $EOM: Makefile,v 1.6 2000/03/28 21:22:06 ho Exp $ # # Copyright (c) 1999 Niels Provos. All rights reserved. # Copyright (c) 2001 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # PROG= certpatch SRCS= certpatch.c BINDIR?= /usr/sbin TOPSRC= ${.CURDIR}/../.. TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f- OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile FEATURES!= awk '/^FEATURES=/ { print $$0 }' ${.CURDIR}/../../Makefile | sed 's/FEATURES=.//' .PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ} CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall LDADD+= -lcrypto DPADD+= ${LIBCRYPTO} MAN= certpatch.8 .if ${FEATURES:Mgmp} == "gmp" CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP LDADD+= -lgmp DPADD+= ${LIBGMP} .else CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL .endif .include "${TOPSRC}/sysdep/${OS}/Makefile.sysdep" # Override LIBSYSDEPDIR definition from Makefile.sysdep LIBSYSDEPDIR= ${TOPSRC}/sysdep/common/libsysdep .include isakmpd-20041012.orig/apps/certpatch/certpatch.c0000644000175000017500000002047410133045740021625 0ustar jdivejdive00000000000000/* $OpenBSD: certpatch.c,v 1.21 2003/06/04 07:31:17 ho Exp $ */ /* $EOM: certpatch.c,v 1.11 2000/12/21 14:50:09 ho Exp $ */ /* * Copyright (c) 1999 Niels Provos. All rights reserved. * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2001 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * This program takes a certificate generated by ssleay and a * private key. It encodes a new id as subject alt name * extension into the certifcate. The result gets written as * new certificate that can be used by isakmpd. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sysdep.h" #ifdef KAME # ifdef CRYPTO # include # endif #else # include #endif #include #include #include "conf.h" #include "ipsec_num.h" #include "log.h" #include "math_mp.h" #include "x509.h" #define IDTYPE_IP "ip" #define IDTYPE_FQDN "fqdn" #define IDTYPE_UFQDN "ufqdn" int main (int argc, char **argv) { char *usage = "%s [-t idtype] -i id -k keyfile certin certout\n\n" "This programs takes a certificate and adds a subjectAltName extension\n" "with the identication given as command line argument. Be sure that \n" "the signing key matches the issuer.\n"; EVP_PKEY *pkey_priv; X509 *cert; BIO *file; const EVP_MD *digest; X509_EXTENSION *ex = NULL; ASN1_OCTET_STRING *data = NULL; struct in_addr saddr; unsigned char ipaddr[6], *new_id; char *type = IDTYPE_IP, *keyfile = NULL, *id = NULL; char *certin, *certout; int ch, err; #if SSLEAY_VERSION_NUMBER >= 0x00904100L unsigned char *p; ASN1_STRING str; int i; #endif /* read command line arguments */ while ((ch = getopt (argc, argv, "t:k:i:")) != -1) switch (ch) { case 't': type = optarg; break; case 'k': keyfile = optarg; break; case 'i': id = optarg; break; default: fprintf (stderr, usage, argv[0]); return (1); } argc -= optind; if (argc != 2) { fprintf (stderr, usage, argv[0]); return (1); } argv += optind; certin = argv[0]; certout = argv[1]; /* Check ID */ if ((strcasecmp (IDTYPE_IP, type) != 0 && strcasecmp (IDTYPE_FQDN, type) != 0 && strcasecmp (IDTYPE_UFQDN, type) != 0) || id == NULL) { printf ("wrong id type or missing id\n"); return (1); } /* * X509_verify will fail, as will all other functions that call * EVP_get_digest_byname. */ SSLeay_add_all_algorithms (); /* Use a certificate created by ssleay and add the appr. extension */ printf ("Reading ssleay created certificate %s and modify it\n", certin); file = BIO_new (BIO_s_file ()); if (BIO_read_filename (file, certin) == -1) { perror ("read"); return (1); } #if SSLEAY_VERSION_NUMBER >= 0x00904100L cert = PEM_read_bio_X509 (file, NULL, NULL, NULL); #else cert = PEM_read_bio_X509 (file, NULL, NULL); #endif BIO_free (file); if (cert == NULL) { printf ("PEM_read_bio_X509 () failed\n"); return (1); } /* Get the digest for the actual signing */ digest = EVP_get_digestbyname (OBJ_nid2sn (OBJ_obj2nid (cert->sig_alg->algorithm))); if (!X509_set_version (cert, 2)) { printf ("X509 failed to set version number\n"); return (1); } if (!strcasecmp (IDTYPE_IP, type)) { if (inet_aton (id, &saddr) == 0) { printf ("inet_aton () failed\n"); return (1); } saddr.s_addr = htonl (saddr.s_addr); ipaddr[0] = 0x87; ipaddr[1] = 0x04; ipaddr[2] = saddr.s_addr >> 24; ipaddr[3] = (saddr.s_addr >> 16) & 0xff; ipaddr[4] = (saddr.s_addr >> 8) & 0xff; ipaddr[5] = saddr.s_addr & 0xff; #if SSLEAY_VERSION_NUMBER >= 0x00904100L str.length = 6; str.type = V_ASN1_OCTET_STRING; str.data = ipaddr; data = ASN1_OCTET_STRING_new (); if (!data) { perror ("ASN1_OCTET_STRING_new() failed"); return (1); } i = i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, NULL); if (!ASN1_STRING_set ((ASN1_STRING *)data,NULL,i)) { perror ("ASN1_STRING_set() failed"); return (1); } p = (unsigned char *)data->data; i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, &p); data->length = i; #else data = X509v3_pack_string (NULL, V_ASN1_OCTET_STRING, ipaddr, 6); #endif } else if (!strcasecmp (IDTYPE_FQDN, type) || !strcasecmp (IDTYPE_UFQDN, type)) { new_id = malloc (strlen (id) + 2); if (new_id == NULL) { printf ("malloc () failed\n"); return (1); } if (!strcasecmp (IDTYPE_FQDN, type)) new_id[0] = 0x82; else new_id[0] = 0x81; /* IDTYPE_UFQDN */ memcpy (new_id + 2, id, strlen(id)); new_id[1] = strlen (id); #if SSLEAY_VERSION_NUMBER >= 0x00904100L str.length = strlen (id) + 2; str.type = V_ASN1_OCTET_STRING; str.data = new_id; data = ASN1_OCTET_STRING_new (); if (!data) { perror ("ASN1_OCTET_STRING_new() failed"); return (1); } i = i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, NULL); if (!ASN1_STRING_set ((ASN1_STRING *)data,NULL,i)) { perror ("ASN1_STRING_set() failed"); return (1); } p = (unsigned char *)data->data; i2d_ASN1_OCTET_STRING ((ASN1_OCTET_STRING *)&str, &p); data->length = i; #else data = X509v3_pack_string (NULL, V_ASN1_OCTET_STRING, new_id, strlen (id) + 2); #endif free (new_id); } /* XXX This is a hack, how to do better? */ data->type = 0x30; data->data[0] = 0x30; ex = X509_EXTENSION_create_by_NID (NULL, NID_subject_alt_name, 1, data); if (ex == NULL) { printf ("X509_EXTENSION_create ()\n"); return (1); } X509_add_ext (cert, ex, -1); file = BIO_new (BIO_s_file ()); if (BIO_read_filename (file, keyfile) == -1) { perror ("open"); return (1); } #if SSLEAY_VERSION_NUMBER >= 0x00904100L if ((pkey_priv = PEM_read_bio_PrivateKey (file, NULL, NULL, NULL)) == NULL) #else if ((pkey_priv = PEM_read_bio_PrivateKey (file, NULL, NULL)) == NULL) #endif { printf ("Can not read private key %s\n", keyfile); return (1); } BIO_free (file); printf ("Creating Signature: PKEY_TYPE = %s: ", pkey_priv->type == EVP_PKEY_RSA ? "RSA" : "unknown"); err = X509_sign (cert, pkey_priv, digest); printf ("X509_sign: %d ", err); if (!err) printf ("FAILED "); else printf ("OKAY "); printf ("\n"); file = BIO_new (BIO_s_file ()); if (BIO_write_filename (file, certout) == -1) { perror ("open"); return (1); } printf ("Writing new certificate to %s\n", certout); PEM_write_bio_X509 (file, cert); BIO_free (file); return (0); } isakmpd-20041012.orig/apps/certpatch/.cvsignore0000644000175000017500000000003510133045740021473 0ustar jdivejdive00000000000000certpatch certpatch.cat8 obj isakmpd-20041012.orig/apps/certpatch/CVS/0000755000175000017500000000000010133045751020132 5ustar jdivejdive00000000000000isakmpd-20041012.orig/apps/certpatch/certpatch.80000644000175000017500000000553110133045740021547 0ustar jdivejdive00000000000000.\" $OpenBSD: certpatch.8,v 1.8 2003/06/04 07:31:17 ho Exp $ .\" $EOM: certpatch.8,v 1.5 2000/04/07 22:17:11 niklas Exp $ .\" .\" Copyright (c) 1999 Niklas Hallqvist. All rights reserved. .\" Copyright (c) 1999 Angelos D. Keromytis. 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. .\" .\" 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. .\" .\" This code was written under funding by Ericsson Radio Systems. .\" .\" Manual page, using -mandoc macros .\" .Dd July 18, 1999 .Dt CERTPATCH 8 .Os .Sh NAME .Nm certpatch .Nd add subjectAltName identities to X.509 certificates .Sh SYNOPSIS .Nm certpatch .Op Fl t Ar identity-type .Fl i .Ar identity .Fl k .Ar signing-key .Ar input-certificate output-certificate .Sh DESCRIPTION .Nm alters PEM-encoded X.509 certificates by adding a subjectAltName extension containing an identity used by the signature-based authentication schemes of the ISAKMP protocol. After the addition the certificate will be signed once again with the supplied CA signing key. .Pp The options are as follows: .Bl -tag -width Ds .It Fl t Ar identity-type If given, the .Fl t option specifies the type of the given identity. Currently .Li ip , .Li fqdn , and .Li ufqdn are recognized. The default is .Li ip . .It Fl i Ar identity The .Fl i option takes an argument which is the identity to put into the subjectAltName field of the certificate. If the identity-type is .Li ip , this argument should be an IPv4 address in dotted decimal notation. .It Fl k Ar signing-key The .Fl k option specifies the key used for signing the certificate once the subjectAltName extension has been added. The key is specified by the filename where it is stored in PEM format. .El .Sh SEE ALSO .Xr isakmpd 8 , .Xr ssl 8 isakmpd-20041012.orig/apps/CVS/0000755000175000017500000000000010133045751016155 5ustar jdivejdive00000000000000isakmpd-20041012.orig/util.h0000644000175000017500000000546210133045740015712 0ustar jdivejdive00000000000000/* $OpenBSD: util.h,v 1.21 2004/06/23 03:01:53 hshoexer Exp $ */ /* $EOM: util.h,v 1.10 2000/10/24 13:33:39 niklas Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. All rights reserved. * Copyright (c) 2001, 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _UTIL_H_ #define _UTIL_H_ #include extern int allow_name_lookups; extern int regrand; extern unsigned long seed; struct message; struct sockaddr; extern int check_file_secrecy_fd(int, char *, size_t *); extern u_int16_t decode_16(u_int8_t *); extern u_int32_t decode_32(u_int8_t *); extern u_int64_t decode_64(u_int8_t *); #if 0 extern void decode_128(u_int8_t *, u_int8_t *); #endif extern void encode_16(u_int8_t *, u_int16_t); extern void encode_32(u_int8_t *, u_int32_t); extern void encode_64(u_int8_t *, u_int64_t); #if 0 extern void encode_128(u_int8_t *, u_int8_t *); #endif extern u_int8_t *getrandom(u_int8_t *, size_t); extern int hex2raw(char *, u_int8_t *, size_t); extern int ones_test(const u_int8_t *, size_t); extern int sockaddr2text(struct sockaddr *, char **, int); extern u_int8_t *sockaddr_addrdata(struct sockaddr *); extern int sockaddr_addrlen(struct sockaddr *); extern in_port_t sockaddr_port(struct sockaddr *); extern void sockaddr_set_port(struct sockaddr *, in_port_t); extern int text2sockaddr(char *, char *, struct sockaddr **); extern void util_ntoa(char **, int, u_int8_t *); extern int zero_test(const u_int8_t *, size_t); #endif /* _UTIL_H_ */ isakmpd-20041012.orig/math_group.h0000644000175000017500000000662210133045740017101 0ustar jdivejdive00000000000000/* $OpenBSD: math_group.h,v 1.10 2004/04/15 18:39:26 deraadt Exp $ */ /* $EOM: math_group.h,v 1.7 1999/04/17 23:20:40 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _MATH_GROUP_H_ #define _MATH_GROUP_H_ enum groups { MODP, /* F_p, Z modulo a prime */ EC2N, /* Elliptic Curve over the Field GF(2**N) */ ECP, /* Elliptic Curve over the Field Z_p */ NOTYET /* Not yet assigned */ }; /* * The group on which diffie hellmann calculations are done. */ struct group { enum groups type; int id; /* Group ID */ int bits; /* Number of key bits provided by this group */ void *group; void *a, *b, *c, *d; void *gen; /* Group Generator */ int (*getlen) (struct group *); void (*getraw) (struct group *, void *, u_int8_t *); int (*setraw) (struct group *, void *, u_int8_t *, int); int (*setrandom) (struct group *, void *); int (*operation) (struct group *, void *, void *, void *); }; /* Description of an Elliptic Group over GF(2**n) for Boot-Strapping */ struct ec2n_dscr { int id; int bits; /* Key Bits provided by this group */ char *polynomial; /* Irreduceable polynomial */ char *gen_x; /* X - Coord. of Generator */ char *a, *b; /* Curve Parameters */ }; /* Description of F_p for Boot-Strapping */ struct modp_dscr { int id; int bits; /* Key Bits provided by this group */ char *prime; /* Prime */ char *gen; /* Generator */ }; /* Prototypes */ void group_init(void); void group_free(struct group *); struct group *group_get(u_int32_t); void ec2n_free(struct group *); struct group *ec2n_clone(struct group *, struct group *); void ec2n_init(struct group *); void modp_free(struct group *); struct group *modp_clone(struct group *, struct group *); void modp_init(struct group *); #endif /* _MATH_GROUP_H_ */ isakmpd-20041012.orig/ui.c0000644000175000017500000002772410133045740015352 0ustar jdivejdive00000000000000/* $OpenBSD: ui.c,v 1.42 2004/08/08 19:11:06 deraadt Exp $ */ /* $EOM: ui.c,v 1.43 2000/10/05 09:25:12 niklas Exp $ */ /* * Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2000, 2001, 2002 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include #include "sysdep.h" #include "conf.h" #include "connection.h" #include "doi.h" #include "exchange.h" #include "init.h" #include "isakmp.h" #include "log.h" #include "monitor.h" #include "sa.h" #include "timer.h" #include "transport.h" #include "ui.h" #include "util.h" #define BUF_SZ 256 /* from isakmpd.c */ void daemon_shutdown_now(int); /* Report all SA configuration information. */ void ui_report_sa(char *); static FILE *ui_open_result(void); char *ui_fifo = FIFO; int ui_socket; struct event *ui_cr_event = NULL; /* Create and open the FIFO used for user control. */ void ui_init(void) { struct stat st; /* -f- means control messages comes in via stdin. */ if (strcmp(ui_fifo, "-") == 0) { ui_socket = 0; return; } /* Don't overwrite a file, i.e '-f /etc/isakmpd/isakmpd.conf'. */ if (lstat(ui_fifo, &st) == 0) { if ((st.st_mode & S_IFMT) == S_IFREG) { errno = EEXIST; log_fatal("ui_init: could not create FIFO \"%s\"", ui_fifo); } } /* No need to know about errors. */ unlink(ui_fifo); if (mkfifo(ui_fifo, 0600) == -1) log_fatal("ui_init: mkfifo (\"%s\", 0600) failed", ui_fifo); ui_socket = open(ui_fifo, O_RDWR | O_NONBLOCK, 0); if (ui_socket == -1) log_fatal("ui_init: open (\"%s\", O_RDWR | O_NONBLOCK, 0) " "failed", ui_fifo); } /* * Setup a phase 2 connection. * XXX Maybe phase 1 works too, but teardown won't work then, fix? */ static void ui_connect(char *cmd) { char name[81]; if (sscanf(cmd, "c %80s", name) != 1) { log_print("ui_connect: command \"%s\" malformed", cmd); return; } LOG_DBG((LOG_UI, 10, "ui_connect: setup connection \"%s\"", name)); connection_setup(name); } /* Tear down a phase 2 connection. */ static void ui_teardown(char *cmd) { char name[81]; struct sa *sa; if (sscanf(cmd, "t %80s", name) != 1) { log_print("ui_teardown: command \"%s\" malformed", cmd); return; } LOG_DBG((LOG_UI, 10, "ui_teardown: teardown connection \"%s\"", name)); connection_teardown(name); while ((sa = sa_lookup_by_name(name, 2)) != 0) sa_delete(sa, 1); } /* Tear down all phase 2 connections. */ static void ui_teardown_all(char *cmd) { /* Skip 'cmd' as arg. */ sa_teardown_all(); } static void ui_conn_reinit_event(void *v) { /* * This event is required for isakmpd to reinitialize the connection * and passive-connection lists. Otherwise a change to the * "[Phase 2]:Connections" tag will not have any effect. */ connection_reinit(); ui_cr_event = NULL; } static void ui_conn_reinit(void) { struct timeval tv; if (ui_cr_event) timer_remove_event(ui_cr_event); gettimeofday(&tv, 0); tv.tv_sec += 5; ui_cr_event = timer_add_event("ui_conn_reinit", ui_conn_reinit_event, 0, &tv); if (!ui_cr_event) log_print("ui_conn_reinit: timer_add_event() failed. " "Connections will not be updated."); } /* * Call the configuration API. * XXX Error handling! How to do multi-line transactions? Too short arbitrary * limit on the parameters? */ static void ui_config(char *cmd) { char subcmd[81], section[81], tag[81], value[81], tmp[81]; char *v, *nv; int trans = 0, items, nvlen; FILE *fd; if (sscanf(cmd, "C %80s", subcmd) != 1) goto fail; if (strcasecmp(subcmd, "get") == 0) { if (sscanf(cmd, "C %*s [%80[^]]]:%80s", section, tag) != 2) goto fail; v = conf_get_str(section, tag); fd = ui_open_result(); if (fd) { if (v) fprintf(fd, "%s\n", v); fclose(fd); } LOG_DBG((LOG_UI, 30, "ui_config: \"%s\"", cmd)); return; } trans = conf_begin(); if (strcasecmp(subcmd, "set") == 0) { items = sscanf(cmd, "C %*s [%80[^]]]:%80[^=]=%80s %80s", section, tag, value, tmp); if (!(items == 3 || items == 4)) goto fail; conf_set(trans, section, tag, value, items == 4 ? 1 : 0, 0); if (strcasecmp(section, "Phase 2") == 0 && (strcasecmp(tag, "Connections") == 0 || strcasecmp(tag, "Passive-connections") == 0)) ui_conn_reinit(); } else if (strcasecmp(subcmd, "add") == 0) { items = sscanf(cmd, "C %*s [%80[^]]]:%80[^=]=%80s %80s", section, tag, value, tmp); if (!(items == 3 || items == 4)) goto fail; v = conf_get_str(section, tag); if (!v) conf_set(trans, section, tag, value, 1, 0); else { /* Add the new value to the end of the 'v' list. */ nvlen = strlen(v) + strlen(value) + 2; nv = (char *)malloc(nvlen); if (!nv) { log_error("ui_config: malloc(%d) failed", nvlen); if (trans) conf_end(trans, 0); return; } snprintf(nv, nvlen, v[strlen(v) - 1] == ',' ? "%s%s" : "%s,%s", v, value); conf_set(trans, section, tag, nv, 1, 0); free(nv); } if (strcasecmp(section, "Phase 2") == 0 && (strcasecmp(tag, "Connections") == 0 || strcasecmp(tag, "Passive-connections") == 0)) ui_conn_reinit(); } else if (strcasecmp(subcmd, "rm") == 0) { if (sscanf(cmd, "C %*s [%80[^]]]:%80s", section, tag) != 2) goto fail; conf_remove(trans, section, tag); } else if (strcasecmp(subcmd, "rms") == 0) { if (sscanf(cmd, "C %*s [%80[^]]]", section) != 1) goto fail; conf_remove_section(trans, section); } else goto fail; LOG_DBG((LOG_UI, 30, "ui_config: \"%s\"", cmd)); conf_end(trans, 1); return; fail: if (trans) conf_end(trans, 0); log_print("ui_config: command \"%s\" malformed", cmd); } static void ui_delete(char *cmd) { char cookies_str[ISAKMP_HDR_COOKIES_LEN * 2 + 1]; char message_id_str[ISAKMP_HDR_MESSAGE_ID_LEN * 2 + 1]; u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN]; u_int8_t message_id_buf[ISAKMP_HDR_MESSAGE_ID_LEN]; u_int8_t *message_id = message_id_buf; struct sa *sa; if (sscanf(cmd, "d %32s %8s", cookies_str, message_id_str) != 2) { log_print("ui_delete: command \"%s\" malformed", cmd); return; } if (strcmp(message_id_str, "-") == 0) message_id = 0; if (hex2raw(cookies_str, cookies, ISAKMP_HDR_COOKIES_LEN) == -1 || (message_id && hex2raw(message_id_str, message_id_buf, ISAKMP_HDR_MESSAGE_ID_LEN) == -1)) { log_print("ui_delete: command \"%s\" has bad arguments", cmd); return; } sa = sa_lookup(cookies, message_id); if (!sa) { log_print("ui_delete: command \"%s\" found no SA", cmd); return; } LOG_DBG((LOG_UI, 20, "ui_delete: deleting SA for cookie \"%s\" msgid \"%s\"", cookies_str, message_id_str)); sa_delete(sa, 1); } #ifdef USE_DEBUG /* Parse the debug command found in CMD. */ static void ui_debug(char *cmd) { int cls, level; char subcmd[3]; if (sscanf(cmd, "D %d %d", &cls, &level) == 2) { log_debug_cmd(cls, level); return; } else if (sscanf(cmd, "D %2s %d", subcmd, &level) == 2) { switch (subcmd[0]) { case 'A': for (cls = 0; cls < LOG_ENDCLASS; cls++) log_debug_cmd(cls, level); return; } } else if (sscanf(cmd, "D %2s", subcmd) == 1) { switch (subcmd[0]) { case 'T': log_debug_toggle(); return; } } log_print("ui_debug: command \"%s\" malformed", cmd); return; } static void ui_packetlog(char *cmd) { char subcmd[81]; if (sscanf(cmd, "p %80s", subcmd) != 1) goto fail; if (strncasecmp(subcmd, "on=", 3) == 0) { /* Start capture to a new file. */ if (subcmd[strlen(subcmd) - 1] == '\n') subcmd[strlen(subcmd) - 1] = 0; log_packet_restart(subcmd + 3); } else if (strcasecmp(subcmd, "on") == 0) log_packet_restart(NULL); else if (strcasecmp(subcmd, "off") == 0) log_packet_stop(); return; fail: log_print("ui_packetlog: command \"%s\" malformed", cmd); } #endif /* USE_DEBUG */ static void ui_shutdown_daemon(char *cmd) { if (strlen(cmd) == 1) { log_print("ui_shutdown_daemon: received shutdown command"); daemon_shutdown_now(0); } else log_print("ui_shutdown_daemon: command \"%s\" malformed", cmd); } /* Report SAs and ongoing exchanges. */ void ui_report(char *cmd) { /* XXX Skip 'cmd' as arg? */ sa_report(); exchange_report(); transport_report(); connection_report(); timer_report(); conf_report(); } /* Report all SA configuration information. */ void ui_report_sa(char *cmd) { /* Skip 'cmd' as arg? */ FILE *fd = ui_open_result(); if (!fd) return; sa_report_all(fd); fclose(fd); } /* * Call the relevant command handler based on the first character of the * line (the command). */ static void ui_handle_command(char *line) { /* Find out what one-letter command was sent. */ switch (line[0]) { case 'c': ui_connect(line); break; case 'C': ui_config(line); break; case 'd': ui_delete(line); break; #ifdef USE_DEBUG case 'D': ui_debug(line); break; case 'p': ui_packetlog(line); break; #endif case 'Q': ui_shutdown_daemon(line); break; case 'R': reinit(); break; case 'S': ui_report_sa(line); break; case 'r': ui_report(line); break; case 't': ui_teardown(line); break; case 'T': ui_teardown_all(line); break; default: log_print("ui_handle_messages: unrecognized command: '%c'", line[0]); } } /* * A half-complex implementation of reading from a file descriptor * line by line without resorting to stdio which apparently have * troubles with non-blocking fifos. */ void ui_handler(void) { static char *buf = 0; static char *p; static size_t sz; static size_t resid; ssize_t n; char *new_buf; /* If no buffer, set it up. */ if (!buf) { sz = BUF_SZ; buf = malloc(sz); if (!buf) { log_print("ui_handler: malloc (%lu) failed", (unsigned long)sz); return; } p = buf; resid = sz; } /* If no place left in the buffer reallocate twice as large. */ if (!resid) { new_buf = realloc(buf, sz * 2); if (!new_buf) { log_print("ui_handler: realloc (%p, %lu) failed", buf, (unsigned long)sz * 2); free(buf); buf = 0; return; } buf = new_buf; p = buf + sz; resid = sz; sz *= 2; } n = read(ui_socket, p, resid); if (n == -1) { log_error("ui_handler: read (%d, %p, %lu)", ui_socket, p, (unsigned long)resid); return; } if (!n) return; resid -= n; while (n--) { /* * When we find a newline, cut off the line and feed it to the * command processor. Then move the rest up-front. */ if (*p == '\n') { *p = '\0'; ui_handle_command(buf); memcpy(buf, p + 1, n); p = buf; resid = sz - n; continue; } p++; } } static FILE * ui_open_result(void) { FILE *fd = monitor_fopen(RESULT_FILE, "w"); if (!fd) log_error("ui_open_result: fopen() failed"); return fd; } isakmpd-20041012.orig/pf_key_v2.h0000644000175000017500000000470610133045740016621 0ustar jdivejdive00000000000000/* $OpenBSD: pf_key_v2.h,v 1.12 2004/08/10 15:59:10 ho Exp $ */ /* $EOM: pf_key_v2.h,v 1.4 2000/12/04 04:46:35 angelos Exp $ */ /* * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _PF_KEY_V2_H_ #define _PF_KEY_V2_H_ #include #include struct proto; struct sa; struct sockaddr; struct kernel_sa; extern int pf_key_v2_socket; extern void pf_key_v2_connection_check(char *); extern int pf_key_v2_delete_spi(struct sa *, struct proto *, int); extern int pf_key_v2_enable_sa(struct sa *, struct sa *); extern int pf_key_v2_enable_spi(in_addr_t, in_addr_t, in_addr_t, in_addr_t, u_int8_t *, u_int8_t, in_addr_t); extern struct sa_kinfo *pf_key_v2_get_kernel_sa(u_int8_t *, size_t, u_int8_t, struct sockaddr *); extern u_int8_t *pf_key_v2_get_spi(size_t *, u_int8_t, struct sockaddr *, struct sockaddr *, u_int32_t); extern int pf_key_v2_group_spis(struct sa *, struct proto *, struct proto *, int); extern void pf_key_v2_handler(int); extern int pf_key_v2_open(void); extern int pf_key_v2_set_spi(struct sa *, struct proto *, int, struct sa *); #endif /* _PF_KEY_V2_H_ */ isakmpd-20041012.orig/x509.h0000644000175000017500000000656310133045740015445 0ustar jdivejdive00000000000000/* $OpenBSD: x509.h,v 1.21 2004/05/23 18:17:56 hshoexer Exp $ */ /* $EOM: x509.h,v 1.11 2000/09/28 12:53:27 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2000, 2001 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _X509_H_ #define _X509_H_ #include "libcrypto.h" #define X509v3_RFC_NAME 1 #define X509v3_DNS_NAME 2 #define X509v3_IP_ADDR 7 struct x509_attribval { char *type; char *val; }; /* * The acceptable certification authority. * XXX We only support two names at the moment, as of ASN this can * be dynamic but we don't care for now. */ struct x509_aca { struct x509_attribval name1; struct x509_attribval name2; }; struct X509; struct X509_STORE; /* Functions provided by cert handler. */ int x509_certreq_validate(u_int8_t *, u_int32_t); void *x509_certreq_decode(u_int8_t *, u_int32_t); void x509_cert_free(void *); void *x509_cert_get(u_int8_t *, u_int32_t); int x509_cert_get_key(void *, void *); int x509_cert_get_subjects(void *, int *, u_int8_t ***, u_int32_t **); int x509_cert_init(void); int x509_crl_init(void); int x509_cert_obtain(u_int8_t *, size_t, void *, u_int8_t **, u_int32_t *); int x509_cert_validate(void *); void x509_free_aca(void *); void *x509_cert_dup(void *); void x509_serialize(void *, u_int8_t **, u_int32_t *); char *x509_printable(void *); void *x509_from_printable(char *); /* Misc. X509 certificate functions. */ char *x509_DN_string(u_int8_t *, size_t); int x509_cert_insert(int, void *); int x509_cert_subjectaltname(X509 * cert, u_char **, u_int *); X509 *x509_from_asn(u_char *, u_int); int x509_generate_kn(int, X509 *); int x509_read_from_dir(X509_STORE *, char *, int); int x509_read_crls_from_dir(X509_STORE *, char *); #endif /* _X509_H_ */ isakmpd-20041012.orig/field.h0000644000175000017500000000413610133045740016015 0ustar jdivejdive00000000000000/* $OpenBSD: field.h,v 1.6 2004/05/23 18:17:55 hshoexer Exp $ */ /* $EOM: field.h,v 1.3 1998/08/02 20:25:01 niklas Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _FIELD_H_ #define _FIELD_H_ #include struct field { char *name; int offset; size_t len; enum { raw, num, mask, ign, cst } type; struct constant_map **maps; }; extern void field_dump_field(struct field *, u_int8_t *); extern void field_dump_payload(struct field *, u_int8_t *); extern u_int32_t field_get_num(struct field *, u_int8_t *); extern void field_get_raw(struct field *, u_int8_t *, u_int8_t *); extern void field_set_num(struct field *, u_int8_t *, u_int32_t); extern void field_set_raw(struct field *, u_int8_t *, u_int8_t *); #endif /* _FIELD_H_ */ isakmpd-20041012.orig/virtual.c0000644000175000017500000004605310133045740016417 0ustar jdivejdive00000000000000/* $OpenBSD: virtual.c,v 1.9 2004/09/20 21:36:50 hshoexer Exp $ */ /* * Copyright (c) 2004 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. * * 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 #include #include #ifndef linux #include #endif #include #include #include #include #include #include #include #include #include #include #include "conf.h" #include "if.h" #include "exchange.h" #include "log.h" #include "transport.h" #include "virtual.h" #include "udp.h" #include "util.h" #if defined (USE_NAT_TRAVERSAL) #include "udp_encap.h" #endif static struct transport *virtual_bind(const struct sockaddr *); static struct transport *virtual_bind_ADDR_ANY(sa_family_t); static int virtual_bind_if(char *, struct sockaddr *, void *); static struct transport *virtual_clone(struct transport *, struct sockaddr *); static struct transport *virtual_create(char *); static char *virtual_decode_ids (struct transport *); static void virtual_get_dst(struct transport *, struct sockaddr **); static struct msg_head *virtual_get_queue(struct message *); static void virtual_get_src(struct transport *, struct sockaddr **); static void virtual_handle_message(struct transport *); static void virtual_reinit(void); static void virtual_remove(struct transport *); static void virtual_report(struct transport *); static int virtual_send_message(struct message *, struct transport *); static struct transport_vtbl virtual_transport_vtbl = { { 0 }, "udp", virtual_create, virtual_reinit, virtual_remove, virtual_report, 0, 0, virtual_handle_message, virtual_send_message, virtual_get_dst, virtual_get_src, virtual_decode_ids, virtual_clone, virtual_get_queue }; static LIST_HEAD (virtual_listen_list, virtual_transport) virtual_listen_list; static struct transport *default_transport, *default_transport6; void virtual_init(void) { struct conf_list *listen_on; LIST_INIT(&virtual_listen_list); transport_method_add(&virtual_transport_vtbl); /* Bind the ISAKMP port(s) on all network interfaces we have. */ if (if_map(virtual_bind_if, 0) == -1) log_fatal("virtual_init: " "could not bind the ISAKMP port(s) on all interfaces"); /* Only listen to the specified address if Listen-on is configured */ listen_on = conf_get_list("General", "Listen-on"); if (listen_on) { LOG_DBG((LOG_TRANSPORT, 50, "virtual_init: not binding ISAKMP port(s) to ADDR_ANY")); conf_free_list(listen_on); return; } /* * Bind to INADDR_ANY in case of new addresses popping up. * Packet reception on this transport is taken as a hint to reprobe the * interface list. */ if (!bind_family || (bind_family & BIND_FAMILY_INET4)) { default_transport = virtual_bind_ADDR_ANY(AF_INET); if (!default_transport) return; LIST_INSERT_HEAD(&virtual_listen_list, (struct virtual_transport *)default_transport, link); transport_reference(default_transport); } if (!bind_family || (bind_family & BIND_FAMILY_INET6)) { default_transport6 = virtual_bind_ADDR_ANY(AF_INET6); if (!default_transport6) return; LIST_INSERT_HEAD(&virtual_listen_list, (struct virtual_transport *)default_transport6, link); transport_reference(default_transport6); } return; } struct virtual_transport * virtual_get_default(sa_family_t af) { switch (af) { case AF_INET: return (struct virtual_transport *)default_transport; case AF_INET6: return (struct virtual_transport *)default_transport6; default: return 0; } } /* * Probe the interface list and determine what new interfaces have * appeared. * * At the same time, we try to determine whether existing interfaces have * been rendered invalid; we do this by marking all virtual transports before * we call virtual_bind_if () through if_map (), and then releasing those * transports that have not been unmarked. */ void virtual_reinit(void) { struct virtual_transport *v, *v2; /* Mark all UDP transports, except the default ones. */ for (v = LIST_FIRST(&virtual_listen_list); v; v = LIST_NEXT(v, link)) if (&v->transport != default_transport && &v->transport != default_transport6) v->transport.flags |= TRANSPORT_MARK; /* Re-probe interface list. */ if (if_map(virtual_bind_if, 0) == -1) log_print("virtual_init: " "could not bind the ISAKMP port(s) on all interfaces"); /* * Release listening transports for local addresses that no * longer exist. virtual_bind_if () will have left those still marked. */ v = LIST_FIRST(&virtual_listen_list); while (v) { v2 = LIST_NEXT(v, link); if (v->transport.flags & TRANSPORT_MARK) { LIST_REMOVE(v, link); transport_release(&v->transport); } v = v2; } } struct virtual_transport * virtual_listen_lookup(struct sockaddr *addr) { struct virtual_transport *v; struct udp_transport *u; for (v = LIST_FIRST(&virtual_listen_list); v; v = LIST_NEXT(v, link)) { if (!(u = (struct udp_transport *)v->main)) if (!(u = (struct udp_transport *)v->encap)) { log_print("virtual_listen_lookup: " "virtual %p has no low-level transports", v); continue; } if (u->src->sa_family == addr->sa_family && sockaddr_addrlen(u->src) == sockaddr_addrlen(addr) && memcmp(sockaddr_addrdata (u->src), sockaddr_addrdata(addr), sockaddr_addrlen(addr)) == 0) return v; } LOG_DBG((LOG_TRANSPORT, 40, "virtual_listen_lookup: no match")); return 0; } /* * Initialize an object of the VIRTUAL transport class. */ static struct transport * virtual_bind(const struct sockaddr *addr) { struct virtual_transport *v; struct sockaddr_storage tmp_sa; char *port; char *ep; long lport; v = (struct virtual_transport *)calloc(1, sizeof *v); if (!v) { log_error("virtual_bind: calloc(1, %lu) failed", (unsigned long)sizeof *v); return 0; } v->transport.vtbl = &virtual_transport_vtbl; memcpy(&tmp_sa, addr, sysdep_sa_len((struct sockaddr *)addr)); /* * Get port. * XXX Use getservbyname too. */ port = udp_default_port ? udp_default_port : UDP_DEFAULT_PORT_STR; lport = strtol(port, &ep, 10); if (*ep != '\0' || lport < 0 || lport > (long)USHRT_MAX) { log_print("virtual_bind: " "port string \"%s\" not convertible to in_port_t", port); free(v); return 0; } sockaddr_set_port((struct sockaddr *)&tmp_sa, (in_port_t)lport); v->main = udp_bind((struct sockaddr *)&tmp_sa); if (!v->main) { free(v); return 0; } ((struct transport *)v->main)->virtual = (struct transport *)v; #if defined (USE_NAT_TRAVERSAL) memcpy(&tmp_sa, addr, sysdep_sa_len((struct sockaddr *)addr)); /* * Get port. * XXX Use getservbyname too. */ port = udp_encap_default_port ? udp_encap_default_port : UDP_ENCAP_DEFAULT_PORT_STR; lport = strtol(port, &ep, 10); if (*ep != '\0' || lport < 0 || lport > (long)USHRT_MAX) { log_print("virtual_bind: " "port string \"%s\" not convertible to in_port_t", port); v->main->vtbl->remove(v->main); free(v); return 0; } sockaddr_set_port((struct sockaddr *)&tmp_sa, (in_port_t)lport); v->encap = udp_encap_bind((struct sockaddr *)&tmp_sa); if (!v->encap) { v->main->vtbl->remove(v->main); free(v); return 0; } ((struct transport *)v->encap)->virtual = (struct transport *)v; #endif v->encap_is_active = 0; transport_setup(&v->transport, 1); v->transport.flags |= TRANSPORT_LISTEN; return (struct transport *)v; } static struct transport * virtual_bind_ADDR_ANY(sa_family_t af) { struct sockaddr_storage dflt_stor; struct sockaddr_in *d4 = (struct sockaddr_in *)&dflt_stor; struct sockaddr_in6 *d6 = (struct sockaddr_in6 *)&dflt_stor; struct transport *t; struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; memset(&dflt_stor, 0, sizeof dflt_stor); switch (af) { case AF_INET: d4->sin_family = af; #if !defined (LINUX_IPSEC) d4->sin_len = sizeof(struct sockaddr_in); #endif d4->sin_addr.s_addr = INADDR_ANY; break; case AF_INET6: d6->sin6_family = af; #if !defined (LINUX_IPSEC) d6->sin6_len = sizeof(struct sockaddr_in6); #endif memcpy(&d6->sin6_addr.s6_addr, &in6addr_any, sizeof in6addr_any); break; } t = virtual_bind((struct sockaddr *)&dflt_stor); if (!t) log_error("virtual_bind_ADDR_ANY: " "could not allocate default IPv%s ISAKMP port(s)", af == AF_INET ? "4" : "6"); return t; } static int virtual_bind_if(char *ifname, struct sockaddr *if_addr, void *arg) { struct conf_list *listen_on; struct virtual_transport *v; struct conf_list_node *address; struct sockaddr *addr; struct transport *t; struct ifreq flags_ifr; char *addr_str; int s, error; #if defined (USE_DEBUG) if (sockaddr2text(if_addr, &addr_str, 0)) addr_str = 0; LOG_DBG((LOG_TRANSPORT, 90, "virtual_bind_if: interface %s family %s address %s", ifname ? ifname : "", if_addr->sa_family == AF_INET ? "v4" : (if_addr->sa_family == AF_INET6 ? "v6" : ""), addr_str ? addr_str : "")); if (addr_str) free(addr_str); #endif /* * Drop non-Internet stuff. */ if ((if_addr->sa_family != AF_INET || sysdep_sa_len(if_addr) != sizeof (struct sockaddr_in)) && (if_addr->sa_family != AF_INET6 || sysdep_sa_len(if_addr) != sizeof (struct sockaddr_in6))) return 0; /* * Only create sockets for families we should listen to. */ if (bind_family) switch (if_addr->sa_family) { case AF_INET: if ((bind_family & BIND_FAMILY_INET4) == 0) return 0; break; case AF_INET6: if ((bind_family & BIND_FAMILY_INET6) == 0) return 0; break; default: return 0; } /* * These special addresses are not useable as they have special meaning * in the IP stack. */ if (if_addr->sa_family == AF_INET && (((struct sockaddr_in *)if_addr)->sin_addr.s_addr == INADDR_ANY || (((struct sockaddr_in *)if_addr)->sin_addr.s_addr == INADDR_NONE))) return 0; /* * Go through the list of transports and see if we already have this * address bound. If so, unmark the transport and skip it; this allows * us to call this function when we suspect a new address has appeared. */ if ((v = virtual_listen_lookup(if_addr)) != 0) { LOG_DBG ((LOG_TRANSPORT, 90, "virtual_bind_if: " "already bound")); v->transport.flags &= ~TRANSPORT_MARK; return 0; } /* * Don't bother with interfaces that are down. * Note: This socket is only used to collect the interface status. */ s = socket(if_addr->sa_family, SOCK_DGRAM, 0); if (s == -1) { log_error("virtual_bind_if: " "socket (%d, SOCK_DGRAM, 0) failed", if_addr->sa_family); return -1; } strlcpy(flags_ifr.ifr_name, ifname, sizeof flags_ifr.ifr_name); if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&flags_ifr) == -1) { log_error("virtual_bind_if: " "ioctl (%d, SIOCGIFFLAGS, ...) failed", s); close(s); return -1; } close(s); if (!(flags_ifr.ifr_flags & IFF_UP)) return 0; /* Set the port number to zero. */ switch (if_addr->sa_family) { case AF_INET: ((struct sockaddr_in *)if_addr)->sin_port = htons(0); break; case AF_INET6: ((struct sockaddr_in6 *)if_addr)->sin6_port = htons(0); break; default: log_print("virtual_bind_if: unsupported protocol family %d", if_addr->sa_family); break; } /* * If we are explicit about what addresses we can listen to, be sure * to respect that option. * This is quite wasteful redoing the list-run for every interface, * but who cares? This is not an operation that needs to be fast. */ listen_on = conf_get_list("General", "Listen-on"); if (listen_on) { for (address = TAILQ_FIRST(&listen_on->fields); address; address = TAILQ_NEXT(address, link)) { if (text2sockaddr(address->field, 0, &addr)) { log_print("virtual_bind_if: " "invalid address %s in \"Listen-on\"", address->field); continue; } /* If found, take the easy way out. */ if (memcmp(addr, if_addr, sysdep_sa_len(addr)) == 0) { free(addr); break; } free(addr); } conf_free_list(listen_on); /* * If address is zero then we did not find the address among * the ones we should listen to. * XXX We do not discover if we do not find our listen * addresses. Maybe this should be the other way round. */ if (!address) return 0; } t = virtual_bind(if_addr); if (!t) { error = sockaddr2text(if_addr, &addr_str, 0); log_print("virtual_bind_if: failed to create a socket on %s", error ? "unknown" : addr_str); if (!error) free(addr_str); return -1; } LIST_INSERT_HEAD(&virtual_listen_list, (struct virtual_transport *)t, link); transport_reference(t); return 0; } static struct transport * virtual_clone(struct transport *vt, struct sockaddr *raddr) { struct virtual_transport *v = (struct virtual_transport *)vt; struct virtual_transport *v2; struct transport *t; t = malloc(sizeof *v); if (!t) { log_error("virtual_clone: malloc(%lu) failed", (unsigned long)sizeof *v); return 0; } v2 = (struct virtual_transport *)t; memcpy(v2, v, sizeof *v); /* Remove the copy's links into virtual_listen_list. */ v2->link.le_next = 0; v2->link.le_prev = 0; if (v->encap_is_active) v2->main = 0; /* No need to clone this. */ else { v2->main = v->main->vtbl->clone(v->main, raddr); v2->main->virtual = (struct transport *)v2; } #if defined (USE_NAT_TRAVERSAL) /* XXX fix strtol() call */ sockaddr_set_port(raddr, udp_encap_default_port ? strtol(udp_encap_default_port, NULL, 10) : UDP_ENCAP_DEFAULT_PORT); v2->encap = v->encap->vtbl->clone(v->encap, raddr); v2->encap->virtual = (struct transport *)v2; #endif LOG_DBG((LOG_TRANSPORT, 50, "virtual_clone: old %p new %p (%s is %p)", v, t, v->encap_is_active ? "encap" : "main", v->encap_is_active ? v2->encap : v2->main)); t->flags &= ~TRANSPORT_LISTEN; transport_setup(t, 1); return t; } static struct transport * virtual_create(char *name) { struct virtual_transport *v; struct transport *t, *t2; t = transport_create("udp_physical", name); if (!t) return 0; #if defined (USE_NAT_TRAVERSAL) t2 = transport_create("udp_encap", name); if (!t2) { t->vtbl->remove(t); return 0; } #else t2 = 0; #endif v = (struct virtual_transport *)calloc(1, sizeof *v); if (!v) { log_error("virtual_create: calloc(1, %lu) failed", (unsigned long)sizeof *v); t->vtbl->remove(t); if (t2) t2->vtbl->remove(t2); return 0; } memcpy(v, t, sizeof *t); v->transport.virtual = 0; v->main = t; v->encap = t2; v->transport.vtbl = &virtual_transport_vtbl; t->virtual = (struct transport *)v; if (t2) t2->virtual = (struct transport *)v; transport_setup(&v->transport, 1); return (struct transport *)v; } static void virtual_remove(struct transport *t) { struct virtual_transport *v = (struct virtual_transport *)t; if (v->encap) v->encap->vtbl->remove(v->encap); if (v->main) v->main->vtbl->remove(v->main); if (v->link.le_prev) LIST_REMOVE(v, link); LOG_DBG((LOG_TRANSPORT, 90, "virtual_remove: removed %p", v)); free(t); } static void virtual_report(struct transport *t) { return; } static void virtual_handle_message(struct transport *t) { if (t->virtual == default_transport || t->virtual == default_transport6) { /* XXX drain pending message. See udp_handle_message(). */ virtual_reinit(); /* * As we don't know the actual destination address of the * packet, we can't really deal with it. So, just ignore it * and hope we catch the retransmission. */ return; } /* * As per the NAT-T draft, in case we have already switched ports, * any messages recieved on the old (500) port SHOULD be discarded. * (Actually, while phase 1 messages should be discarded, * informational exchanges MAY be processed normally. For now, we * discard them all.) */ if (((struct virtual_transport *)t->virtual)->encap_is_active && ((struct virtual_transport *)t->virtual)->main == t) { LOG_DBG((LOG_MESSAGE, 10, "virtual_handle_message: " "message on old port discarded")); return; } t->vtbl->handle_message(t); } static int virtual_send_message(struct message *msg, struct transport *t) { struct virtual_transport *v = (struct virtual_transport *)msg->transport; #if defined (USE_NAT_TRAVERSAL) struct sockaddr *dst; in_port_t port; /* * Activate NAT-T Encapsulation if * - the exchange says we can, and * - in ID_PROT, after step 4 (draft-ietf-ipsec-nat-t-ike-03), or * - in other exchange (Aggressive, ), asap * XXX ISAKMP_EXCH_BASE etc? */ if (v->encap_is_active == 0 && (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) && (msg->exchange->type != ISAKMP_EXCH_ID_PROT || msg->exchange->step > 4)) { LOG_DBG((LOG_MESSAGE, 10, "virtual_send_message: " "enabling NAT-T encapsulation for this exchange")); v->encap_is_active++; /* Copy destination port if it is translated (NAT). */ v->main->vtbl->get_dst(v->main, &dst); port = ntohs(sockaddr_port(dst)); if (port != UDP_DEFAULT_PORT) { v->main->vtbl->get_dst(v->encap, &dst); sockaddr_set_port(dst, port); } } #endif /* USE_NAT_TRAVERSAL */ if (v->encap_is_active) return v->encap->vtbl->send_message(msg, v->encap); else return v->main->vtbl->send_message(msg, v->main); } static void virtual_get_src(struct transport *t, struct sockaddr **s) { struct virtual_transport *v = (struct virtual_transport *)t; if (v->encap_is_active) v->encap->vtbl->get_src(v->encap, s); else v->main->vtbl->get_src(v->main, s); } static void virtual_get_dst(struct transport *t, struct sockaddr **s) { struct virtual_transport *v = (struct virtual_transport *)t; if (v->encap_is_active) v->encap->vtbl->get_dst(v->encap, s); else v->main->vtbl->get_dst(v->main, s); } static char * virtual_decode_ids(struct transport *t) { struct virtual_transport *v = (struct virtual_transport *)t; if (v->encap_is_active) return v->encap->vtbl->decode_ids(t); else return v->main->vtbl->decode_ids(t); } static struct msg_head * virtual_get_queue(struct message *msg) { if (msg->flags & MSG_PRIORITIZED) return &msg->transport->prio_sendq; else return &msg->transport->sendq; } isakmpd-20041012.orig/pf_key_v2.c0000644000175000017500000034662710133045740016627 0ustar jdivejdive00000000000000/* $OpenBSD: pf_key_v2.c,v 1.150 2004/09/17 13:53:08 ho Exp $ */ /* $EOM: pf_key_v2.c,v 1.79 2000/12/12 00:33:19 niklas Exp $ */ /* * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2001 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include "sysdep.h" #if !defined (LINUX_IPSEC) #include #endif #include #ifdef SADB_X_EXT_FLOW_TYPE #include #include #endif #include #include #include #include #include #include #include #include "cert.h" #include "conf.h" #include "exchange.h" #include "ipsec.h" #include "ipsec_num.h" #include "key.h" #include "log.h" #include "pf_key_v2.h" #include "sa.h" #include "timer.h" #include "transport.h" #include "util.h" #if defined (USE_KEYNOTE) #include "policy.h" #endif #if defined (USE_NAT_TRAVERSAL) #include "udp_encap.h" #endif #define IN6_IS_ADDR_FULL(a) \ ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffff) && \ (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffff) && \ (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffff) && \ (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffff)) #define ADDRESS_MAX sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255" /* * PF_KEY v2 always work with 64-bit entities and aligns on 64-bit boundaries. */ #define PF_KEY_V2_CHUNK 8 #define PF_KEY_V2_ROUND(x) \ (((x) + PF_KEY_V2_CHUNK - 1) & ~(PF_KEY_V2_CHUNK - 1)) /* How many microseconds we will wait for a reply from the PF_KEY socket. */ #define PF_KEY_REPLY_TIMEOUT 1000 struct pf_key_v2_node { TAILQ_ENTRY(pf_key_v2_node) link; void *seg; size_t sz; int cnt; u_int16_t type; u_int8_t flags; }; TAILQ_HEAD(pf_key_v2_msg, pf_key_v2_node); #define PF_KEY_V2_NODE_MALLOCED 1 #define PF_KEY_V2_NODE_MARK 2 /* Used to derive "unique" connection identifiers. */ int connection_seq = 0; #ifdef KAME /* * KAME requires the sadb_msg_seq of an UPDATE be the same of that of the * GETSPI creating the larval SA. */ struct pf_key_v2_sa_seq { TAILQ_ENTRY(pf_key_v2_sa_seq) link; u_int8_t *spi; size_t sz; u_int8_t proto; struct sockaddr *dst; int dstlen; u_int32_t seq; }; TAILQ_HEAD(, pf_key_v2_sa_seq) pf_key_v2_sa_seq_map; #endif #ifndef KAME static u_int8_t *pf_key_v2_convert_id(u_int8_t *, int, size_t *, int *); #endif static struct pf_key_v2_msg *pf_key_v2_call(struct pf_key_v2_msg *); static struct pf_key_v2_node *pf_key_v2_find_ext(struct pf_key_v2_msg *, u_int16_t); static void pf_key_v2_notify(struct pf_key_v2_msg *); static struct pf_key_v2_msg *pf_key_v2_read(u_int32_t); static u_int32_t pf_key_v2_seq(void); static u_int32_t pf_key_v2_write(struct pf_key_v2_msg *); static int pf_key_v2_remove_conf(char *); static int pf_key_v2_conf_refhandle(int, char *); #ifdef SADB_X_ASKPOLICY static int pf_key_v2_conf_refinc(int, char *); #endif /* The socket to use for PF_KEY interactions. */ int pf_key_v2_socket; #ifdef KAME static int pf_key_v2_register_sa_seq(u_int8_t *spi, size_t sz, u_int8_t proto, struct sockaddr *dst, int dstlen, u_int32_t seq) { struct pf_key_v2_sa_seq *node = 0; node = malloc(sizeof *node); if (!node) goto cleanup; memset(node, '0', sizeof *node); node->spi = malloc(sz); if (!node->spi) goto cleanup; node->dst = malloc(sysdep_sa_len(dst)); if (!node->dst) goto cleanup; memcpy(node->dst, dst, sysdep_sa_len(dst)); node->dstlen = sysdep_sa_len(dst); memcpy(node->spi, spi, sz); node->sz = sz; node->proto = proto; node->seq = seq; TAILQ_INSERT_TAIL(&pf_key_v2_sa_seq_map, node, link); return 1; cleanup: if (node->dst) free(node->dst); if (node) free(node); return 0; } static u_int32_t pf_key_v2_seq_by_sa(u_int8_t *spi, size_t sz, u_int8_t proto, struct sockaddr *dst, int dstlen) { struct pf_key_v2_sa_seq *node; for (node = TAILQ_FIRST(&pf_key_v2_sa_seq_map); node; node = TAILQ_NEXT(node, link)) if (node->proto == proto && node->sz == sz && memcmp(node->spi, spi, sz) == 0 && node->dstlen == sysdep_sa_len(dst) && memcmp(node->dst, dst, sysdep_sa_len(dst)) == 0) return node->seq; return 0; } #endif static struct pf_key_v2_msg * pf_key_v2_msg_new(struct sadb_msg *msg, int flags) { struct pf_key_v2_node *node = 0; struct pf_key_v2_msg *ret; node = malloc(sizeof *node); if (!node) goto cleanup; ret = malloc(sizeof *ret); if (!ret) goto cleanup; TAILQ_INIT(ret); node->seg = msg; node->sz = sizeof *msg; node->type = 0; node->cnt = 1; node->flags = flags; TAILQ_INSERT_HEAD(ret, node, link); return ret; cleanup: if (node) free(node); return 0; } /* Add a SZ sized segment SEG to the PF_KEY message MSG. */ static int pf_key_v2_msg_add(struct pf_key_v2_msg *msg, struct sadb_ext *ext, int flags) { struct pf_key_v2_node *node; node = malloc(sizeof *node); if (!node) return -1; node->seg = ext; node->sz = ext->sadb_ext_len * PF_KEY_V2_CHUNK; node->type = ext->sadb_ext_type; node->flags = flags; TAILQ_FIRST(msg)->cnt++; TAILQ_INSERT_TAIL(msg, node, link); return 0; } /* Deallocate the PF_KEY message MSG. */ static void pf_key_v2_msg_free(struct pf_key_v2_msg *msg) { struct pf_key_v2_node *np; np = TAILQ_FIRST(msg); while (np) { TAILQ_REMOVE(msg, np, link); if (np->flags & PF_KEY_V2_NODE_MALLOCED) free(np->seg); free(np); np = TAILQ_FIRST(msg); } free(msg); } /* Just return a new sequence number. */ static u_int32_t pf_key_v2_seq(void) { static u_int32_t seq = 0; return ++seq; } /* * Read a PF_KEY packet with SEQ as the sequence number, looping if necessary. * If SEQ is zero just read the first message we see, otherwise we queue * messages up until both the PID and the sequence number match. */ static struct pf_key_v2_msg * pf_key_v2_read(u_int32_t seq) { ssize_t n; u_int8_t *buf = 0; struct pf_key_v2_msg *ret = 0; struct sadb_msg *msg; struct sadb_msg hdr; struct sadb_ext *ext; struct timeval tv; fd_set *fds; while (1) { /* * If this is a read of a reply we should actually expect the * reply to get lost as PF_KEY is an unreliable service per * the specs. Currently we do this by setting a short timeout, * and if it is not readable in that time, we fail the read. */ if (seq) { fds = calloc(howmany(pf_key_v2_socket + 1, NFDBITS), sizeof(fd_mask)); if (!fds) { log_error("pf_key_v2_read: " "calloc (%lu, %lu) failed", (unsigned long) howmany(pf_key_v2_socket + 1, NFDBITS), (unsigned long) sizeof(fd_mask)); goto cleanup; } FD_SET(pf_key_v2_socket, fds); tv.tv_sec = 0; tv.tv_usec = PF_KEY_REPLY_TIMEOUT; n = select(pf_key_v2_socket + 1, fds, 0, 0, &tv); free(fds); if (n == -1) { log_error("pf_key_v2_read: " "select (%d, fds, 0, 0, &tv) failed", pf_key_v2_socket + 1); goto cleanup; } if (!n) { log_print("pf_key_v2_read: " "no reply from PF_KEY"); goto cleanup; } } n = recv(pf_key_v2_socket, &hdr, sizeof hdr, MSG_PEEK); if (n == -1) { log_error("pf_key_v2_read: recv (%d, ...) failed", pf_key_v2_socket); goto cleanup; } if (n != sizeof hdr) { log_error("pf_key_v2_read: recv (%d, ...) " "returned short packet (%lu bytes)", pf_key_v2_socket, (unsigned long) n); goto cleanup; } n = hdr.sadb_msg_len * PF_KEY_V2_CHUNK; buf = malloc(n); if (!buf) { log_error("pf_key_v2_read: malloc (%lu) failed", (unsigned long) n); goto cleanup; } n = read(pf_key_v2_socket, buf, n); if (n == -1) { log_error("pf_key_v2_read: read (%d, ...) failed", pf_key_v2_socket); goto cleanup; } if (n != hdr.sadb_msg_len * PF_KEY_V2_CHUNK) { log_print("pf_key_v2_read: read (%d, ...) " "returned short packet (%lu bytes)", pf_key_v2_socket, (unsigned long) n); goto cleanup; } LOG_DBG_BUF((LOG_SYSDEP, 80, "pf_key_v2_read: msg", buf, n)); /* We drop all messages that is not what we expect. */ msg = (struct sadb_msg *) buf; if (msg->sadb_msg_version != PF_KEY_V2 || (msg->sadb_msg_pid != 0 && msg->sadb_msg_pid != (u_int32_t) getpid())) { if (seq) { free(buf); buf = 0; continue; } else { LOG_DBG((LOG_SYSDEP, 90, "pf_key_v2_read:" "bad version (%d) or PID (%d, mine is " "%ld), ignored", msg->sadb_msg_version, msg->sadb_msg_pid, (long) getpid())); goto cleanup; } } /* Parse the message. */ ret = pf_key_v2_msg_new(msg, PF_KEY_V2_NODE_MALLOCED); if (!ret) goto cleanup; buf = 0; for (ext = (struct sadb_ext *) (msg + 1); (u_int8_t *) ext - (u_int8_t *) msg < msg->sadb_msg_len * PF_KEY_V2_CHUNK; ext = (struct sadb_ext *) ((u_int8_t *) ext + ext->sadb_ext_len * PF_KEY_V2_CHUNK)) pf_key_v2_msg_add(ret, ext, 0); /* * If the message is not the one we are waiting for, queue it * up. */ if (seq && (msg->sadb_msg_pid != (u_int32_t) getpid() || msg->sadb_msg_seq != seq)) { gettimeofday(&tv, 0); timer_add_event("pf_key_v2_notify", (void (*) (void *)) pf_key_v2_notify, ret, &tv); ret = 0; continue; } return ret; } cleanup: if (buf) free(buf); if (ret) pf_key_v2_msg_free(ret); return 0; } /* Write the message in PMSG to the PF_KEY socket. */ u_int32_t pf_key_v2_write(struct pf_key_v2_msg *pmsg) { struct iovec *iov = 0; ssize_t n; size_t len; int i, cnt = TAILQ_FIRST(pmsg)->cnt; char header[80]; struct sadb_msg *msg = TAILQ_FIRST(pmsg)->seg; struct pf_key_v2_node *np = TAILQ_FIRST(pmsg); iov = (struct iovec *) malloc(cnt * sizeof *iov); if (!iov) { log_error("pf_key_v2_write: malloc (%lu) failed", cnt * (unsigned long) sizeof *iov); return 0; } msg->sadb_msg_version = PF_KEY_V2; msg->sadb_msg_errno = 0; msg->sadb_msg_reserved = 0; msg->sadb_msg_pid = getpid(); if (!msg->sadb_msg_seq) msg->sadb_msg_seq = pf_key_v2_seq(); /* Compute the iovec segments as well as the message length. */ len = 0; for (i = 0; i < cnt; i++) { iov[i].iov_base = np->seg; len += iov[i].iov_len = np->sz; /* * XXX One can envision setting specific extension fields, like * *_reserved ones here. For now we require them to be set by the * caller. */ np = TAILQ_NEXT(np, link); } msg->sadb_msg_len = len / PF_KEY_V2_CHUNK; for (i = 0; i < cnt; i++) { snprintf(header, sizeof header, "pf_key_v2_write: iov[%d]", i); LOG_DBG_BUF((LOG_SYSDEP, 80, header, (u_int8_t *) iov[i].iov_base, iov[i].iov_len)); } n = writev(pf_key_v2_socket, iov, cnt); if (n == -1) { log_error("pf_key_v2_write: writev (%d, %p, %d) failed", pf_key_v2_socket, iov, cnt); goto cleanup; } if ((size_t) n != len) { log_error("pf_key_v2_write: " "writev (%d, ...) returned prematurely (%lu)", pf_key_v2_socket, (unsigned long) n); goto cleanup; } free(iov); return msg->sadb_msg_seq; cleanup: if (iov) free(iov); return 0; } /* * Do a PF_KEY "call", i.e. write a message MSG, read the reply and return * it to the caller. */ static struct pf_key_v2_msg * pf_key_v2_call(struct pf_key_v2_msg *msg) { u_int32_t seq; seq = pf_key_v2_write(msg); if (!seq) return 0; return pf_key_v2_read(seq); } /* Find the TYPE extension in MSG. Return zero if none found. */ static struct pf_key_v2_node * pf_key_v2_find_ext(struct pf_key_v2_msg *msg, u_int16_t type) { struct pf_key_v2_node *ext; for (ext = TAILQ_NEXT(TAILQ_FIRST(msg), link); ext; ext = TAILQ_NEXT(ext, link)) if (ext->type == type) return ext; return 0; } /* * Open the PF_KEYv2 sockets and return the descriptor used for notifies. * Return -1 for failure and -2 if no notifies will show up. */ int pf_key_v2_open(void) { int fd = -1, err; struct sadb_msg msg; struct pf_key_v2_msg *regmsg = 0, *ret = 0; /* Open the socket we use to speak to IPsec. */ pf_key_v2_socket = -1; fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); if (fd == -1) { log_error("pf_key_v2_open: " "socket (PF_KEY, SOCK_RAW, PF_KEY_V2) failed"); goto cleanup; } pf_key_v2_socket = fd; /* Register it to get ESP and AH acquires from the kernel. */ msg.sadb_msg_seq = 0; msg.sadb_msg_type = SADB_REGISTER; msg.sadb_msg_satype = SADB_SATYPE_ESP; regmsg = pf_key_v2_msg_new(&msg, 0); if (!regmsg) goto cleanup; ret = pf_key_v2_call(regmsg); pf_key_v2_msg_free(regmsg); if (!ret) goto cleanup; err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; if (err) { log_print("pf_key_v2_open: REGISTER: %s", strerror(err)); goto cleanup; } /* XXX Register the accepted transforms. */ pf_key_v2_msg_free(ret); ret = 0; msg.sadb_msg_seq = 0; msg.sadb_msg_type = SADB_REGISTER; msg.sadb_msg_satype = SADB_SATYPE_AH; regmsg = pf_key_v2_msg_new(&msg, 0); if (!regmsg) goto cleanup; ret = pf_key_v2_call(regmsg); pf_key_v2_msg_free(regmsg); if (!ret) goto cleanup; err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; if (err) { log_print("pf_key_v2_open: REGISTER: %s", strerror(err)); goto cleanup; } /* XXX Register the accepted transforms. */ pf_key_v2_msg_free(ret); ret = 0; #ifdef SADB_X_SATYPE_IPCOMP msg.sadb_msg_seq = 0; msg.sadb_msg_type = SADB_REGISTER; msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; regmsg = pf_key_v2_msg_new(&msg, 0); if (!regmsg) goto cleanup; ret = pf_key_v2_call(regmsg); pf_key_v2_msg_free(regmsg); if (!ret) goto cleanup; err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; if (err) { log_print("pf_key_v2_open: REGISTER: %s", strerror(err)); goto cleanup; } /* XXX Register the accepted transforms. */ pf_key_v2_msg_free(ret); #endif /* SADB_X_SATYPE_IPCOMP */ #ifdef KAME TAILQ_INIT(&pf_key_v2_sa_seq_map); #endif return fd; cleanup: if (pf_key_v2_socket != -1) { close(pf_key_v2_socket); pf_key_v2_socket = -1; } if (ret) pf_key_v2_msg_free(ret); return -1; } /* * Generate a SPI for protocol PROTO and the source/destination pair given by * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. */ u_int8_t * pf_key_v2_get_spi(size_t *sz, u_int8_t proto, struct sockaddr *src, struct sockaddr *dst, u_int32_t seq) { struct sadb_msg msg; struct sadb_sa *sa; struct sadb_address *addr = 0; struct sadb_spirange spirange; struct pf_key_v2_msg *getspi = 0, *ret = 0; struct pf_key_v2_node *ext; u_int8_t *spi = 0; int len, err; #ifdef KAME struct sadb_x_sa2 ssa2; #endif msg.sadb_msg_type = SADB_GETSPI; switch (proto) { case IPSEC_PROTO_IPSEC_ESP: msg.sadb_msg_satype = SADB_SATYPE_ESP; break; case IPSEC_PROTO_IPSEC_AH: msg.sadb_msg_satype = SADB_SATYPE_AH; break; #ifdef SADB_X_SATYPE_IPCOMP case IPSEC_PROTO_IPCOMP: msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; break; #endif default: log_print("pf_key_v2_get_spi: invalid proto %d", proto); goto cleanup; } /* Set the sequence number from the ACQUIRE message. */ msg.sadb_msg_seq = seq; getspi = pf_key_v2_msg_new(&msg, 0); if (!getspi) goto cleanup; #ifdef KAME memset(&ssa2, 0, sizeof ssa2); ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; ssa2.sadb_x_sa2_mode = 0; if (pf_key_v2_msg_add(getspi, (struct sadb_ext *)&ssa2, 0) == -1) goto cleanup; #endif /* Setup the ADDRESS extensions. */ len = sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(src)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifndef __OpenBSD__ addr->sadb_address_proto = 0; addr->sadb_address_prefixlen = 0; #endif addr->sadb_address_reserved = 0; memcpy(addr + 1, src, sysdep_sa_len(src)); switch (((struct sockaddr *) (addr + 1))->sa_family) { case AF_INET: ((struct sockaddr_in *) (addr + 1))->sin_port = 0; break; case AF_INET6: ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; break; } if (pf_key_v2_msg_add(getspi, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; len = sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifndef __OpenBSD__ addr->sadb_address_proto = 0; addr->sadb_address_prefixlen = 0; #endif addr->sadb_address_reserved = 0; memcpy(addr + 1, dst, sysdep_sa_len(dst)); switch (((struct sockaddr *) (addr + 1))->sa_family) { case AF_INET: ((struct sockaddr_in *) (addr + 1))->sin_port = 0; break; case AF_INET6: ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; break; } if (pf_key_v2_msg_add(getspi, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; /* Setup the SPIRANGE extension. */ spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; spirange.sadb_spirange_len = sizeof spirange / PF_KEY_V2_CHUNK; if (proto == IPSEC_PROTO_IPCOMP) { spirange.sadb_spirange_min = CPI_RESERVED_MAX + 1; spirange.sadb_spirange_max = CPI_PRIVATE_MIN - 1; } else { spirange.sadb_spirange_min = IPSEC_SPI_LOW; spirange.sadb_spirange_max = 0xffffffff; } spirange.sadb_spirange_reserved = 0; if (pf_key_v2_msg_add(getspi, (struct sadb_ext *)&spirange, 0) == -1) goto cleanup; ret = pf_key_v2_call(getspi); pf_key_v2_msg_free(getspi); getspi = 0; if (!ret) goto cleanup; err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; if (err) { log_print("pf_key_v2_get_spi: GETSPI: %s", strerror(err)); goto cleanup; } ext = pf_key_v2_find_ext(ret, SADB_EXT_SA); if (!ext) { log_print("pf_key_v2_get_spi: no SA extension found"); goto cleanup; } sa = ext->seg; /* IPCOMP CPIs are only 16 bits long. */ *sz = (proto == IPSEC_PROTO_IPCOMP) ? sizeof(u_int16_t) : sizeof sa->sadb_sa_spi; spi = malloc(*sz); if (!spi) goto cleanup; /* XXX This is ugly. */ if (proto == IPSEC_PROTO_IPCOMP) { u_int32_t tspi = ntohl(sa->sadb_sa_spi); *(u_int16_t *) spi = htons((u_int16_t) tspi); } else memcpy(spi, &sa->sadb_sa_spi, *sz); #ifdef KAME if (!pf_key_v2_register_sa_seq(spi, *sz, proto, dst, sysdep_sa_len(dst), ((struct sadb_msg *) (TAILQ_FIRST(ret)->seg))->sadb_msg_seq)) goto cleanup; #endif pf_key_v2_msg_free(ret); LOG_DBG_BUF((LOG_SYSDEP, 50, "pf_key_v2_get_spi: spi", spi, *sz)); return spi; cleanup: if (spi) free(spi); if (addr) free(addr); if (getspi) pf_key_v2_msg_free(getspi); if (ret) pf_key_v2_msg_free(ret); return 0; } /* Fetch SA information from the kernel. XXX OpenBSD only? */ struct sa_kinfo * pf_key_v2_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, struct sockaddr *dst) { struct sadb_msg msg; struct sadb_sa *ssa; struct sadb_address *addr = 0; struct sockaddr *sa; struct sadb_lifetime *life; struct pf_key_v2_msg *gettdb = 0, *ret = 0; struct pf_key_v2_node *ext; static struct sa_kinfo ksa; #if defined (SADB_X_EXT_UDPENCAP) struct sadb_x_udpencap *udpencap; #endif int len, err; if (spi_sz != sizeof (ssa->sadb_sa_spi)) return 0; msg.sadb_msg_type = SADB_GET; switch (proto) { case IPSEC_PROTO_IPSEC_ESP: msg.sadb_msg_satype = SADB_SATYPE_ESP; break; case IPSEC_PROTO_IPSEC_AH: msg.sadb_msg_satype = SADB_SATYPE_AH; break; #ifdef SADB_X_SATYPE_IPCOMP case IPSEC_PROTO_IPCOMP: msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; break; #endif default: log_print("pf_key_v2_get_kernel_sa: invalid proto %d", proto); goto cleanup; } gettdb = pf_key_v2_msg_new(&msg, 0); if (!gettdb) goto cleanup; /* SPI */ ssa = (struct sadb_sa *)calloc(1, sizeof *ssa); if (!ssa) { log_print("pf_key_v2_get_kernel_sa: calloc(1, %lu) failed", (unsigned long)sizeof *ssa); goto cleanup; } ssa->sadb_sa_exttype = SADB_EXT_SA; ssa->sadb_sa_len = sizeof *ssa / PF_KEY_V2_CHUNK; memcpy(&ssa->sadb_sa_spi, spi, sizeof ssa->sadb_sa_spi); ssa->sadb_sa_state = SADB_SASTATE_MATURE; if (pf_key_v2_msg_add(gettdb, (struct sadb_ext *)ssa, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; ssa = 0; /* XXX KAME SADB_X_EXT_xyz here? */ /* Address */ len = sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifndef __OpenBSD__ addr->sadb_address_proto = 0; addr->sadb_address_prefixlen = 0; #endif addr->sadb_address_reserved = 0; memcpy(addr + 1, dst, sysdep_sa_len(dst)); switch (((struct sockaddr *) (addr + 1))->sa_family) { case AF_INET: ((struct sockaddr_in *) (addr + 1))->sin_port = 0; break; case AF_INET6: ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; break; } if (pf_key_v2_msg_add(gettdb, (struct sadb_ext *)addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; ret = pf_key_v2_call(gettdb); pf_key_v2_msg_free(gettdb); gettdb = 0; if (!ret) goto cleanup; err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; if (err) { log_print("pf_key_v2_get_kernel_sa: SADB_GET: %s", strerror(err)); goto cleanup; } /* Extract the data. */ memset(&ksa, 0, sizeof ksa); ext = pf_key_v2_find_ext(ret, SADB_EXT_SA); if (!ext) goto cleanup; ssa = (struct sadb_sa *)ext; ksa.spi = ssa->sadb_sa_spi; ksa.wnd = ssa->sadb_sa_replay; ksa.flags = ssa->sadb_sa_flags; ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_CURRENT); if (ext) { life = (struct sadb_lifetime *)ext->seg; ksa.cur_allocations = life->sadb_lifetime_allocations; ksa.cur_bytes = life->sadb_lifetime_bytes; ksa.first_use = life->sadb_lifetime_usetime; ksa.established = life->sadb_lifetime_addtime; } ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_SOFT); if (ext) { life = (struct sadb_lifetime *)ext->seg; ksa.soft_allocations = life->sadb_lifetime_allocations; ksa.soft_bytes = life->sadb_lifetime_bytes; ksa.soft_timeout = life->sadb_lifetime_addtime; ksa.soft_first_use = life->sadb_lifetime_usetime; } ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_HARD); if (ext) { life = (struct sadb_lifetime *)ext->seg; ksa.exp_allocations = life->sadb_lifetime_allocations; ksa.exp_bytes = life->sadb_lifetime_bytes; ksa.exp_timeout = life->sadb_lifetime_addtime; ksa.exp_first_use = life->sadb_lifetime_usetime; } #if defined (SADB_X_EXT_LIFETIME_LASTUSE) ext = pf_key_v2_find_ext(ret, SADB_X_EXT_LIFETIME_LASTUSE); if (ext) { life = (struct sadb_lifetime *)ext->seg; ksa.last_used = life->sadb_lifetime_usetime; } #endif ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_SRC); if (ext) { sa = (struct sockaddr *)ext->seg; memcpy(&ksa.src, sa, sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); } ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_DST); if (ext) { sa = (struct sockaddr *)ext->seg; memcpy(&ksa.dst, sa, sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); } ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_PROXY); if (ext) { sa = (struct sockaddr *)ext->seg; memcpy(sa, &ksa.proxy, sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); } #if defined (SADB_X_EXT_UDPENCAP) ext = pf_key_v2_find_ext(ret, SADB_X_EXT_UDPENCAP); if (ext) { udpencap = (struct sadb_x_udpencap *)ext->seg; ksa.udpencap_port = udpencap->sadb_x_udpencap_port; } #endif pf_key_v2_msg_free(ret); LOG_DBG_BUF((LOG_SYSDEP, 50, "pf_key_v2_get_kernel_sa: spi", spi, spi_sz)); return &ksa; cleanup: if (addr) free (addr); if (gettdb) pf_key_v2_msg_free(gettdb); if (ret) pf_key_v2_msg_free(ret); return 0; } static void pf_key_v2_setup_sockaddr(void *res, struct sockaddr *src, struct sockaddr *dst, in_port_t port, int ingress) { struct sockaddr_in *ip4_sa; struct sockaddr_in6 *ip6_sa; u_int8_t *p; switch (src->sa_family) { case AF_INET: ip4_sa = (struct sockaddr_in *) res; ip4_sa->sin_family = AF_INET; #ifndef USE_OLD_SOCKADDR ip4_sa->sin_len = sizeof *ip4_sa; #endif ip4_sa->sin_port = port; if (dst) p = (u_int8_t *) (ingress ? &((struct sockaddr_in *)src)->sin_addr.s_addr : &((struct sockaddr_in *)dst)->sin_addr.s_addr); else p = (u_int8_t *)&((struct sockaddr_in *)src)->sin_addr.s_addr; ip4_sa->sin_addr.s_addr = *((in_addr_t *) p); break; case AF_INET6: ip6_sa = (struct sockaddr_in6 *) res; ip6_sa->sin6_family = AF_INET6; #ifndef USE_OLD_SOCKADDR ip6_sa->sin6_len = sizeof *ip6_sa; #endif ip6_sa->sin6_port = port; if (dst) p = (u_int8_t *) (ingress ? &((struct sockaddr_in6 *)src)->sin6_addr.s6_addr : &((struct sockaddr_in6 *)dst)->sin6_addr.s6_addr); else p = (u_int8_t *)&((struct sockaddr_in6 *)src)->sin6_addr.s6_addr; memcpy(ip6_sa->sin6_addr.s6_addr, p, sizeof(struct in6_addr)); break; default: log_print("pf_key_v2_setup_sockaddr: unknown family %d\n", src->sa_family); break; } } /* * Store/update a PF_KEY_V2 security association with full information from the * IKE SA and PROTO into the kernel. INCOMING is set if we are setting the * parameters for the incoming SA, and cleared otherwise. */ int pf_key_v2_set_spi(struct sa *sa, struct proto *proto, int incoming, struct sa *isakmp_sa) { struct sadb_msg msg; struct sadb_sa ssa; struct sadb_lifetime *life = 0; struct sadb_address *addr = 0; struct sadb_key *key = 0; struct sadb_ident *sid = 0; struct sockaddr *src, *dst; struct pf_key_v2_msg *update = 0, *ret = 0; struct ipsec_proto *iproto = proto->data; size_t len; int keylen, hashlen, err; #ifndef KAME u_int8_t *pp; int idtype; #else /* KAME */ struct sadb_x_sa2 ssa2; #endif #if defined (SADB_X_CREDTYPE_NONE) || defined (SADB_X_AUTHTYPE_NONE) struct ipsec_sa *isa = sa->data; struct sadb_x_cred *cred; struct sadb_protocol flowtype, tprotocol; #endif #if defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_UDPENCAP) struct sadb_x_udpencap udpencap; #endif #ifdef USE_DEBUG char *addr_str; #endif msg.sadb_msg_type = incoming ? SADB_UPDATE : SADB_ADD; switch (proto->proto) { case IPSEC_PROTO_IPSEC_ESP: msg.sadb_msg_satype = SADB_SATYPE_ESP; keylen = ipsec_esp_enckeylength(proto); hashlen = ipsec_esp_authkeylength(proto); switch (proto->id) { case IPSEC_ESP_DES: case IPSEC_ESP_DES_IV32: case IPSEC_ESP_DES_IV64: ssa.sadb_sa_encrypt = SADB_EALG_DESCBC; break; case IPSEC_ESP_3DES: ssa.sadb_sa_encrypt = SADB_EALG_3DESCBC; break; #ifdef SADB_X_EALG_AES case IPSEC_ESP_AES: /* case IPSEC_ESP_AES_128_CTR: */ ssa.sadb_sa_encrypt = SADB_X_EALG_AES; break; #endif #ifdef SADB_X_EALG_CAST case IPSEC_ESP_CAST: ssa.sadb_sa_encrypt = SADB_X_EALG_CAST; break; #endif #ifdef SADB_X_EALG_BLF case IPSEC_ESP_BLOWFISH: ssa.sadb_sa_encrypt = SADB_X_EALG_BLF; break; #endif default: LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: " "unknown encryption algorithm %d", proto->id)); return -1; } switch (iproto->auth) { case IPSEC_AUTH_HMAC_MD5: #ifdef SADB_AALG_MD5HMAC96 ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96; #else ssa.sadb_sa_auth = SADB_AALG_MD5HMAC; #endif break; case IPSEC_AUTH_HMAC_SHA: #ifdef SADB_AALG_SHA1HMAC96 ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96; #else ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC; #endif break; #ifndef KAME case IPSEC_AUTH_HMAC_RIPEMD: #ifdef SADB_X_AALG_RIPEMD160HMAC96 ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96; #elif defined (SADB_X_AALG_RIPEMD160HMAC) ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC; #elif defined (SADB_X_AALG_RIPEMD160) ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160; #else ssa.sadb_sa_auth = SADB_AALG_RIPEMD160HMAC; #endif break; #endif #ifdef SADB_X_AALG_SHA2_256 case IPSEC_AUTH_HMAC_SHA2_256: ssa.sadb_sa_auth = SADB_X_AALG_SHA2_256; break; #endif #ifdef SADB_X_AALG_SHA2_384 case IPSEC_AUTH_HMAC_SHA2_384: ssa.sadb_sa_auth = SADB_X_AALG_SHA2_384; break; #endif #ifdef SADB_X_AALG_SHA2_512 case IPSEC_AUTH_HMAC_SHA2_512: ssa.sadb_sa_auth = SADB_X_AALG_SHA2_512; break; #endif case IPSEC_AUTH_DES_MAC: case IPSEC_AUTH_KPDK: /* XXX We should be supporting KPDK */ LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: " "unknown authentication algorithm %d", iproto->auth)); return -1; default: ssa.sadb_sa_auth = SADB_AALG_NONE; } break; case IPSEC_PROTO_IPSEC_AH: msg.sadb_msg_satype = SADB_SATYPE_AH; hashlen = ipsec_ah_keylength(proto); keylen = 0; ssa.sadb_sa_encrypt = SADB_EALG_NONE; switch (proto->id) { case IPSEC_AH_MD5: #ifdef SADB_AALG_MD5HMAC96 ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96; #else ssa.sadb_sa_auth = SADB_AALG_MD5HMAC; #endif break; case IPSEC_AH_SHA: #ifdef SADB_AALG_SHA1HMAC96 ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96; #else ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC; #endif break; #ifndef KAME case IPSEC_AH_RIPEMD: #ifdef SADB_X_AALG_RIPEMD160HMAC96 ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96; #elif defined (SADB_X_AALG_RIPEMD160HMAC) ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC; #elif defined (SADB_X_AALG_RIPEMD160) ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160; #else ssa.sadb_sa_auth = SADB_AALG_RIPEMD160HMAC; #endif break; #endif #ifdef SADB_X_AALG_SHA2_256 case IPSEC_AH_SHA2_256: ssa.sadb_sa_auth = SADB_X_AALG_SHA2_256; break; #endif #ifdef SADB_X_AALG_SHA2_384 case IPSEC_AH_SHA2_384: ssa.sadb_sa_auth = SADB_X_AALG_SHA2_384; break; #endif #ifdef SADB_X_AALG_SHA2_512 case IPSEC_AH_SHA2_512: ssa.sadb_sa_auth = SADB_X_AALG_SHA2_512; break; #endif default: LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: " "unknown authentication algorithm %d", proto->id)); goto cleanup; } break; #ifdef SADB_X_SATYPE_IPCOMP case IPSEC_PROTO_IPCOMP: msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; ssa.sadb_sa_auth = SADB_AALG_NONE; keylen = 0; hashlen = 0; /* * Put compression algorithm type in the sadb_sa_encrypt * field. */ switch (proto->id) { #ifdef SADB_X_CALG_OUI case IPSEC_IPCOMP_OUI: ssa.sadb_sa_encrypt = SADB_X_CALG_OUI; break; #endif #ifdef SADB_X_CALG_DEFLATE case IPSEC_IPCOMP_DEFLATE: ssa.sadb_sa_encrypt = SADB_X_CALG_DEFLATE; break; #endif #ifdef SADB_X_CALG_LZS case IPSEC_IPCOMP_LZS: ssa.sadb_sa_encrypt = SADB_X_CALG_LZS; break; #endif #ifdef SADB_X_CALG_V42BIS case IPSEC_IPCOMP_V42BIS: ssa.sadb_sa_encrypt = SADB_X_CALG_V42BIS; break; #endif default: break; } break; #endif /* SADB_X_SATYPE_IPCOMP */ default: log_print("pf_key_v2_set_spi: invalid proto %d", proto->proto); goto cleanup; } if (incoming) sa->transport->vtbl->get_src(sa->transport, &dst); else sa->transport->vtbl->get_dst(sa->transport, &dst); #ifdef KAME msg.sadb_msg_seq = (incoming ? pf_key_v2_seq_by_sa(proto->spi[incoming], sizeof ssa.sadb_sa_spi, proto->proto, dst, sysdep_sa_len(dst)) : 0); #else msg.sadb_msg_seq = sa->seq; #endif update = pf_key_v2_msg_new(&msg, 0); if (!update) goto cleanup; #ifdef KAME memset(&ssa2, 0, sizeof ssa2); ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; #if defined (LINUX_IPSEC) if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) ssa2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL; else ssa2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT; #else ssa2.sadb_x_sa2_mode = 0; #endif if (pf_key_v2_msg_add(update, (struct sadb_ext *)&ssa2, 0) == -1) goto cleanup; #endif /* Setup the rest of the SA extension. */ ssa.sadb_sa_exttype = SADB_EXT_SA; ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK; if (proto->spi_sz[incoming] == 2) /* IPCOMP uses 16bit CPIs. */ ssa.sadb_sa_spi = htonl(proto->spi[incoming][0] << 8 | proto->spi[incoming][1]); else memcpy(&ssa.sadb_sa_spi, proto->spi[incoming], sizeof ssa.sadb_sa_spi); ssa.sadb_sa_replay = conf_get_str("General", "Shared-SADB") ? 0 : iproto->replay_window; ssa.sadb_sa_state = SADB_SASTATE_MATURE; ssa.sadb_sa_flags = 0; #ifdef SADB_X_SAFLAGS_TUNNEL if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL || iproto->encap_mode == IPSEC_ENCAP_UDP_ENCAP_TUNNEL) ssa.sadb_sa_flags = SADB_X_SAFLAGS_TUNNEL; #endif #if defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_UDPENCAP) if (isakmp_sa->flags & SA_FLAG_NAT_T_ENABLE) { memset(&udpencap, 0, sizeof udpencap); ssa.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; udpencap.sadb_x_udpencap_len = sizeof udpencap / PF_KEY_V2_CHUNK; udpencap.sadb_x_udpencap_port = sockaddr_port(dst); if (pf_key_v2_msg_add(update, (struct sadb_ext *)&udpencap, 0) == -1) goto cleanup; } #endif if (pf_key_v2_msg_add(update, (struct sadb_ext *)&ssa, 0) == -1) goto cleanup; if (sa->seconds || sa->kilobytes) { /* Setup the hard limits. */ life = malloc(sizeof *life); if (!life) goto cleanup; life->sadb_lifetime_len = sizeof *life / PF_KEY_V2_CHUNK; life->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; life->sadb_lifetime_allocations = 0; life->sadb_lifetime_bytes = sa->kilobytes * 1024; /* * XXX I am not sure which one is best in security respect. * Maybe the RFCs actually mandate what a lifetime really is. */ #if 0 life->sadb_lifetime_addtime = 0; life->sadb_lifetime_usetime = sa->seconds; #else life->sadb_lifetime_addtime = sa->seconds; life->sadb_lifetime_usetime = 0; #endif if (pf_key_v2_msg_add(update, (struct sadb_ext *) life, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; life = 0; /* * Setup the soft limits, we use 90 % of the hard ones. * XXX A configurable ratio would be better. */ life = malloc(sizeof *life); if (!life) goto cleanup; life->sadb_lifetime_len = sizeof *life / PF_KEY_V2_CHUNK; life->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; life->sadb_lifetime_allocations = 0; life->sadb_lifetime_bytes = sa->kilobytes * 1024 * 9 / 10; /* * XXX I am not sure which one is best in security respect. * Maybe the RFCs actually mandate what a lifetime really is. */ #if 0 life->sadb_lifetime_addtime = 0; life->sadb_lifetime_usetime = sa->seconds * 9 / 10; #else life->sadb_lifetime_addtime = sa->seconds * 9 / 10; life->sadb_lifetime_usetime = 0; #endif if (pf_key_v2_msg_add(update, (struct sadb_ext *) life, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; life = 0; } /* * Setup the ADDRESS extensions. */ if (incoming) sa->transport->vtbl->get_dst(sa->transport, &src); else sa->transport->vtbl->get_src(sa->transport, &src); len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifndef __OpenBSD__ addr->sadb_address_proto = 0; addr->sadb_address_prefixlen = 0; #endif addr->sadb_address_reserved = 0; memcpy(addr + 1, src, sysdep_sa_len(src)); switch (((struct sockaddr *) (addr + 1))->sa_family) { case AF_INET: ((struct sockaddr_in *) (addr + 1))->sin_port = 0; break; case AF_INET6: ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; break; } if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifndef __OpenBSD__ addr->sadb_address_proto = 0; addr->sadb_address_prefixlen = 0; #endif addr->sadb_address_reserved = 0; memcpy(addr + 1, dst, sysdep_sa_len(dst)); switch (((struct sockaddr *) (addr + 1))->sa_family) { case AF_INET: ((struct sockaddr_in *) (addr + 1))->sin_port = 0; break; case AF_INET6: ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; break; } if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; #if 0 /* XXX I am not sure about what to do here just yet. */ if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) { len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(dst)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifndef __OpenBSD__ addr->sadb_address_proto = 0; addr->sadb_address_prefixlen = 0; #endif addr->sadb_address_reserved = 0; memcpy(addr + 1, dst, sysdep_sa_len(dst)); switch (((struct sockaddr *) (addr + 1))->sa_family) { case AF_INET: ((struct sockaddr_in *) (addr + 1))->sin_port = 0; break; case AF_INET6: ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; break; } if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; #if 0 msg->em_odst = msg->em_dst; msg->em_osrc = msg->em_src; #endif } #endif if (proto->proto != IPSEC_PROTO_IPCOMP) { /* Setup the KEY extensions. */ if (hashlen) { len = sizeof *key + PF_KEY_V2_ROUND(hashlen); key = malloc(len); if (!key) goto cleanup; key->sadb_key_exttype = SADB_EXT_KEY_AUTH; key->sadb_key_len = len / PF_KEY_V2_CHUNK; key->sadb_key_bits = hashlen * 8; key->sadb_key_reserved = 0; memcpy(key + 1, iproto->keymat[incoming] + (proto->proto == IPSEC_PROTO_IPSEC_ESP ? keylen : 0), hashlen); if (pf_key_v2_msg_add(update, (struct sadb_ext *) key, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; key = 0; } if (keylen) { len = sizeof *key + PF_KEY_V2_ROUND(keylen); key = malloc(len); if (!key) goto cleanup; key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; key->sadb_key_len = len / PF_KEY_V2_CHUNK; key->sadb_key_bits = keylen * 8; key->sadb_key_reserved = 0; memcpy(key + 1, iproto->keymat[incoming], keylen); if (pf_key_v2_msg_add(update, (struct sadb_ext *) key, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; key = 0; } } #ifndef KAME /* Setup identity extensions. */ if (isakmp_sa->id_i) { pp = pf_key_v2_convert_id(isakmp_sa->id_i, isakmp_sa->id_i_len, &len, &idtype); if (!pp) goto nosid; sid = calloc(PF_KEY_V2_ROUND(len + 1) + sizeof *sid, sizeof(u_int8_t)); if (!sid) { free(pp); goto cleanup; } sid->sadb_ident_type = idtype; sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) + PF_KEY_V2_ROUND(len + 1) / PF_KEY_V2_CHUNK; if ((isakmp_sa->initiator && !incoming) || (!isakmp_sa->initiator && incoming)) sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; else sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; memcpy(sid + 1, pp, len); free(pp); if (pf_key_v2_msg_add(update, (struct sadb_ext *) sid, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; sid = 0; nosid: if (sid) free(sid); sid = 0; } if (isakmp_sa->id_r) { pp = pf_key_v2_convert_id(isakmp_sa->id_r, isakmp_sa->id_r_len, &len, &idtype); if (!pp) goto nodid; sid = calloc(PF_KEY_V2_ROUND(len + 1) + sizeof *sid, sizeof(u_int8_t)); if (!sid) { free(pp); goto cleanup; } sid->sadb_ident_type = idtype; sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) + PF_KEY_V2_ROUND(len + 1) / PF_KEY_V2_CHUNK; if ((isakmp_sa->initiator && !incoming) || (!isakmp_sa->initiator && incoming)) sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; else sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; memcpy(sid + 1, pp, len); free(pp); if (pf_key_v2_msg_add(update, (struct sadb_ext *) sid, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; sid = 0; nodid: if (sid) free(sid); sid = 0; } #endif /* KAME */ #ifdef SADB_X_CREDTYPE_NONE /* * Send received credentials to the kernel. We don't bother with * our credentials, since the process either knows them (if it * specified them with setsockopt()), or has no business looking at * them (e.g., system wide certs). */ if (isakmp_sa->recv_cert) { switch (isakmp_sa->recv_certtype) { case ISAKMP_CERTENC_NONE: /* Nothing to be done here. */ break; #if defined (USE_KEYNOTE) && defined (SADB_X_EXT_REMOTE_CREDENTIALS) case ISAKMP_CERTENC_KEYNOTE: len = strlen(isakmp_sa->recv_cert); cred = calloc(PF_KEY_V2_ROUND(len) + sizeof *cred, sizeof(u_int8_t)); if (!cred) goto cleanup; cred->sadb_x_cred_len = ((sizeof *cred) / PF_KEY_V2_CHUNK) + PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK; cred->sadb_x_cred_exttype = SADB_X_EXT_REMOTE_CREDENTIALS; cred->sadb_x_cred_type = SADB_X_CREDTYPE_KEYNOTE; memcpy(cred + 1, isakmp_sa->recv_cert, len); if (pf_key_v2_msg_add(update, (struct sadb_ext *) cred, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; break; #endif /* USE_KEYNOTE */ #if defined (USE_X509) && defined (SADB_X_EXT_REMOTE_CREDENTIALS) case ISAKMP_CERTENC_X509_SIG: { u_int8_t *data; u_int32_t datalen; struct cert_handler *handler; /* We do it this way to avoid weird includes.*/ handler = cert_get(ISAKMP_CERTENC_X509_SIG); if (!handler) break; handler->cert_serialize(isakmp_sa->recv_cert, &data, &datalen); if (!data) break; len = datalen; cred = calloc(PF_KEY_V2_ROUND(len) + sizeof *cred, sizeof(u_int8_t)); if (!cred) { free(data); goto cleanup; } cred->sadb_x_cred_len = ((sizeof *cred) / PF_KEY_V2_CHUNK) + PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK; cred->sadb_x_cred_exttype = SADB_X_EXT_REMOTE_CREDENTIALS; cred->sadb_x_cred_type = SADB_X_CREDTYPE_X509; memcpy(cred + 1, data, len); free(data); if (pf_key_v2_msg_add(update, (struct sadb_ext *) cred, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; } break; #endif /* USE_X509 */ } } #endif /* SADB_X_CREDTYPE_NONE */ #ifdef SADB_X_AUTHTYPE_NONE /* * Tell the kernel what the peer used to authenticate, unless it was a * passphrase. */ if (isakmp_sa->recv_key) { u_int8_t *data; /* * If it's a private key, we shouldn't pass it to the kernel * for processes to see; successful authentication of Phase 1 * implies that the process already knew the passphrase. On * the other hand, we don't want to reveal to processes any * system-wide passphrases used for authentication with remote * systems. Same reason we don't send up the key (private or * passphrase) we used to authenticate with the peer. */ if (isakmp_sa->recv_keytype == ISAKMP_KEY_PASSPHRASE) goto doneauth; key_serialize(isakmp_sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC, isakmp_sa->recv_key, &data, &len); if (!data) goto cleanup; cred = calloc(PF_KEY_V2_ROUND(len) + sizeof *cred, sizeof(u_int8_t)); if (!cred) { free(data); goto cleanup; } cred->sadb_x_cred_len = ((sizeof *cred) / PF_KEY_V2_CHUNK) + PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK; cred->sadb_x_cred_exttype = SADB_X_EXT_REMOTE_AUTH; memcpy(cred + 1, data, len); free(data); switch (isakmp_sa->recv_keytype) { case ISAKMP_KEY_RSA: cred->sadb_x_cred_type = SADB_X_AUTHTYPE_RSA; break; default: log_print("pf_key_v2_set_spi: " "unknown received key type %d", isakmp_sa->recv_keytype); free(cred); goto cleanup; } if (pf_key_v2_msg_add(update, (struct sadb_ext *) cred, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; } doneauth: #endif /* SADB_X_AUTHTYPE_NONE */ #ifdef SADB_X_EXT_FLOW_TYPE /* Setup the flow type extension. */ bzero(&flowtype, sizeof flowtype); flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK; flowtype.sadb_protocol_direction = incoming ? IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT; if (pf_key_v2_msg_add(update, (struct sadb_ext *)&flowtype, 0) == -1) goto cleanup; bzero(&tprotocol, sizeof tprotocol); tprotocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; tprotocol.sadb_protocol_len = sizeof tprotocol / PF_KEY_V2_CHUNK; tprotocol.sadb_protocol_proto = isa->tproto; if (pf_key_v2_msg_add(update, (struct sadb_ext *)&tprotocol, 0) == -1) goto cleanup; len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(isa->src_net)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = incoming ? SADB_X_EXT_DST_FLOW : SADB_X_EXT_SRC_FLOW; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; addr->sadb_address_reserved = 0; pf_key_v2_setup_sockaddr(addr + 1, isa->src_net, 0, isa->sport, 0); if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = incoming ? SADB_X_EXT_DST_MASK : SADB_X_EXT_SRC_MASK; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; addr->sadb_address_reserved = 0; pf_key_v2_setup_sockaddr(addr + 1, isa->src_mask, 0, isa->sport ? 0xffff : 0, 0); if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = incoming ? SADB_X_EXT_SRC_FLOW : SADB_X_EXT_DST_FLOW; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; addr->sadb_address_reserved = 0; pf_key_v2_setup_sockaddr(addr + 1, isa->dst_net, 0, isa->dport, 0); if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = incoming ? SADB_X_EXT_SRC_MASK : SADB_X_EXT_DST_MASK; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; addr->sadb_address_reserved = 0; pf_key_v2_setup_sockaddr(addr + 1, isa->dst_mask, 0, isa->dport ? 0xffff : 0, 0); if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; #endif /* SADB_X_EXT_FLOW_TYPE */ /* XXX Here can sensitivity extensions be setup. */ #ifdef USE_DEBUG if (sockaddr2text(dst, &addr_str, 0)) addr_str = 0; LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_set_spi: " "satype %d dst %s SPI 0x%x", msg.sadb_msg_satype, addr_str ? addr_str : "unknown", ntohl(ssa.sadb_sa_spi))); if (addr_str) free(addr_str); #endif /* USE_DEBUG */ /* * Although PF_KEY knows about expirations, it is unreliable per the * specs thus we need to do them inside isakmpd as well. */ if (sa->seconds) if (sa_setup_expirations(sa)) goto cleanup; ret = pf_key_v2_call(update); pf_key_v2_msg_free(update); update = 0; if (!ret) goto cleanup; err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; pf_key_v2_msg_free(ret); ret = 0; /* * If we are doing an addition into an SADB shared with our peer, * errors here are to be expected as the peer will already have * created the SA, and can thus be ignored. */ if (err && !(msg.sadb_msg_type == SADB_ADD && conf_get_str("General", "Shared-SADB"))) { log_print("pf_key_v2_set_spi: %s: %s", msg.sadb_msg_type == SADB_ADD ? "ADD" : "UPDATE", strerror(err)); goto cleanup; } LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: done")); return 0; cleanup: if (sid) free(sid); if (addr) free(addr); if (life) free(life); if (key) free(key); if (update) pf_key_v2_msg_free(update); if (ret) pf_key_v2_msg_free(ret); return -1; } static __inline__ int pf_key_v2_mask_to_bits(u_int32_t mask) { u_int32_t hmask = ntohl(mask); return (33 - ffs(~hmask + 1)) % 33; } static int pf_key_v2_mask6_to_bits(u_int8_t * mask) { int n; bit_ffc(mask, 128, &n); return n == -1 ? 128 : n; } /* * Enable/disable a flow. * XXX Assumes OpenBSD {ADD,DEL}FLOW extensions. * Should probably be moved to sysdep.c */ static int pf_key_v2_flow(struct sockaddr *laddr, struct sockaddr *lmask, struct sockaddr *raddr, struct sockaddr *rmask, u_int8_t tproto, u_int16_t sport, u_int16_t dport, u_int8_t *spi, u_int8_t proto, struct sockaddr *dst, struct sockaddr *src, int delete, int ingress, u_int8_t srcid_type, u_int8_t *srcid, int srcid_len, u_int8_t dstid_type, u_int8_t *dstid, int dstid_len, struct ipsec_proto *iproto) { #ifdef USE_DEBUG char *laddr_str, *lmask_str, *raddr_str, *rmask_str; #endif #if defined (SADB_X_ADDFLOW) && defined (SADB_X_DELFLOW) struct sadb_msg msg; #if defined (SADB_X_EXT_FLOW_TYPE) struct sadb_protocol flowtype; struct sadb_ident *sid = 0; #else struct sadb_sa ssa; #endif struct sadb_address *addr = 0; struct sadb_protocol tprotocol; struct pf_key_v2_msg *flow = 0, *ret = 0; size_t len; int err; #if !defined (SADB_X_SAFLAGS_INGRESS_FLOW) && !defined (SADB_X_EXT_FLOW_TYPE) if (ingress) return 0; #endif msg.sadb_msg_type = delete ? SADB_X_DELFLOW : SADB_X_ADDFLOW; switch (proto) { case IPSEC_PROTO_IPSEC_ESP: msg.sadb_msg_satype = SADB_SATYPE_ESP; break; case IPSEC_PROTO_IPSEC_AH: msg.sadb_msg_satype = SADB_SATYPE_AH; break; case IPSEC_PROTO_IPCOMP: msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; break; default: log_print("pf_key_v2_flow: invalid proto %d", proto); goto cleanup; } msg.sadb_msg_seq = 0; flow = pf_key_v2_msg_new(&msg, 0); if (!flow) goto cleanup; #if defined (SADB_X_EXT_FLOW_TYPE) if (!delete) { /* Setup the source ID, if provided. */ if (srcid) { sid = calloc( PF_KEY_V2_ROUND(srcid_len + 1) + sizeof *sid, sizeof(u_int8_t)); if (!sid) goto cleanup; sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) + PF_KEY_V2_ROUND(srcid_len + 1) / PF_KEY_V2_CHUNK; sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; sid->sadb_ident_type = srcid_type; memcpy(sid + 1, srcid, srcid_len); if (pf_key_v2_msg_add(flow, (struct sadb_ext *) sid, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; sid = 0; } /* Setup the destination ID, if provided. */ if (dstid) { sid = calloc( PF_KEY_V2_ROUND(dstid_len + 1) + sizeof *sid, sizeof(u_int8_t)); if (!sid) goto cleanup; sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) + PF_KEY_V2_ROUND(dstid_len + 1) / PF_KEY_V2_CHUNK; sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; sid->sadb_ident_type = dstid_type; memcpy(sid + 1, dstid, dstid_len); if (pf_key_v2_msg_add(flow, (struct sadb_ext *) sid, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; sid = 0; } } /* Setup the flow type extension. */ bzero(&flowtype, sizeof flowtype); flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK; flowtype.sadb_protocol_direction = ingress ? IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT; flowtype.sadb_protocol_proto = ingress ? SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE; if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&flowtype, 0) == -1) goto cleanup; #else /* SADB_X_EXT_FLOW_TYPE */ /* Setup the SA extension. */ ssa.sadb_sa_exttype = SADB_EXT_SA; ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK; memcpy(&ssa.sadb_sa_spi, spi, sizeof ssa.sadb_sa_spi); ssa.sadb_sa_replay = 0; ssa.sadb_sa_state = 0; ssa.sadb_sa_auth = 0; ssa.sadb_sa_encrypt = 0; ssa.sadb_sa_flags = 0; #if defined (SADB_X_SAFLAGS_INGRESS_FLOW) if (ingress) ssa.sadb_sa_flags |= SADB_X_SAFLAGS_INGRESS_FLOW; #endif #if defined (SADB_X_SAFLAGS_REPLACEFLOW) if (!delete && !ingress) ssa.sadb_sa_flags |= SADB_X_SAFLAGS_REPLACEFLOW; #endif if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&ssa, 0) == -1) goto cleanup; #endif /* SADB_X_EXT_FLOW_TYPE */ /* * Setup the ADDRESS extensions. */ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src)); #if !defined (SADB_X_EXT_FLOW_TYPE) if (!delete || ingress) #else if (!delete) #endif /* SADB_X_EXT_FLOW_TYPE */ { addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; addr->sadb_address_reserved = 0; #if defined (SADB_X_EXT_FLOW_TYPE) pf_key_v2_setup_sockaddr(addr + 1, src, dst, 0, ingress); #else pf_key_v2_setup_sockaddr(addr + 1, dst, 0, 0, 0); #endif if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; } len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(laddr)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_X_EXT_SRC_FLOW; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; addr->sadb_address_reserved = 0; pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, sport, 0); if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_X_EXT_SRC_MASK; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; addr->sadb_address_reserved = 0; pf_key_v2_setup_sockaddr(addr + 1, lmask, 0, sport ? 0xffff : 0, 0); if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_X_EXT_DST_FLOW; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; addr->sadb_address_reserved = 0; pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, dport, 0); if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_X_EXT_DST_MASK; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; addr->sadb_address_reserved = 0; pf_key_v2_setup_sockaddr(addr + 1, rmask, 0, dport ? 0xffff : 0, 0); if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; /* Setup the protocol extension. */ bzero(&tprotocol, sizeof tprotocol); tprotocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; tprotocol.sadb_protocol_len = sizeof tprotocol / PF_KEY_V2_CHUNK; tprotocol.sadb_protocol_proto = tproto; if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&tprotocol, 0) == -1) goto cleanup; #ifdef USE_DEBUG if (sockaddr2text(laddr, &laddr_str, 0)) laddr_str = 0; if (sockaddr2text(lmask, &lmask_str, 0)) lmask_str = 0; if (sockaddr2text(raddr, &raddr_str, 0)) raddr_str = 0; if (sockaddr2text(rmask, &rmask_str, 0)) rmask_str = 0; LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: src %s %s dst %s %s proto %u sport %u dport %u", laddr_str ? laddr_str : "", lmask_str ? lmask_str : "", raddr_str ? raddr_str : "", rmask_str ? rmask_str : "", tproto, ntohs(sport), ntohs(dport))); if (laddr_str) free(laddr_str); if (lmask_str) free(lmask_str); if (raddr_str) free(raddr_str); if (rmask_str) free(rmask_str); #endif /* USE_DEBUG */ ret = pf_key_v2_call(flow); pf_key_v2_msg_free(flow); flow = 0; if (!ret) goto cleanup; err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; if (err) { if (err == ESRCH) /* These are common and usually * harmless. */ LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_flow: %sFLOW: %s", delete ? "DEL" : "ADD", strerror(err))); else log_print("pf_key_v2_flow: %sFLOW: %s", delete ? "DEL" : "ADD", strerror(err)); goto cleanup; } pf_key_v2_msg_free(ret); LOG_DBG((LOG_MISC, 50, "pf_key_v2_flow: %sFLOW: done", delete ? "DEL" : "ADD")); return 0; cleanup: #if defined (SADB_X_EXT_FLOW_TYPE) if (sid) free(sid); #endif /* SADB_X_EXT_FLOW_TYPE */ if (addr) free(addr); if (flow) pf_key_v2_msg_free(flow); if (ret) pf_key_v2_msg_free(ret); return -1; #elif defined (SADB_X_SPDADD) && defined (SADB_X_SPDDELETE) struct sadb_msg msg; struct sadb_x_policy *policy = 0; struct sadb_x_ipsecrequest *ipsecrequest; struct sadb_x_sa2 ssa2; struct sadb_address *addr = 0; struct sockaddr *saddr; struct pf_key_v2_msg *flow = 0, *ret = 0; u_int8_t *policy_buf; size_t len; int err; struct sockaddr_in *ip4_sa; struct sockaddr_in6 *ip6_sa; msg.sadb_msg_type = delete ? SADB_X_SPDDELETE : SADB_X_SPDADD; msg.sadb_msg_satype = SADB_SATYPE_UNSPEC; msg.sadb_msg_seq = 0; flow = pf_key_v2_msg_new(&msg, 0); if (!flow) goto cleanup; memset(&ssa2, 0, sizeof ssa2); ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; ssa2.sadb_x_sa2_mode = 0; if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&ssa2, 0) == -1) goto cleanup; /* * Setup the ADDRESS extensions. */ len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifdef LINUX_IPSEC addr->sadb_address_proto = tproto; #else addr->sadb_address_proto = IPSEC_ULPROTO_ANY; #endif addr->sadb_address_reserved = 0; #ifdef LINUX_IPSEC pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, sport, 0); #else pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, IPSEC_PORT_ANY, 0); #endif switch (laddr->sa_family) { case AF_INET: ip4_sa = (struct sockaddr_in *) lmask; addr->sadb_address_prefixlen = pf_key_v2_mask_to_bits(ip4_sa->sin_addr.s_addr); break; case AF_INET6: ip6_sa = (struct sockaddr_in6 *) lmask; addr->sadb_address_prefixlen = pf_key_v2_mask6_to_bits(&ip6_sa->sin6_addr.s6_addr[0]); break; } if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(raddr)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifdef LINUX_IPSEC addr->sadb_address_proto = tproto; #else addr->sadb_address_proto = IPSEC_ULPROTO_ANY; #endif addr->sadb_address_reserved = 0; #ifdef LINUX_IPSEC pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, dport, 0); #else pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, IPSEC_PORT_ANY, 0); #endif switch (raddr->sa_family) { case AF_INET: ip4_sa = (struct sockaddr_in *) rmask; addr->sadb_address_prefixlen = pf_key_v2_mask_to_bits(ip4_sa->sin_addr.s_addr); break; case AF_INET6: ip6_sa = (struct sockaddr_in6 *) rmask; addr->sadb_address_prefixlen = pf_key_v2_mask6_to_bits(&ip6_sa->sin6_addr.s6_addr[0]); break; } if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; /* Setup the POLICY extension. */ len = sizeof *policy + sizeof *ipsecrequest + 2 * PF_KEY_V2_ROUND(sysdep_sa_len(src)); policy_buf = (u_int8_t *) calloc(1, len); if (!policy_buf) { log_error("pf_key_v2_flow: calloc %lu failed", (unsigned long) len); goto cleanup; } policy = (struct sadb_x_policy *) policy_buf; policy->sadb_x_policy_exttype = SADB_X_EXT_POLICY; policy->sadb_x_policy_len = len / PF_KEY_V2_CHUNK; policy->sadb_x_policy_type = IPSEC_POLICY_IPSEC; if (ingress) policy->sadb_x_policy_dir = IPSEC_DIR_INBOUND; else policy->sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; policy->sadb_x_policy_reserved = 0; /* Setup the IPSECREQUEST extension part. */ ipsecrequest = (struct sadb_x_ipsecrequest *) (policy + 1); ipsecrequest->sadb_x_ipsecrequest_len = len - sizeof *policy; switch (proto) { case IPSEC_PROTO_IPSEC_ESP: ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_ESP; break; case IPSEC_PROTO_IPSEC_AH: ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_AH; break; default: log_print("pf_key_v2_flow: invalid proto %d", proto); goto cleanup; } #if defined (LINUX_IPSEC) if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; else ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT; #else ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; /* XXX */ #endif ipsecrequest->sadb_x_ipsecrequest_level = ingress ? IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE; ipsecrequest->sadb_x_ipsecrequest_reqid = 0; /* XXX */ /* Add source and destination addresses. */ saddr = (struct sockaddr *)(ipsecrequest + 1); pf_key_v2_setup_sockaddr(saddr, src, 0, 0, 0); switch (src->sa_family) { case AF_INET: saddr = (struct sockaddr *)((struct sockaddr_in *)saddr + 1); break; case AF_INET6: saddr = (struct sockaddr *)((struct sockaddr_in6 *)saddr + 1); break; } pf_key_v2_setup_sockaddr(saddr, dst, 0, 0, 0); if (pf_key_v2_msg_add(flow, (struct sadb_ext *)policy, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; policy = 0; #ifdef USE_DEBUG if (sockaddr2text(laddr, &laddr_str, 0)) laddr_str = 0; if (sockaddr2text(lmask, &lmask_str, 0)) lmask_str = 0; if (sockaddr2text(raddr, &raddr_str, 0)) raddr_str = 0; if (sockaddr2text(rmask, &rmask_str, 0)) rmask_str = 0; LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: src %s %s dst %s %s", laddr_str ? laddr_str : "", lmask_str ? lmask_str : "", raddr_str ? raddr_str : "", rmask_str ? rmask_str : "")); if (laddr_str) free(laddr_str); if (lmask_str) free(lmask_str); if (raddr_str) free(raddr_str); if (rmask_str) free(rmask_str); #endif ret = pf_key_v2_call(flow); pf_key_v2_msg_free(flow); flow = 0; if (!ret) goto cleanup; err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; if (!delete && err == EEXIST) { LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: " "SPDADD returns EEXIST")); } else if (err) { log_print("pf_key_v2_flow: SPD%s: %s", delete ? "DELETE" : "ADD", strerror(err)); goto cleanup; } pf_key_v2_msg_free(ret); LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: SPD%s: done", delete ? "DELETE" : "ADD")); return 0; cleanup: if (addr) free(addr); if (policy) free(policy); if (flow) pf_key_v2_msg_free(flow); if (ret) pf_key_v2_msg_free(ret); return -1; #else log_print("pf_key_v2_flow: not supported in pure PF_KEYv2"); return -1; #endif } #ifndef KAME static u_int8_t * pf_key_v2_convert_id(u_int8_t * id, int idlen, size_t * reslen, int *idtype) { u_int8_t *addr, *res = 0; char addrbuf[ADDRESS_MAX + 5]; switch (id[0]) { case IPSEC_ID_FQDN: res = calloc(idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ, sizeof(u_int8_t)); if (!res) return 0; *reslen = idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ; memcpy(res, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, *reslen); *idtype = SADB_IDENTTYPE_FQDN; LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: FQDN %.*s", (int) *reslen, res)); return res; case IPSEC_ID_USER_FQDN: res = calloc(idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ, sizeof(u_int8_t)); if (!res) return 0; *reslen = idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ; memcpy(res, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, *reslen); *idtype = SADB_IDENTTYPE_USERFQDN; LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: UFQDN %.*s", (int) *reslen, res)); return res; case IPSEC_ID_IPV4_ADDR: /* XXX CONNECTION ? */ if (inet_ntop(AF_INET, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, addrbuf, ADDRESS_MAX) == NULL) return 0; *reslen = strlen(addrbuf) + 3; strlcat(addrbuf, "/32", ADDRESS_MAX + 5); res = (u_int8_t *) strdup(addrbuf); if (!res) return 0; *idtype = SADB_IDENTTYPE_PREFIX; LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " "IPv4 address %s", res)); return res; case IPSEC_ID_IPV6_ADDR: /* XXX CONNECTION ? */ if (inet_ntop(AF_INET6, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, addrbuf, ADDRESS_MAX) == NULL) return 0; *reslen = strlen(addrbuf) + 4; strlcat(addrbuf, "/128", ADDRESS_MAX + 5); res = (u_int8_t *) strdup(addrbuf); if (!res) return 0; LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " "IPv6 address %s", res)); *idtype = SADB_IDENTTYPE_PREFIX; return res; case IPSEC_ID_IPV4_ADDR_SUBNET: /* XXX PREFIX */ addr = id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; if (inet_ntop(AF_INET, addr, addrbuf, ADDRESS_MAX) == NULL) return 0; snprintf(addrbuf + strlen(addrbuf), ADDRESS_MAX - strlen(addrbuf), "/%d", pf_key_v2_mask_to_bits(*(u_int32_t *)(addr + sizeof(struct in_addr)))); *reslen = strlen(addrbuf); res = (u_int8_t *) strdup(addrbuf); if (!res) return 0; *idtype = SADB_IDENTTYPE_PREFIX; LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " "IPv4 subnet %s", res)); return res; case IPSEC_ID_IPV6_ADDR_SUBNET: /* XXX PREFIX */ addr = id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; if (inet_ntop(AF_INET6, addr, addrbuf, ADDRESS_MAX) == NULL) return 0; snprintf(addrbuf + strlen(addrbuf), ADDRESS_MAX - strlen(addrbuf), "/%d", pf_key_v2_mask6_to_bits(addr + sizeof(struct in6_addr))); *reslen = strlen(addrbuf); res = (u_int8_t *) strdup(addrbuf); if (!res) return 0; LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: " "IPv6 subnet %s", res)); *idtype = SADB_IDENTTYPE_PREFIX; return res; case IPSEC_ID_IPV4_RANGE: case IPSEC_ID_IPV6_RANGE: case IPSEC_ID_DER_ASN1_DN: case IPSEC_ID_DER_ASN1_GN: case IPSEC_ID_KEY_ID: /* XXX Not implemented yet. */ return 0; } return 0; } #endif /* Enable a flow given an SA. */ int pf_key_v2_enable_sa(struct sa *sa, struct sa *isakmp_sa) { struct ipsec_sa *isa = sa->data; struct sockaddr *dst, *src; int error; struct proto *proto = TAILQ_FIRST(&sa->protos); int sidtype = 0, didtype = 0; size_t sidlen = 0, didlen = 0; u_int8_t *sid = 0, *did = 0; #if !defined (SADB_X_EXT_FLOW_TYPE) struct sockaddr_storage hostmask_storage; struct sockaddr *hostmask = (struct sockaddr *)&hostmask_storage; #endif /* SADB_X_EXT_FLOW_TYPE */ sa->transport->vtbl->get_dst(sa->transport, &dst); sa->transport->vtbl->get_src(sa->transport, &src); #if defined (SADB_X_EXT_FLOW_TYPE) if (isakmp_sa->id_i) { if (isakmp_sa->initiator) sid = pf_key_v2_convert_id(isakmp_sa->id_i, isakmp_sa->id_i_len, &sidlen, &sidtype); else did = pf_key_v2_convert_id(isakmp_sa->id_i, isakmp_sa->id_i_len, &didlen, &didtype); } if (isakmp_sa->id_r) { if (isakmp_sa->initiator) did = pf_key_v2_convert_id(isakmp_sa->id_r, isakmp_sa->id_r_len, &didlen, &didtype); else sid = pf_key_v2_convert_id(isakmp_sa->id_r, isakmp_sa->id_r_len, &sidlen, &sidtype); } #endif /* SADB_X_EXT_FLOW_TYPE */ error = pf_key_v2_flow(isa->src_net, isa->src_mask, isa->dst_net, isa->dst_mask, isa->tproto, isa->sport, isa->dport, proto->spi[0], proto->proto, dst, src, 0, 0, sidtype, sid, sidlen, didtype, did, didlen, proto->data); if (error) goto cleanup; #if !defined (SADB_X_EXT_FLOW_TYPE) /* Set hostmask to '-1'. */ switch (dst->sa_family) { case AF_INET: ((struct sockaddr_in *) hostmask)->sin_family = AF_INET; #ifndef USE_OLD_SOCKADDR ((struct sockaddr_in *) hostmask)->sin_len = sizeof(struct in_addr); #endif memset(&((struct sockaddr_in *) hostmask)->sin_addr.s_addr, 0xff, sizeof(struct in_addr)); break; case AF_INET6: ((struct sockaddr_in6 *) hostmask)->sin6_family = AF_INET6; #ifndef USE_OLD_SOCKADDR ((struct sockaddr_in6 *) hostmask)->sin6_len = sizeof(struct in6_addr); #endif memset(&((struct sockaddr_in6 *) hostmask)->sin6_addr.s6_addr, 0xff, sizeof(struct in6_addr)); break; } /* Ingress flows, handling SA bundles. */ while (TAILQ_NEXT(proto, link)) { error = pf_key_v2_flow(dst, hostmask, src, hostmask, 0, 0, 0, proto->spi[1], proto->proto, src, dst, 0, 1, 0, 0, 0, 0, 0, 0, proto->data); if (error) goto cleanup; proto = TAILQ_NEXT(proto, link); } #endif /* SADB_X_EXT_FLOW_TYPE */ error = pf_key_v2_flow(isa->dst_net, isa->dst_mask, isa->src_net, isa->src_mask, isa->tproto, isa->dport, isa->sport, proto->spi[1], proto->proto, src, dst, 0, 1, sidtype, sid, sidlen, didtype, did, didlen, proto->data); cleanup: #if defined (SADB_X_EXT_FLOW_TYPE) if (sid) free(sid); if (did) free(did); #endif /* SADB_X_EXT_FLOW_TYPE */ return error; } #if defined (SADB_X_ASKPOLICY) /* Increase reference count of refcounted sections. */ static int pf_key_v2_conf_refinc(int af, char *section) { char conn[22]; int num; if (!section) return 0; num = conf_get_num(section, "Refcount", 0); if (num == 0) return 0; snprintf(conn, sizeof conn, "%d", num + 1); conf_set(af, section, "Refcount", conn, 1, 0); return 0; } #endif /* * Return 0 if the section didn't exist or was removed, non-zero otherwise. * Don't touch non-refcounted (statically defined) sections. */ static int pf_key_v2_conf_refhandle(int af, char *section) { char conn[22]; int num; if (!section) return 0; num = conf_get_num(section, "Refcount", 0); if (num == 1) { conf_remove_section(af, section); num--; } else if (num != 0) { snprintf(conn, sizeof conn, "%d", num - 1); conf_set(af, section, "Refcount", conn, 1, 0); } return num; } /* Remove all dynamically-established configuration entries. */ static int pf_key_v2_remove_conf(char *section) { char *ikepeer, *localid, *remoteid, *configname; struct conf_list_node *attr; struct conf_list *attrs; int af; if (!section) return 0; if (!conf_get_str(section, "Phase")) return 0; /* Only remove dynamically-established entries. */ attrs = conf_get_list(section, "Flags"); if (attrs) { for (attr = TAILQ_FIRST(&attrs->fields); attr; attr = TAILQ_NEXT(attr, link)) if (!strcasecmp(attr->field, "__ondemand")) goto passed; conf_free_list(attrs); } return 0; passed: conf_free_list(attrs); af = conf_begin(); configname = conf_get_str(section, "Configuration"); conf_remove_section(af, configname); /* These are the Phase 2 Local/Remote IDs. */ localid = conf_get_str(section, "Local-ID"); pf_key_v2_conf_refhandle(af, localid); remoteid = conf_get_str(section, "Remote-ID"); pf_key_v2_conf_refhandle(af, remoteid); ikepeer = conf_get_str(section, "ISAKMP-peer"); pf_key_v2_conf_refhandle(af, section); if (ikepeer) { remoteid = conf_get_str(ikepeer, "Remote-ID"); localid = conf_get_str(ikepeer, "ID"); configname = conf_get_str(ikepeer, "Configuration"); pf_key_v2_conf_refhandle(af, ikepeer); pf_key_v2_conf_refhandle(af, configname); /* Phase 1 IDs */ pf_key_v2_conf_refhandle(af, localid); pf_key_v2_conf_refhandle(af, remoteid); } conf_end(af, 1); return 0; } /* Disable a flow given a SA. */ static int pf_key_v2_disable_sa(struct sa *sa, int incoming) { struct ipsec_sa *isa = sa->data; struct sockaddr *dst, *src; struct proto *proto = TAILQ_FIRST(&sa->protos); #if !defined (SADB_X_EXT_FLOW_TYPE) struct sockaddr_storage hostmask_storage; struct sockaddr *hostmask = (struct sockaddr *)&hostmask_storage; int error; #endif /* SADB_X_EXT_FLOW_TYPE */ sa->transport->vtbl->get_dst(sa->transport, &dst); sa->transport->vtbl->get_src(sa->transport, &src); if (!incoming) return pf_key_v2_flow(isa->src_net, isa->src_mask, isa->dst_net, isa->dst_mask, isa->tproto, isa->sport, isa->dport, proto->spi[0], proto->proto, src, dst, 1, 0, 0, 0, 0, 0, 0, 0, proto->data); else { #if !defined (SADB_X_EXT_FLOW_TYPE) /* Set hostmask to '-1'. */ switch (dst->sa_family) { case AF_INET: ((struct sockaddr_in *) hostmask)->sin_family = AF_INET; #ifndef USE_OLD_SOCKADDR ((struct sockaddr_in *) hostmask)->sin_len = sizeof(struct in_addr); #endif memset(&((struct sockaddr_in *) hostmask)->sin_addr.s_addr, 0xff, sizeof(struct in_addr)); break; case AF_INET6: ((struct sockaddr_in6 *) hostmask)->sin6_family = AF_INET6; #ifndef USE_OLD_SOCKADDR ((struct sockaddr_in6 *) hostmask)->sin6_len = sizeof(struct in6_addr); #endif memset(&((struct sockaddr_in6 *) hostmask)->sin6_addr.s6_addr, 0xff, sizeof(struct in6_addr)); break; } /* Ingress flow --- SA bundles */ while (TAILQ_NEXT(proto, link)) { error = pf_key_v2_flow(dst, hostmask, src, hostmask, 0, 0, 0, proto->spi[1], proto->proto, src, dst, 1, 1, 0, 0, 0, 0, 0, 0, proto->data); if (error) return error; proto = TAILQ_NEXT(proto, link); } #endif /* SADB_X_EXT_FLOW_TYPE */ return pf_key_v2_flow(isa->dst_net, isa->dst_mask, isa->src_net, isa->src_mask, isa->tproto, isa->dport, isa->sport, proto->spi[1], proto->proto, src, dst, 1, 1, 0, 0, 0, 0, 0, 0, proto->data); } } /* * Delete the IPsec SA represented by the INCOMING direction in protocol PROTO * of the IKE security association SA. Also delete potential flows tied to it. */ int pf_key_v2_delete_spi(struct sa *sa, struct proto *proto, int incoming) { struct sadb_msg msg; struct sadb_sa ssa; struct sadb_address *addr = 0; struct sockaddr *saddr; int len, err; struct pf_key_v2_msg *delete = 0, *ret = 0; #ifdef KAME struct sadb_x_sa2 ssa2; #endif /* If it's not an established SA, don't proceed. */ if (!(sa->flags & SA_FLAG_READY)) return 0; /* * If the SA was not replaced and was not one acquired through the * kernel (ACQUIRE message), remove the flow associated with it. * We ignore any errors from the disabling of the flow. */ if (!(sa->flags & SA_FLAG_REPLACED) && !(sa->flags & SA_FLAG_ONDEMAND)) pf_key_v2_disable_sa(sa, incoming); if (sa->name && !(sa->flags & SA_FLAG_REPLACED)) { LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_delete_spi: removing configuration %s", sa->name)); pf_key_v2_remove_conf(sa->name); } msg.sadb_msg_type = SADB_DELETE; switch (proto->proto) { case IPSEC_PROTO_IPSEC_ESP: msg.sadb_msg_satype = SADB_SATYPE_ESP; break; case IPSEC_PROTO_IPSEC_AH: msg.sadb_msg_satype = SADB_SATYPE_AH; break; #if defined (SADB_X_SATYPE_IPCOMP) case IPSEC_PROTO_IPCOMP: msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; break; #endif default: log_print("pf_key_v2_delete_spi: invalid proto %d", proto->proto); goto cleanup; } msg.sadb_msg_seq = 0; delete = pf_key_v2_msg_new(&msg, 0); if (!delete) goto cleanup; /* Setup the SA extension. */ ssa.sadb_sa_exttype = SADB_EXT_SA; ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK; memcpy(&ssa.sadb_sa_spi, proto->spi[incoming], sizeof ssa.sadb_sa_spi); ssa.sadb_sa_replay = 0; ssa.sadb_sa_state = 0; ssa.sadb_sa_auth = 0; ssa.sadb_sa_encrypt = 0; ssa.sadb_sa_flags = 0; if (pf_key_v2_msg_add(delete, (struct sadb_ext *)&ssa, 0) == -1) goto cleanup; #ifdef KAME memset(&ssa2, 0, sizeof ssa2); ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK; ssa2.sadb_x_sa2_mode = 0; if (pf_key_v2_msg_add(delete, (struct sadb_ext *)&ssa2, 0) == -1) goto cleanup; #endif /* * Setup the ADDRESS extensions. */ if (incoming) sa->transport->vtbl->get_dst(sa->transport, &saddr); else sa->transport->vtbl->get_src(sa->transport, &saddr); len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifndef __OpenBSD__ addr->sadb_address_proto = 0; addr->sadb_address_prefixlen = 0; #endif addr->sadb_address_reserved = 0; memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); switch (saddr->sa_family) { case AF_INET: ((struct sockaddr_in *) (addr + 1))->sin_port = 0; break; case AF_INET6: ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; break; } if (pf_key_v2_msg_add(delete, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; if (incoming) sa->transport->vtbl->get_src(sa->transport, &saddr); else sa->transport->vtbl->get_dst(sa->transport, &saddr); len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifndef __OpenBSD__ addr->sadb_address_proto = 0; addr->sadb_address_prefixlen = 0; #endif addr->sadb_address_reserved = 0; memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); switch (saddr->sa_family) { case AF_INET: ((struct sockaddr_in *) (addr + 1))->sin_port = 0; break; case AF_INET6: ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0; break; } if (pf_key_v2_msg_add(delete, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; ret = pf_key_v2_call(delete); pf_key_v2_msg_free(delete); delete = 0; if (!ret) goto cleanup; err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; if (err) { LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_delete_spi: DELETE: %s", strerror(err))); goto cleanup; } pf_key_v2_msg_free(ret); LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_delete_spi: done")); return 0; cleanup: if (addr) free(addr); if (delete) pf_key_v2_msg_free(delete); if (ret) pf_key_v2_msg_free(ret); return -1; } static void pf_key_v2_stayalive(struct exchange *exchange, void *vconn, int fail) { char *conn = vconn; struct sa *sa; /* XXX What if it is phase 1 ? */ sa = sa_lookup_by_name(conn, 2); if (sa) sa->flags |= SA_FLAG_STAYALIVE; /* * Remove failed configuration entry -- call twice because it is * created with a Refcount of 2. */ if (fail && (!exchange || exchange->name)) { pf_key_v2_remove_conf(conn); pf_key_v2_remove_conf(conn); } } /* Check if a connection CONN exists, otherwise establish it. */ void pf_key_v2_connection_check(char *conn) { if (!sa_lookup_by_name(conn, 2)) { LOG_DBG((LOG_SYSDEP, 70, "pf_key_v2_connection_check: SA for %s missing", conn)); exchange_establish(conn, pf_key_v2_stayalive, conn); } else LOG_DBG((LOG_SYSDEP, 70, "pf_key_v2_connection_check: " "SA for %s exists", conn)); } /* Handle a PF_KEY lifetime expiration message PMSG. */ static void pf_key_v2_expire(struct pf_key_v2_msg *pmsg) { struct sadb_msg *msg; struct sadb_sa *ssa; struct sadb_address *dst; struct sockaddr *dstaddr; struct sadb_lifetime *life, *lifecurrent; struct sa *sa; struct pf_key_v2_node *lifenode, *ext; #ifdef USE_DEBUG char *dst_str; #endif msg = (struct sadb_msg *)TAILQ_FIRST(pmsg)->seg; ext = pf_key_v2_find_ext(pmsg, SADB_EXT_SA); if (!ext) { log_print("pf_key_v2_expire: no SA extension found"); return; } ssa = ext->seg; ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_DST); if (!ext) { log_print("pf_key_v2_expire: " "no destination address extension found"); return; } dst = ext->seg; dstaddr = (struct sockaddr *) (dst + 1); lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_HARD); if (!lifenode) lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_SOFT); if (!lifenode) { log_print("pf_key_v2_expire: no lifetime extension found"); return; } life = lifenode->seg; lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_CURRENT); if (!lifenode) { log_print("pf_key_v2_expire: " "no current lifetime extension found"); return; } lifecurrent = lifenode->seg; #ifdef USE_DEBUG if (sockaddr2text(dstaddr, &dst_str, 0)) dst_str = 0; LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_expire: " "%s dst %s SPI %x sproto %d", life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? "SOFT" : "HARD", dst_str ? dst_str : "", ntohl(ssa->sadb_sa_spi), msg->sadb_msg_satype)); if (dst_str) free(dst_str); #endif /* USE_DEBUG */ /* * Find the IPsec SA. The IPsec stack has two SAs for every IKE SA, * one outgoing and one incoming, we regard expirations for any of * them as an expiration of the full IKE SA. Likewise, in * protection suites consisting of more than one protocol, any * expired individual IPsec stack SA will be seen as an expiration * of the full suite. */ switch (msg->sadb_msg_satype) { case SADB_SATYPE_ESP: sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi, IPSEC_PROTO_IPSEC_ESP); break; case SADB_SATYPE_AH: sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi, IPSEC_PROTO_IPSEC_AH); break; #ifdef SADB_X_SATYPE_IPCOMP case SADB_X_SATYPE_IPCOMP: sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi, IPSEC_PROTO_IPCOMP); break; #endif default: /* XXX Log? */ sa = 0; break; } /* If the SA is already gone, don't do anything. */ if (!sa) return; /* * If we got a notification, try to renegotiate the SA -- unless of * course it has already been replaced by another. * Also, ignore SAs that were not dynamically established, or that * did not see any use. */ if (!(sa->flags & SA_FLAG_REPLACED) && (sa->flags & SA_FLAG_ONDEMAND) && lifecurrent->sadb_lifetime_bytes) exchange_establish(sa->name, 0, 0); if (life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_HARD) { /* Remove the old SA, it isn't useful anymore. */ sa_free(sa); } } /* Handle a PF_KEY SA ACQUIRE message PMSG. */ static void pf_key_v2_acquire(struct pf_key_v2_msg *pmsg) { #if defined (SADB_X_ASKPOLICY) struct sadb_msg *msg, askpolicy_msg; struct pf_key_v2_msg *askpolicy = 0, *ret = 0; struct sadb_x_policy policy; struct sadb_address *dst = 0, *src = 0; struct sockaddr *dstaddr, *srcaddr = 0; struct sadb_comb *scmb = 0; struct sadb_prop *sprp = 0; struct sadb_ident *srcident = 0, *dstident = 0; char dstbuf[ADDRESS_MAX], srcbuf[ADDRESS_MAX], *peer = 0, *conn = 0; char confname[120]; char *srcid = 0, *dstid = 0, *prefstring = 0; int slen, af, afamily, masklen, buflen; struct sockaddr *smask, *sflow, *dmask, *dflow; struct sadb_protocol *sproto; char ssflow[ADDRESS_MAX], sdflow[ADDRESS_MAX]; char sdmask[ADDRESS_MAX], ssmask[ADDRESS_MAX]; char *sidtype = 0, *didtype = 0; char lname[100], dname[100], configname[30]; int shostflag = 0, dhostflag = 0; struct pf_key_v2_node *ext; struct passwd *pwd = 0; u_int16_t sport = 0, dport = 0; u_int8_t tproto = 0; char tmbuf[sizeof sport * 3 + 1], *xform; int connlen; #if defined (SADB_X_CREDTYPE_NONE) struct sadb_x_cred *cred = 0, *sauth = 0; #endif /* This needs to be dynamically allocated. */ connlen = 22; conn = malloc(connlen); if (!conn) { log_error("pf_key_v2_acquire: malloc (%d) failed", connlen); return; } msg = (struct sadb_msg *)TAILQ_FIRST(pmsg)->seg; ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_DST); if (!ext) { log_print("pf_key_v2_acquire: " "no destination address specified"); return; } dst = ext->seg; ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_SRC); if (ext) src = ext->seg; ext = pf_key_v2_find_ext(pmsg, SADB_EXT_PROPOSAL); if (ext) { sprp = ext->seg; scmb = (struct sadb_comb *) (sprp + 1); } ext = pf_key_v2_find_ext(pmsg, SADB_EXT_IDENTITY_SRC); if (ext) srcident = ext->seg; ext = pf_key_v2_find_ext(pmsg, SADB_EXT_IDENTITY_DST); if (ext) dstident = ext->seg; /* Ask the kernel for the matching policy. */ bzero(&askpolicy_msg, sizeof askpolicy_msg); askpolicy_msg.sadb_msg_type = SADB_X_ASKPOLICY; askpolicy = pf_key_v2_msg_new(&askpolicy_msg, 0); if (!askpolicy) goto fail; policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; policy.sadb_x_policy_len = sizeof policy / PF_KEY_V2_CHUNK; policy.sadb_x_policy_seq = msg->sadb_msg_seq; if (pf_key_v2_msg_add(askpolicy, (struct sadb_ext *)&policy, 0) == -1) goto fail; ret = pf_key_v2_call(askpolicy); if (!ret) goto fail; /* Now we have all the information needed. */ ext = pf_key_v2_find_ext(ret, SADB_X_EXT_SRC_FLOW); if (!ext) { log_print("pf_key_v2_acquire: no source flow extension found"); goto fail; } sflow = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); ext = pf_key_v2_find_ext(ret, SADB_X_EXT_DST_FLOW); if (!ext) { log_print("pf_key_v2_acquire: " "no destination flow extension found"); goto fail; } dflow = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); ext = pf_key_v2_find_ext(ret, SADB_X_EXT_SRC_MASK); if (!ext) { log_print("pf_key_v2_acquire: no source mask extension found"); goto fail; } smask = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); ext = pf_key_v2_find_ext(ret, SADB_X_EXT_DST_MASK); if (!ext) { log_print("pf_key_v2_acquire: " "no destination mask extension found"); goto fail; } dmask = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1); ext = pf_key_v2_find_ext(ret, SADB_X_EXT_FLOW_TYPE); if (!ext) { log_print("pf_key_v2_acquire: no flow type extension found"); goto fail; } sproto = ext->seg; tproto = sproto->sadb_protocol_proto; #if defined (SADB_X_EXT_LOCAL_CREDENTIALS) ext = pf_key_v2_find_ext(pmsg, SADB_X_EXT_LOCAL_CREDENTIALS); if (ext) cred = (struct sadb_x_cred *) ext->seg; else cred = 0; #endif #if defined (SADB_X_EXT_LOCAL_AUTH) ext = pf_key_v2_find_ext(pmsg, SADB_X_EXT_LOCAL_AUTH); if (ext) sauth = (struct sadb_x_cred *) ext->seg; else sauth = 0; #endif bzero(ssflow, sizeof ssflow); bzero(sdflow, sizeof sdflow); bzero(ssmask, sizeof ssmask); bzero(sdmask, sizeof sdmask); sidtype = didtype = "IPV4_ADDR_SUBNET"; /* default */ switch (sflow->sa_family) { case AF_INET: if (inet_ntop(AF_INET, &((struct sockaddr_in *) sflow)->sin_addr, ssflow, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: inet_ntop failed"); goto fail; } sport = ((struct sockaddr_in *) sflow)->sin_port; if (inet_ntop(AF_INET, &((struct sockaddr_in *) dflow)->sin_addr, sdflow, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: inet_ntop failed"); goto fail; } dport = ((struct sockaddr_in *) dflow)->sin_port; if (inet_ntop(AF_INET, &((struct sockaddr_in *) smask)->sin_addr, ssmask, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: inet_ntop failed"); goto fail; } if (inet_ntop(AF_INET, &((struct sockaddr_in *) dmask)->sin_addr, sdmask, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: inet_ntop failed"); goto fail; } if (((struct sockaddr_in *) smask)->sin_addr.s_addr == INADDR_BROADCAST) { shostflag = 1; sidtype = "IPV4_ADDR"; } if (((struct sockaddr_in *) dmask)->sin_addr.s_addr == INADDR_BROADCAST) { dhostflag = 1; didtype = "IPV4_ADDR"; } break; case AF_INET6: if (inet_ntop(AF_INET6, &((struct sockaddr_in6 *) sflow)->sin6_addr, ssflow, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: inet_ntop failed"); goto fail; } sport = ((struct sockaddr_in6 *) sflow)->sin6_port; if (inet_ntop(AF_INET6, &((struct sockaddr_in6 *) dflow)->sin6_addr, sdflow, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: inet_ntop failed"); goto fail; } dport = ((struct sockaddr_in6 *) dflow)->sin6_port; if (inet_ntop(AF_INET6, &((struct sockaddr_in6 *) smask)->sin6_addr, ssmask, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: inet_ntop failed"); goto fail; } if (inet_ntop(AF_INET6, &((struct sockaddr_in6 *) dmask)->sin6_addr, sdmask, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: inet_ntop failed"); goto fail; } sidtype = didtype = "IPV6_ADDR_SUBNET"; if (IN6_IS_ADDR_FULL(&((struct sockaddr_in6 *)smask)->sin6_addr)) { shostflag = 1; sidtype = "IPV6_ADDR"; } if (IN6_IS_ADDR_FULL(&((struct sockaddr_in6 *)dmask)->sin6_addr)) { dhostflag = 1; didtype = "IPV6_ADDR"; } break; } dstaddr = (struct sockaddr *)(dst + 1); bzero(dstbuf, sizeof dstbuf); bzero(srcbuf, sizeof srcbuf); if (dstaddr->sa_family == 0) { /* * Destination was not specified in the flow -- can we derive * it? */ if (dhostflag == 0) { log_print("pf_key_v2_acquire: " "Cannot determine precise destination"); goto fail; } dstaddr = dflow; } switch (dstaddr->sa_family) { case AF_INET: if (inet_ntop(AF_INET, &((struct sockaddr_in *) dstaddr)->sin_addr, dstbuf, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: inet_ntop failed"); goto fail; } LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_acquire: dst=%s sproto %d", dstbuf, msg->sadb_msg_satype)); break; case AF_INET6: if (inet_ntop(AF_INET6, &((struct sockaddr_in6 *) dstaddr)->sin6_addr, dstbuf, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: inet_ntop failed"); goto fail; } LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_acquire: dst=%s sproto %d", dstbuf, msg->sadb_msg_satype)); break; } if (src) { srcaddr = (struct sockaddr *) (src + 1); switch (srcaddr->sa_family) { case AF_INET: if (inet_ntop(AF_INET, &((struct sockaddr_in *) srcaddr)->sin_addr, srcbuf, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: " "inet_ntop failed"); goto fail; } break; case AF_INET6: if (inet_ntop(AF_INET6, &((struct sockaddr_in6 *)srcaddr)->sin6_addr, srcbuf, ADDRESS_MAX) == NULL) { log_print("pf_key_v2_acquire: " "inet_ntop failed"); goto fail; } break; default: /* * The kernel will pass an all '0' EXT_ADDRESS_SRC if * it wasn't specified for the flow. In that case, do * NOT specify the srcaddr in the Peer-name below */ srcbuf[0] = 0; srcaddr = NULL; break; } } /* Insert source ID. */ if (srcident) { slen = (srcident->sadb_ident_len * sizeof(u_int64_t)) - sizeof(struct sadb_ident); if (((unsigned char *) (srcident + 1))[slen - 1] != '\0') { log_print("pf_key_v2_acquire: " "source identity not NUL-terminated"); goto fail; } /* Check for valid type. */ switch (srcident->sadb_ident_type) { #if defined (SADB_X_IDENTTYPE_CONNECTION) case SADB_X_IDENTTYPE_CONNECTION: /* XXX */ break; #endif case SADB_IDENTTYPE_PREFIX: /* Determine what the address family is. */ srcid = memchr(srcident + 1, ':', slen); if (srcid) afamily = AF_INET6; else afamily = AF_INET; srcid = memchr(srcident + 1, '/', slen); if (!srcid) { log_print("pf_key_v2_acquire: " "badly formatted PREFIX identity"); goto fail; } masklen = atoi(srcid + 1); /* XXX We only support host addresses. */ if ((afamily == AF_INET6 && masklen != 128) || (afamily == AF_INET && masklen != 32)) { log_print("pf_key_v2_acquire: " "non-host address specified in source " "identity (mask length %d), ignoring " "request", masklen); goto fail; } /* * NUL-terminate the PREFIX string at the separator, * then dup. */ *srcid = '\0'; slen = strlen((char *) (srcident + 1)) + sizeof "ID:Address/"; srcid = malloc(slen); if (!srcid) { log_error("pf_key_v2_acquire: " "malloc (%d) failed", slen); goto fail; } snprintf(srcid, slen, "ID:Address/%s", (char *) (srcident + 1)); /* Set the section if it doesn't already exist. */ af = conf_begin(); if (!conf_get_str(srcid, "ID-type")) { if (conf_set(af, srcid, "ID-type", afamily == AF_INET ? "IPV4_ADDR" : "IPV6_ADDR", 1, 0) || conf_set(af, srcid, "Refcount", "1", 1, 0) || conf_set(af, srcid, "Address", (char *) (srcident + 1), 1, 0)) { conf_end(af, 0); goto fail; } } else pf_key_v2_conf_refinc(af, srcid); conf_end(af, 1); break; case SADB_IDENTTYPE_FQDN: prefstring = "FQDN"; /* Fall through */ case SADB_IDENTTYPE_USERFQDN: if (!prefstring) { prefstring = "USER_FQDN"; /* * Check whether there is a string following * the header; if no, that there is a user ID * (and acquire the login name). If there is * both a string and a user ID, check that * they match. */ if ((slen == 0) && (srcident->sadb_ident_id == 0)) { log_print("pf_key_v2_acquire: " "no user FQDN or ID provided"); goto fail; } if (srcident->sadb_ident_id) { pwd = getpwuid(srcident->sadb_ident_id); if (!pwd) { log_error("pf_key_v2_acquire: " "could not acquire " "username from provided " "ID %llu", srcident->sadb_ident_id); goto fail; } if (slen != 0) if (strcmp(pwd->pw_name, (char *) (srcident + 1)) != 0) { log_print("pf_key_v2_acquire: " "provided user " "name and ID do " "not match (%s != " "%s)", (char *) (srcident + 1), pwd->pw_name); /* * String has * precedence, per * RFC 2367. */ } } } buflen = (slen ? slen : strlen(pwd->pw_name)) + strlen(prefstring) + sizeof "ID:/"; srcid = malloc(buflen); if (!srcid) { log_error("pf_key_v2_acquire: " "malloc (%d) failed", buflen); goto fail; } snprintf(srcid, buflen, "ID:%s/", prefstring); if (slen != 0) strlcat(srcid, (char *) (srcident + 1), buflen); else strlcat(srcid, pwd->pw_name, buflen); pwd = 0; /* Set the section if it doesn't already exist. */ af = conf_begin(); if (!conf_get_str(srcid, "ID-type")) { if (conf_set(af, srcid, "ID-type", prefstring, 1, 0) || conf_set(af, srcid, "Refcount", "1", 1, 0) || conf_set(af, srcid, "Name", srcid + sizeof "ID:/" - 1 + strlen(prefstring), 1, 0)) { conf_end(af, 0); goto fail; } } else pf_key_v2_conf_refinc(af, srcid); conf_end(af, 1); break; default: LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_acquire: invalid source ID type %d", srcident->sadb_ident_type)); goto fail; } LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_acquire: constructed source ID \"%s\"", srcid)); prefstring = 0; } /* Insert destination ID. */ if (dstident) { slen = (dstident->sadb_ident_len * sizeof(u_int64_t)) - sizeof(struct sadb_ident); /* Check for valid type. */ switch (dstident->sadb_ident_type) { #if defined (SADB_X_IDENTTYPE_CONNECTION) case SADB_X_IDENTTYPE_CONNECTION: /* XXX */ break; #endif case SADB_IDENTTYPE_PREFIX: /* Determine what the address family is. */ dstid = memchr(dstident + 1, ':', slen); if (dstid) afamily = AF_INET6; else afamily = AF_INET; dstid = memchr(dstident + 1, '/', slen); if (!dstid) { log_print("pf_key_v2_acquire: " "badly formatted PREFIX identity"); goto fail; } masklen = atoi(dstid + 1); /* XXX We only support host addresses. */ if ((afamily == AF_INET6 && masklen != 128) || (afamily == AF_INET && masklen != 32)) { log_print("pf_key_v2_acquire: " "non-host address specified in " "destination identity (mask length %d), " "ignoring request", masklen); goto fail; } /* * NUL-terminate the PREFIX string at the separator, * then dup. */ *dstid = '\0'; slen = strlen((char *) (dstident + 1)) + sizeof "ID:Address/"; dstid = malloc(slen); if (!dstid) { log_error("pf_key_v2_acquire: " "malloc (%d) failed", slen); goto fail; } snprintf(dstid, slen, "ID:Address/%s", (char *) (dstident + 1)); /* Set the section if it doesn't already exist. */ af = conf_begin(); if (!conf_get_str(dstid, "ID-type")) { if (conf_set(af, dstid, "ID-type", afamily == AF_INET ? "IPV4_ADDR" : "IPV6_ADDR", 1, 0) || conf_set(af, dstid, "Refcount", "1", 1, 0) || conf_set(af, dstid, "Address", (char *) (dstident + 1), 1, 0)) { conf_end(af, 0); goto fail; } } else pf_key_v2_conf_refinc(af, dstid); conf_end(af, 1); break; case SADB_IDENTTYPE_FQDN: prefstring = "FQDN"; /* Fall through */ case SADB_IDENTTYPE_USERFQDN: if (!prefstring) { prefstring = "USER_FQDN"; /* * Check whether there is a string following * the header; if no, that there is a user ID * (and acquire the login name). If there is * both a string and a user ID, check that * they match. */ if (slen == 0 && dstident->sadb_ident_id == 0) { log_print("pf_key_v2_acquire: " "no user FQDN or ID provided"); goto fail; } if (dstident->sadb_ident_id) { pwd = getpwuid(dstident->sadb_ident_id); if (!pwd) { log_error("pf_key_v2_acquire: " "could not acquire " "username from provided " "ID %llu", dstident->sadb_ident_id); goto fail; } if (slen != 0) if (strcmp(pwd->pw_name, (char *) (dstident + 1)) != 0) { log_print("pf_key_v2_acquire: " "provided user " "name and ID do " "not match (%s != " "%s)", (char *) (dstident + 1), pwd->pw_name); /* * String has * precedence, per RF * 2367. */ } } } buflen = (slen ? slen : strlen(pwd->pw_name)) + strlen(prefstring) + sizeof "ID:/"; dstid = malloc(buflen); if (!dstid) { log_error("pf_key_v2_acquire: " "malloc (%d) failed", buflen); goto fail; } snprintf(dstid, buflen, "ID:%s/", prefstring); if (slen != 0) strlcat(dstid, (char *) (dstident + 1), buflen); else strlcat(dstid, pwd->pw_name, buflen); pwd = 0; /* Set the section if it doesn't already exist. */ af = conf_begin(); if (!conf_get_str(dstid, "ID-type")) { if (conf_set(af, dstid, "ID-type", prefstring, 1, 0) || conf_set(af, dstid, "Refcount", "1", 1, 0) || conf_set(af, dstid, "Name", dstid + sizeof "ID:/" - 1 + strlen(prefstring), 1, 0)) { conf_end(af, 0); goto fail; } } else pf_key_v2_conf_refinc(af, dstid); conf_end(af, 1); break; default: LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_acquire: " "invalid destination ID type %d", dstident->sadb_ident_type)); goto fail; } LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_acquire: constructed destination ID \"%s\"", dstid)); } /* Now we've placed the necessary IDs in the configuration space. */ /* Get a new connection sequence number. */ for (;; connection_seq++) { snprintf(conn, connlen, "Connection-%u", connection_seq); snprintf(configname, sizeof configname, "Config-Phase2-%u", connection_seq); /* Does it exist ? */ if (!conf_get_str(conn, "Phase") && !conf_get_str(configname, "Suites")) break; } /* * Set the IPsec connection entry. In particular, the following fields: * - Phase * - ISAKMP-peer * - Local-ID/Remote-ID (if provided) * - Acquire-ID (sequence number of kernel message, e.g., PF_KEYv2) * - Configuration * * Also set the following section: * [Peer-dstaddr(/srcaddr)(-srcid)(/dstid)] * with these fields: * - Phase * - ID (if provided) * - Remote-ID (if provided) * - Local-address (if provided) * - Address * - Configuration (if an entry ISAKMP-configuration-dstaddr(/srcaddr) * exists -- otherwise use the defaults) */ slen = strlen(dstbuf) + strlen(srcbuf) + (srcid ? strlen(srcid) : 0) + (dstid ? strlen(dstid) : 0) + sizeof "Peer-/-/"; peer = malloc(slen); if (!peer) goto fail; /* * The various cases: * - Peer-dstaddr * - Peer-dstaddr/srcaddr * - Peer-dstaddr/srcaddr-srcid * - Peer-dstaddr/srcaddr-srcid/dstid * - Peer-dstaddr/srcaddr-/dstid * - Peer-dstaddr-srcid/dstid * - Peer-dstaddr-/dstid * - Peer-dstaddr-srcid */ snprintf(peer, slen, "Peer-%s%s%s%s%s%s%s", dstbuf, srcaddr ? "/" : "", srcaddr ? srcbuf : "", srcid ? "-" : "", srcid ? srcid : "", dstid ? (srcid ? "/" : "-/") : "", dstid ? dstid : ""); /* * Set the IPsec connection section. Refcount is set to 2, because * it will be linked both to the incoming and the outgoing SA. */ af = conf_begin(); if (conf_set(af, conn, "Phase", "2", 0, 0) || conf_set(af, conn, "Flags", "__ondemand", 0, 0) || conf_set(af, conn, "Refcount", "2", 0, 0) || conf_set(af, conn, "ISAKMP-peer", peer, 0, 0)) { conf_end(af, 0); goto fail; } /* Set the sequence number. */ snprintf(lname, sizeof lname, "%u", msg->sadb_msg_seq); if (conf_set(af, conn, "Acquire-ID", lname, 0, 0)) { conf_end(af, 0); goto fail; } /* Set Phase 2 IDs -- this is the Local-ID section. */ snprintf(lname, sizeof lname, "Phase2-ID:%s/%s/%u/%u", ssflow, ssmask, tproto, sport); if (conf_set(af, conn, "Local-ID", lname, 0, 0)) { conf_end(af, 0); goto fail; } if (!conf_get_str(lname, "ID-type")) { if (conf_set(af, lname, "Refcount", "1", 0, 0)) { conf_end(af, 0); goto fail; } if (shostflag) { if (conf_set(af, lname, "ID-type", sidtype, 0, 0) || conf_set(af, lname, "Address", ssflow, 0, 0)) { conf_end(af, 0); goto fail; } } else { if (conf_set(af, lname, "ID-type", sidtype, 0, 0) || conf_set(af, lname, "Network", ssflow, 0, 0) || conf_set(af, lname, "Netmask", ssmask, 0, 0)) { conf_end(af, 0); goto fail; } } if (tproto) { snprintf(tmbuf, sizeof sport * 3 + 1, "%u", tproto); if (conf_set(af, lname, "Protocol", tmbuf, 0, 0)) { conf_end(af, 0); goto fail; } if (sport) { snprintf(tmbuf, sizeof sport * 3 + 1, "%u", ntohs(sport)); if (conf_set(af, lname, "Port", tmbuf, 0, 0)) { conf_end(af, 0); goto fail; } } } } else pf_key_v2_conf_refinc(af, lname); /* Set Remote-ID section. */ snprintf(dname, sizeof dname, "Phase2-ID:%s/%s/%u/%u", sdflow, sdmask, tproto, dport); if (conf_set(af, conn, "Remote-ID", dname, 0, 0)) { conf_end(af, 0); goto fail; } if (!conf_get_str(dname, "ID-type")) { if (conf_set(af, dname, "Refcount", "1", 0, 0)) { conf_end(af, 0); goto fail; } if (dhostflag) { if (conf_set(af, dname, "ID-type", didtype, 0, 0) || conf_set(af, dname, "Address", sdflow, 0, 0)) { conf_end(af, 0); goto fail; } } else { if (conf_set(af, dname, "ID-type", didtype, 0, 0) || conf_set(af, dname, "Network", sdflow, 0, 0) || conf_set(af, dname, "Netmask", sdmask, 0, 0)) { conf_end(af, 0); goto fail; } } if (tproto) { snprintf(tmbuf, sizeof dport * 3 + 1, "%u", tproto); if (conf_set(af, dname, "Protocol", tmbuf, 0, 0)) { conf_end(af, 0); goto fail; } if (dport) { snprintf(tmbuf, sizeof dport * 3 + 1, "%u", ntohs(dport)); if (conf_set(af, dname, "Port", tmbuf, 0, 0)) { conf_end(af, 0); goto fail; } } } } else pf_key_v2_conf_refinc(af, dname); /* * XXX * We should be using information from the proposal to set this up. * At least, we should make this selectable. */ /* Phase 2 configuration. */ if (conf_set(af, conn, "Configuration", configname, 0, 0)) { conf_end(af, 0); goto fail; } if (conf_set(af, configname, "Exchange_type", "Quick_mode", 0, 0) || conf_set(af, configname, "DOI", "IPSEC", 0, 0)) { conf_end(af, 0); goto fail; } if (conf_get_str("General", "Default-phase-2-suites")) { if (conf_set(af, configname, "Suites", conf_get_str("General", "Default-phase-2-suites"), 0, 0)) { conf_end(af, 0); goto fail; } } else { if (conf_set(af, configname, "Suites", "QM-ESP-3DES-SHA-PFS-SUITE", 0, 0)) { conf_end(af, 0); goto fail; } } /* Set the ISAKMP-peer section. */ if (!conf_get_str(peer, "Phase")) { if (conf_set(af, peer, "Phase", "1", 0, 0) || conf_set(af, peer, "Refcount", "1", 0, 0) || conf_set(af, peer, "Address", dstbuf, 0, 0)) { conf_end(af, 0); goto fail; } if (srcaddr && conf_set(af, peer, "Local-address", srcbuf, 0, 0)) { conf_end(af, 0); goto fail; } snprintf(confname, sizeof confname, "ISAKMP-Configuration-%s", peer); if (conf_set(af, peer, "Configuration", confname, 0, 0)) { conf_end(af, 0); goto fail; } #if defined (SADB_X_CREDTYPE_NONE) /* Store any credentials passed to us. */ if (cred) { struct cert_handler *handler = 0; void *cert; char num[12], *certprint; /* Convert to bytes in-place. */ cred->sadb_x_cred_len *= PF_KEY_V2_CHUNK; if (cred->sadb_x_cred_len <= sizeof *cred) { log_print("pf_key_v2_acquire: " "zero-length credentials, aborting SA " "acquisition"); conf_end(af, 0); goto fail; } switch (cred->sadb_x_cred_type) { case SADB_X_CREDTYPE_X509: snprintf(num, sizeof num, "%d", ISAKMP_CERTENC_X509_SIG); handler = cert_get(ISAKMP_CERTENC_X509_SIG); break; case SADB_X_CREDTYPE_KEYNOTE: snprintf(num, sizeof num, "%d", ISAKMP_CERTENC_KEYNOTE); handler = cert_get(ISAKMP_CERTENC_KEYNOTE); break; default: log_print("pf_key_v2_acquire: " "unknown credential type %d", cred->sadb_x_cred_type); conf_end(af, 0); goto fail; } if (!handler) { log_print("pf_key_v2_acquire: " "cert_get (%s) failed", num); conf_end(af, 0); goto fail; } /* Set the credential type as a number. */ if (conf_set(af, peer, "Credential_type", num, 0, 0)) { conf_end(af, 0); goto fail; } /* Get the certificate. */ cert = handler->cert_get((u_int8_t *) (cred + 1), cred->sadb_x_cred_len - sizeof *cred); /* Now convert to printable format. */ certprint = handler->cert_printable(cert); handler->cert_free(cert); if (!certprint || conf_set(af, peer, "Credentials", certprint, 0, 0)) { if (certprint) free(certprint); conf_end(af, 0); goto fail; } free(certprint); } #endif /* SADB_X_CREDTYPE_NONE */ /* Phase 1 configuration. */ if (!conf_get_str(confname, "exchange_type")) { #if defined (SADB_X_EXT_LOCAL_AUTH) /* * We may have been provided with authentication * material. */ if (sauth) { char *authm; /* Convert to bytes in-place. */ sauth->sadb_x_cred_len *= PF_KEY_V2_CHUNK; switch (sauth->sadb_x_cred_type) { case SADB_X_AUTHTYPE_PASSPHRASE: if (conf_set(af, confname, "Transforms", "3DES-SHA", 0, 0)) { conf_end(af, 0); goto fail; } if (sauth->sadb_x_cred_len <= sizeof *sauth) { log_print("pf_key_v2_acquire: " "zero-length passphrase, " "aborting SA acquisition"); conf_end(af, 0); goto fail; } authm = malloc(sauth->sadb_x_cred_len - sizeof *sauth + 1); if (!authm) { log_error("pf_key_v2_acquire: " "malloc (%lu) failed", sauth->sadb_x_cred_len - (unsigned long) sizeof *sauth + 1); conf_end(af, 0); goto fail; } memcpy(authm, sauth + 1, sauth->sadb_x_cred_len - sizeof *sauth + 1); /* Set the passphrase in the peer. */ if (conf_set(af, peer, "Authentication", authm, 0, 0)) { free(authm); conf_end(af, 0); goto fail; } free(authm); break; case SADB_X_AUTHTYPE_RSA: if (conf_set(af, confname, "Transforms", "3DES-SHA-RSA_SIG", 0, 0)) { conf_end(af, 0); goto fail; } if (sauth->sadb_x_cred_len <= sizeof *sauth) { log_print("pf_key_v2_acquire: " "zero-length RSA key, " "aborting SA acquisition"); conf_end(af, 0); goto fail; } authm = key_printable(ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, (u_int8_t *) sauth + 1, sauth->sadb_x_cred_len - sizeof *sauth); if (!authm) { log_print("pf_key_v2_acquire: " "failed to convert " "private key to printable " "format (size %lu)", sauth->sadb_x_cred_len - (unsigned long) sizeof *sauth); conf_end(af, 0); goto fail; } /* * Set the key in the peer. We don't * use "Authentication" to avoid * potential conflicts with file-based * configurations that use public key * authentication but still specify * an "Authentication" tag (typically * as a remnant of passphrase-based * testing). */ if (conf_set(af, peer, "PKAuthentication", authm, 0, 0)) { free(authm); conf_end(af, 0); goto fail; } free(authm); break; default: log_print("pf_key_v2_acquire: " "unknown authentication " "material type %d received from " "kernel", sauth->sadb_x_cred_type); conf_end(af, 0); goto fail; } } else /* Fall through */ #endif /* SADB_X_EXT_LOCAL_AUTH */ { xform = conf_get_str( "Default-phase-1-configuration", "Transforms"); if (conf_set(af, confname, "Transforms", xform ? xform : "3DES-SHA-RSA_SIG", 0, 0)) { conf_end(af, 0); goto fail; } } if (conf_set(af, confname, "Exchange_Type", "ID_PROT", 0, 0) || conf_set(af, confname, "DOI", "IPSEC", 0, 0) || conf_set(af, confname, "Refcount", "1", 0, 0)) { conf_end(af, 0); goto fail; } } else pf_key_v2_conf_refinc(af, confname); /* The ID we should use in Phase 1. */ if (srcid && conf_set(af, peer, "ID", srcid, 0, 0)) { conf_end(af, 0); goto fail; } /* The ID the other side should use in Phase 1. */ if (dstid && conf_set(af, peer, "Remote-ID", dstid, 0, 0)) { conf_end(af, 0); goto fail; } } else pf_key_v2_conf_refinc(af, peer); /* All done. */ conf_end(af, 1); /* Let's rock 'n roll. */ pf_key_v2_connection_check(conn); conn = 0; /* Fall-through to cleanup. */ fail: if (ret) pf_key_v2_msg_free(ret); if (askpolicy) pf_key_v2_msg_free(askpolicy); if (srcid) free(srcid); if (dstid) free(dstid); if (peer) free(peer); if (conn) free(conn); return; #else /* acquire not supported */ return; #endif /* SADB_X_ASKPOLICY */ } static void pf_key_v2_notify(struct pf_key_v2_msg *msg) { switch (((struct sadb_msg *)TAILQ_FIRST(msg)->seg)->sadb_msg_type) { case SADB_EXPIRE: pf_key_v2_expire(msg); break; case SADB_ACQUIRE: pf_key_v2_acquire(msg); break; default: log_print("pf_key_v2_notify: unexpected message type (%d)", ((struct sadb_msg *)TAILQ_FIRST(msg)->seg)->sadb_msg_type); } pf_key_v2_msg_free(msg); } void pf_key_v2_handler(int fd) { struct pf_key_v2_msg *msg; #if !defined (LINUX_IPSEC) int n; /* * As synchronous read/writes to the socket can have taken place * between the select(2) call of the main loop and this handler, we * need to recheck the readability. */ if (ioctl(pf_key_v2_socket, FIONREAD, &n) == -1) { log_error("pf_key_v2_handler: ioctl (%d, FIONREAD, &n) failed", pf_key_v2_socket); return; } if (!n) return; #endif /* LINUX_IPSEC */ msg = pf_key_v2_read(0); if (msg) pf_key_v2_notify(msg); } /* * Group 2 IPsec SAs given by the PROTO1 and PROTO2 protocols of the SA IKE * security association in a chain. * XXX Assumes OpenBSD GRPSPIS extension. Should probably be moved to sysdep.c */ int pf_key_v2_group_spis(struct sa *sa, struct proto *proto1, struct proto *proto2, int incoming) { #if defined (SADB_X_GRPSPIS) struct sadb_msg msg; struct sadb_sa sa1, sa2; struct sadb_address *addr = 0; struct sadb_protocol protocol; struct pf_key_v2_msg *grpspis = 0, *ret = 0; struct sockaddr *saddr; int err; size_t len; #ifdef KAME struct sadb_x_sa2 kamesa2; #endif msg.sadb_msg_type = SADB_X_GRPSPIS; switch (proto1->proto) { case IPSEC_PROTO_IPSEC_ESP: msg.sadb_msg_satype = SADB_SATYPE_ESP; break; case IPSEC_PROTO_IPSEC_AH: msg.sadb_msg_satype = SADB_SATYPE_AH; break; #if defined (SADB_X_SATYPE_IPCOMP) case IPSEC_PROTO_IPCOMP: msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP; break; #endif default: log_print("pf_key_v2_group_spis: invalid proto %d", proto1->proto); goto cleanup; } msg.sadb_msg_seq = 0; grpspis = pf_key_v2_msg_new(&msg, 0); if (!grpspis) goto cleanup; /* Setup the SA extensions. */ sa1.sadb_sa_exttype = SADB_EXT_SA; sa1.sadb_sa_len = sizeof sa1 / PF_KEY_V2_CHUNK; memcpy(&sa1.sadb_sa_spi, proto1->spi[incoming], sizeof sa1.sadb_sa_spi); sa1.sadb_sa_replay = 0; sa1.sadb_sa_state = 0; sa1.sadb_sa_auth = 0; sa1.sadb_sa_encrypt = 0; sa1.sadb_sa_flags = 0; if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&sa1, 0) == -1) goto cleanup; #ifndef KAME sa2.sadb_sa_exttype = SADB_X_EXT_SA2; sa2.sadb_sa_len = sizeof sa2 / PF_KEY_V2_CHUNK; memcpy(&sa2.sadb_sa_spi, proto2->spi[incoming], sizeof sa2.sadb_sa_spi); sa2.sadb_sa_replay = 0; sa2.sadb_sa_state = 0; sa2.sadb_sa_auth = 0; sa2.sadb_sa_encrypt = 0; sa2.sadb_sa_flags = 0; if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&sa2, 0) == -1) goto cleanup; #else memset(&kamesa2, 0, sizeof kamesa2); kamesa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; kamesa2.sadb_x_sa2_len = sizeof kamesa2 / PF_KEY_V2_CHUNK; kamesa2.sadb_x_sa2_mode = 0; if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&kamesa2, 0) == -1) goto cleanup; #endif /* * Setup the ADDRESS extensions. */ if (incoming) sa->transport->vtbl->get_src(sa->transport, &saddr); else sa->transport->vtbl->get_dst(sa->transport, &saddr); len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr)); addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifndef __OpenBSD__ addr->sadb_address_proto = 0; addr->sadb_address_prefixlen = 0; #endif addr->sadb_address_reserved = 0; memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); ((struct sockaddr_in *) (addr + 1))->sin_port = 0; if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; addr = calloc(1, len); if (!addr) goto cleanup; addr->sadb_address_exttype = SADB_X_EXT_DST2; addr->sadb_address_len = len / PF_KEY_V2_CHUNK; #ifndef __OpenBSD__ addr->sadb_address_proto = 0; addr->sadb_address_prefixlen = 0; #endif addr->sadb_address_reserved = 0; memcpy(addr + 1, saddr, sysdep_sa_len(saddr)); ((struct sockaddr_in *) (addr + 1))->sin_port = 0; if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *) addr, PF_KEY_V2_NODE_MALLOCED) == -1) goto cleanup; addr = 0; /* Setup the PROTOCOL extension. */ protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; protocol.sadb_protocol_len = sizeof protocol / PF_KEY_V2_CHUNK; switch (proto2->proto) { case IPSEC_PROTO_IPSEC_ESP: protocol.sadb_protocol_proto = SADB_SATYPE_ESP; break; case IPSEC_PROTO_IPSEC_AH: protocol.sadb_protocol_proto = SADB_SATYPE_AH; break; #if defined (SADB_X_SATYPE_IPCOMP) case IPSEC_PROTO_IPCOMP: protocol.sadb_protocol_proto = SADB_X_SATYPE_IPCOMP; break; #endif default: log_print("pf_key_v2_group_spis: invalid proto %d", proto2->proto); goto cleanup; } protocol.sadb_protocol_reserved2 = 0; if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&protocol, 0) == -1) goto cleanup; ret = pf_key_v2_call(grpspis); pf_key_v2_msg_free(grpspis); grpspis = 0; if (!ret) goto cleanup; err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno; if (err) { log_print("pf_key_v2_group_spis: GRPSPIS: %s", strerror(err)); goto cleanup; } pf_key_v2_msg_free(ret); LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_group_spis: done")); return 0; cleanup: if (addr) free(addr); if (grpspis) pf_key_v2_msg_free(grpspis); if (ret) pf_key_v2_msg_free(ret); return -1; #else /* SADB_X_GRPSPIS */ log_print("pf_key_v2_group_spis: not supported in pure PF_KEYv2"); return -1; #endif } isakmpd-20041012.orig/math_group.c0000644000175000017500000006174710133045740017105 0ustar jdivejdive00000000000000/* $OpenBSD: math_group.c,v 1.23 2004/06/14 09:55:41 ho Exp $ */ /* $EOM: math_group.c,v 1.25 2000/04/07 19:53:26 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 1999, 2000 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include "sysdep.h" #include "gmp_util.h" #include "log.h" #include "math_2n.h" #include "math_ec2n.h" #include "math_group.h" #include "math_mp.h" /* We do not want to export these definitions. */ int modp_getlen(struct group *); void modp_getraw(struct group *, math_mp_t, u_int8_t *); int modp_setraw(struct group *, math_mp_t, u_int8_t *, int); int modp_setrandom(struct group *, math_mp_t); int modp_operation(struct group *, math_mp_t, math_mp_t, math_mp_t); int ec2n_getlen(struct group *); void ec2n_getraw(struct group *, ec2np_ptr, u_int8_t *); int ec2n_setraw(struct group *, ec2np_ptr, u_int8_t *, int); int ec2n_setrandom(struct group *, ec2np_ptr); int ec2n_operation(struct group *, ec2np_ptr, ec2np_ptr, ec2np_ptr); struct ec2n_group { ec2np_t gen; /* Generator */ ec2ng_t grp; ec2np_t a, b, c, d; }; struct modp_group { math_mp_t gen; /* Generator */ math_mp_t p; /* Prime */ math_mp_t a, b, c, d; }; /* * This module provides access to the operations on the specified group * and is absolutly free of any cryptographic devices. This is math :-). */ #define OAKLEY_GRP_1 1 #define OAKLEY_GRP_2 2 #define OAKLEY_GRP_3 3 #define OAKLEY_GRP_4 4 #define OAKLEY_GRP_5 5 #define OAKLEY_GRP_6 6 #define OAKLEY_GRP_7 7 #define OAKLEY_GRP_8 8 #define OAKLEY_GRP_9 9 #define OAKLEY_GRP_10 10 #define OAKLEY_GRP_11 11 #define OAKLEY_GRP_12 12 #define OAKLEY_GRP_13 13 #define OAKLEY_GRP_14 14 #define OAKLEY_GRP_15 15 #define OAKLEY_GRP_16 16 #define OAKLEY_GRP_17 17 #define OAKLEY_GRP_18 18 /* Describe preconfigured MODP groups */ /* * The Generalized Number Field Sieve has an asymptotic running time * of: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))), where q is the * group order, e.g. q = 2**768. */ struct modp_dscr oakley_modp[] = { {OAKLEY_GRP_1, 72, /* This group is insecure, only sufficient * for DES */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", "0x02" }, {OAKLEY_GRP_2, 82, /* This group is a bit better */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" "FFFFFFFFFFFFFFFF", "0x02" }, {OAKLEY_GRP_5, 102, "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", "0x02" }, {OAKLEY_GRP_14, 135, /* 2048 bit */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" "15728E5A8AACAA68FFFFFFFFFFFFFFFF", "0x02" }, {OAKLEY_GRP_15, 170, /* 3072 bit */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", "0x02" }, {OAKLEY_GRP_16, 195, /* 4096 bit */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" "FFFFFFFFFFFFFFFF", "0x02" }, {OAKLEY_GRP_17, 220, /* 6144 bit */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", "0x02" }, {OAKLEY_GRP_18, 250, /* 8192 bit */ "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" "83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", "0x02" }, }; #ifdef USE_EC /* Describe preconfigured EC2N groups */ /* * Related collision-search methods can compute discrete logarithmns * in O(sqrt(r)), r being the subgroup order. */ struct ec2n_dscr oakley_ec2n[] = { { OAKLEY_GRP_3, 76, /* This group is also considered insecure * (P1363) */ "0x0800000000000000000000004000000000000001", "0x7b", "0x00", "0x7338f" }, { OAKLEY_GRP_4, 91, "0x020000000000000000000000000000200000000000000001", "0x18", "0x00", "0x1ee9" }, }; #endif /* USE_EC */ /* XXX I want to get rid of the casting here. */ struct group groups[] = { { MODP, OAKLEY_GRP_1, 0, &oakley_modp[0], 0, 0, 0, 0, 0, (int (*) (struct group *)) modp_getlen, (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, (int (*) (struct group *, void *)) modp_setrandom, (int (*) (struct group *, void *, void *, void *)) modp_operation }, { MODP, OAKLEY_GRP_2, 0, &oakley_modp[1], 0, 0, 0, 0, 0, (int (*) (struct group *)) modp_getlen, (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, (int (*) (struct group *, void *)) modp_setrandom, (int (*) (struct group *, void *, void *, void *)) modp_operation }, #ifdef USE_EC { EC2N, OAKLEY_GRP_3, 0, &oakley_ec2n[0], 0, 0, 0, 0, 0, (int (*) (struct group *)) ec2n_getlen, (void (*) (struct group *, void *, u_int8_t *)) ec2n_getraw, (int (*) (struct group *, void *, u_int8_t *, int)) ec2n_setraw, (int (*) (struct group *, void *)) ec2n_setrandom, (int (*) (struct group *, void *, void *, void *)) ec2n_operation }, { EC2N, OAKLEY_GRP_4, 0, &oakley_ec2n[1], 0, 0, 0, 0, 0, (int (*) (struct group *)) ec2n_getlen, (void (*) (struct group *, void *, u_int8_t *)) ec2n_getraw, (int (*) (struct group *, void *, u_int8_t *, int)) ec2n_setraw, (int (*) (struct group *, void *)) ec2n_setrandom, (int (*) (struct group *, void *, void *, void *)) ec2n_operation }, #endif /* USE_EC */ { MODP, OAKLEY_GRP_5, 0, &oakley_modp[2], 0, 0, 0, 0, 0, (int (*) (struct group *)) modp_getlen, (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, (int (*) (struct group *, void *)) modp_setrandom, (int (*) (struct group *, void *, void *, void *)) modp_operation }, #ifdef USE_EC /* XXX Higher EC2N group go here... */ #endif /* USE_EC */ /* XXX group 6 to 13 are not yet defined (draft-ike-ecc) */ { NOTYET, OAKLEY_GRP_6, 0, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, { NOTYET, OAKLEY_GRP_7, 0, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, { NOTYET, OAKLEY_GRP_8, 0, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, { NOTYET, OAKLEY_GRP_9, 0, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, { NOTYET, OAKLEY_GRP_10, 0, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, { NOTYET, OAKLEY_GRP_11, 0, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, { NOTYET, OAKLEY_GRP_12, 0, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, { NOTYET, OAKLEY_GRP_13, 0, NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, { MODP, OAKLEY_GRP_14, 0, &oakley_modp[3], 0, 0, 0, 0, 0, (int (*) (struct group *)) modp_getlen, (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, (int (*) (struct group *, void *)) modp_setrandom, (int (*) (struct group *, void *, void *, void *)) modp_operation }, { MODP, OAKLEY_GRP_15, 0, &oakley_modp[4], 0, 0, 0, 0, 0, (int (*) (struct group *)) modp_getlen, (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, (int (*) (struct group *, void *)) modp_setrandom, (int (*) (struct group *, void *, void *, void *)) modp_operation }, { MODP, OAKLEY_GRP_16, 0, &oakley_modp[5], 0, 0, 0, 0, 0, (int (*) (struct group *)) modp_getlen, (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, (int (*) (struct group *, void *)) modp_setrandom, (int (*) (struct group *, void *, void *, void *)) modp_operation }, { MODP, OAKLEY_GRP_17, 0, &oakley_modp[6], 0, 0, 0, 0, 0, (int (*) (struct group *)) modp_getlen, (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, (int (*) (struct group *, void *)) modp_setrandom, (int (*) (struct group *, void *, void *, void *)) modp_operation }, { MODP, OAKLEY_GRP_18, 0, &oakley_modp[7], 0, 0, 0, 0, 0, (int (*) (struct group *)) modp_getlen, (void (*) (struct group *, void *, u_int8_t *)) modp_getraw, (int (*) (struct group *, void *, u_int8_t *, int)) modp_setraw, (int (*) (struct group *, void *)) modp_setrandom, (int (*) (struct group *, void *, void *, void *)) modp_operation }, }; /* * Initialize the group structure for later use, * this is done by converting the values given in the describtion * and converting them to their native representation. */ void group_init(void) { int i; for (i = sizeof(groups) / sizeof(groups[0]) - 1; i >= 0; i--) switch (groups[i].type) { #ifdef USE_EC case EC2N: /* Initialize an Elliptic Curve over GF(2**n) */ ec2n_init(&groups[i]); break; #endif case MODP: /* Initialize an over GF(p) */ modp_init(&groups[i]); break; case NOTYET: /* Not yet assigned, drop silently */ break; default: log_print("Unknown group type %d at index %d in " "group_init().", groups[i].type, i); break; } } struct group * group_get(u_int32_t id) { struct group *new, *clone; if (id < 1 || id > (sizeof(groups) / sizeof(groups[0]))) { log_print("group_get: group ID (%u) out of range", id); return 0; } clone = &groups[id - 1]; new = malloc(sizeof *new); if (!new) { log_error("group_get: malloc (%lu) failed", (unsigned long)sizeof *new); return 0; } switch (clone->type) { #ifdef USE_EC case EC2N: new = ec2n_clone(new, clone); break; #endif case MODP: new = modp_clone(new, clone); break; default: log_print("group_get: unknown group type %d", clone->type); free(new); return 0; } LOG_DBG((LOG_MISC, 70, "group_get: returning %p of group %d", new, new->id)); return new; } void group_free(struct group *grp) { switch (grp->type) { #ifdef USE_EC case EC2N: ec2n_free(grp); break; #endif case MODP: modp_free(grp); break; default: log_print("group_free: unknown group type %d", grp->type); break; } free(grp); } struct group * modp_clone(struct group *new, struct group *clone) { struct modp_group *new_grp, *clone_grp = clone->group; new_grp = malloc(sizeof *new_grp); if (!new_grp) { log_print("modp_clone: malloc (%lu) failed", (unsigned long)sizeof *new_grp); free(new); return 0; } memcpy(new, clone, sizeof(struct group)); new->group = new_grp; #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_init_set(new_grp->p, clone_grp->p); mpz_init_set(new_grp->gen, clone_grp->gen); mpz_init(new_grp->a); mpz_init(new_grp->b); mpz_init(new_grp->c); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL new_grp->p = BN_dup(clone_grp->p); new_grp->gen = BN_dup(clone_grp->gen); new_grp->a = BN_new(); new_grp->b = BN_new(); new_grp->c = BN_new(); #endif new->gen = new_grp->gen; new->a = new_grp->a; new->b = new_grp->b; new->c = new_grp->c; return new; } void modp_free(struct group *old) { struct modp_group *grp = old->group; #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_clear(grp->p); mpz_clear(grp->gen); mpz_clear(grp->a); mpz_clear(grp->b); mpz_clear(grp->c); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL BN_clear_free(grp->p); BN_clear_free(grp->gen); BN_clear_free(grp->a); BN_clear_free(grp->b); BN_clear_free(grp->c); #endif free(grp); } void modp_init(struct group *group) { struct modp_dscr *dscr = (struct modp_dscr *)group->group; struct modp_group *grp; grp = malloc(sizeof *grp); if (!grp) log_fatal("modp_init: malloc (%lu) failed", (unsigned long)sizeof *grp); group->bits = dscr->bits; #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_init_set_str(grp->p, dscr->prime, 0); mpz_init_set_str(grp->gen, dscr->gen, 0); mpz_init(grp->a); mpz_init(grp->b); mpz_init(grp->c); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL grp->p = BN_new(); BN_hex2bn(&grp->p, dscr->prime + 2); grp->gen = BN_new(); BN_hex2bn(&grp->gen, dscr->gen + 2); grp->a = BN_new(); grp->b = BN_new(); grp->c = BN_new(); #endif group->gen = grp->gen; group->a = grp->a; group->b = grp->b; group->c = grp->c; group->group = grp; } #ifdef USE_EC struct group * ec2n_clone(struct group *new, struct group *clone) { struct ec2n_group *new_grp, *clone_grp = clone->group; new_grp = malloc(sizeof *new_grp); if (!new_grp) { log_error("ec2n_clone: malloc (%lu) failed", (unsigned long)sizeof *new_grp); free(new); return 0; } memcpy(new, clone, sizeof(struct group)); new->group = new_grp; ec2ng_init(new_grp->grp); ec2np_init(new_grp->gen); ec2np_init(new_grp->a); ec2np_init(new_grp->b); ec2np_init(new_grp->c); if (ec2ng_set(new_grp->grp, clone_grp->grp)) goto fail; if (ec2np_set(new_grp->gen, clone_grp->gen)) goto fail; new->gen = new_grp->gen; new->a = new_grp->a; new->b = new_grp->b; new->c = new_grp->c; new->d = ((ec2np_ptr) new->a)->x; return new; fail: ec2ng_clear(new_grp->grp); ec2np_clear(new_grp->gen); ec2np_clear(new_grp->a); ec2np_clear(new_grp->b); ec2np_clear(new_grp->c); free(new_grp); free(new); return 0; } void ec2n_free(struct group *old) { struct ec2n_group *grp = old->group; ec2ng_clear(grp->grp); ec2np_clear(grp->gen); ec2np_clear(grp->a); ec2np_clear(grp->b); ec2np_clear(grp->c); free(grp); } void ec2n_init(struct group *group) { struct ec2n_dscr *dscr = (struct ec2n_dscr *)group->group; struct ec2n_group *grp; grp = malloc(sizeof *grp); if (!grp) log_fatal("ec2n_init: malloc (%lu) failed", (unsigned long)sizeof *grp); group->bits = dscr->bits; ec2ng_init(grp->grp); ec2np_init(grp->gen); ec2np_init(grp->a); ec2np_init(grp->b); ec2np_init(grp->c); if (ec2ng_set_p_str(grp->grp, dscr->polynomial)) goto fail; grp->grp->p->bits = b2n_sigbit(grp->grp->p); if (ec2ng_set_a_str(grp->grp, dscr->a)) goto fail; if (ec2ng_set_b_str(grp->grp, dscr->b)) goto fail; if (ec2np_set_x_str(grp->gen, dscr->gen_x)) goto fail; if (ec2np_find_y(grp->gen, grp->grp)) goto fail; /* Sanity check */ if (!ec2np_ison(grp->gen, grp->grp)) log_fatal("ec2n_init: generator is not on curve"); group->gen = grp->gen; group->a = grp->a; group->b = grp->b; group->c = grp->c; group->d = ((ec2np_ptr) group->a)->x; group->group = grp; return; fail: log_fatal("ec2n_init: general failure"); } #endif /* USE_EC */ int modp_getlen(struct group *group) { struct modp_group *grp = (struct modp_group *)group->group; return mpz_sizeinoctets(grp->p); } void modp_getraw(struct group *grp, math_mp_t v, u_int8_t *d) { mpz_getraw(d, v, grp->getlen(grp)); } int modp_setraw(struct group *grp, math_mp_t d, u_int8_t *s, int l) { mpz_setraw(d, s, l); return 0; } int modp_setrandom(struct group *grp, math_mp_t d) { int i, l = grp->getlen(grp); u_int32_t tmp = 0; #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_set_ui(d, 0); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL BN_set_word(d, 0); #endif for (i = 0; i < l; i++) { if (i % 4) tmp = sysdep_random(); #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_mul_2exp(d, d, 8); mpz_add_ui(d, d, tmp & 0xFF); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL BN_lshift(d, d, 8); BN_add_word(d, tmp & 0xFF); #endif tmp >>= 8; } return 0; } int modp_operation(struct group *group, math_mp_t d, math_mp_t a, math_mp_t e) { struct modp_group *grp = (struct modp_group *)group->group; #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_powm(d, a, e, grp->p); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL BN_CTX *ctx = BN_CTX_new(); BN_mod_exp(d, a, e, grp->p, ctx); BN_CTX_free(ctx); #endif return 0; } #ifdef USE_EC int ec2n_getlen(struct group *group) { struct ec2n_group *grp = (struct ec2n_group *)group->group; int bits = b2n_sigbit(grp->grp->p) - 1; return (7 + bits) >> 3; } void ec2n_getraw(struct group *group, ec2np_ptr xo, u_int8_t *e) { struct ec2n_group *grp = (struct ec2n_group *) group->group; int chunks, bytes, i, j; b2n_ptr x = xo->x; CHUNK_TYPE tmp; bytes = b2n_sigbit(grp->grp->p) - 1; chunks = (CHUNK_MASK + bytes) >> CHUNK_SHIFTS; bytes = ((7 + (bytes & CHUNK_MASK)) >> 3); for (i = chunks - 1; i >= 0; i--) { tmp = (i >= x->chunks ? 0 : x->limp[i]); for (j = (i == chunks - 1 ? bytes : CHUNK_BYTES) - 1; j >= 0; j--) { e[j] = tmp & 0xff; tmp >>= 8; } e += (i == chunks - 1 ? bytes : CHUNK_BYTES); } } int ec2n_setraw(struct group *grp, ec2np_ptr out, u_int8_t *s, int l) { int len, bytes, i, j; b2n_ptr outx = out->x; CHUNK_TYPE tmp; len = (CHUNK_BYTES - 1 + l) / CHUNK_BYTES; if (b2n_resize(outx, len)) return -1; bytes = ((l - 1) % CHUNK_BYTES) + 1; for (i = len - 1; i >= 0; i--) { tmp = 0; for (j = (i == len - 1 ? bytes : CHUNK_BYTES); j > 0; j--) { tmp <<= 8; tmp |= *s++; } outx->limp[i] = tmp; } return 0; } int ec2n_setrandom(struct group *group, ec2np_ptr x) { b2n_ptr d = x->x; struct ec2n_group *grp = (struct ec2n_group *) group->group; return b2n_random(d, b2n_sigbit(grp->grp->p) - 1); } /* * This is an attempt at operation abstraction. It can happen * that we need to initialize the y variable for the operation * to proceed correctly. When this is the case operation has * to supply the variable 'a' with the chunks of the Y cooridnate * set to zero. */ int ec2n_operation(struct group *grp, ec2np_ptr d, ec2np_ptr a, ec2np_ptr e) { b2n_ptr ex = e->x; struct ec2n_group *group = (struct ec2n_group *)grp->group; if (a->y->chunks == 0) if (ec2np_find_y(a, group->grp)) return -1; return ec2np_mul(d, a, ex, group->grp); } #endif /* USE_EC */ isakmpd-20041012.orig/libcrypto.c0000644000175000017500000000361610133045740016736 0ustar jdivejdive00000000000000/* $OpenBSD: libcrypto.c,v 1.16 2004/04/15 18:39:26 deraadt Exp $ */ /* $EOM: libcrypto.c,v 1.14 2000/09/28 12:53:27 niklas Exp $ */ /* * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2000 Angelos D. Keromytis. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include "sysdep.h" #include "libcrypto.h" void libcrypto_init(void) { #if defined (USE_X509) && defined (USE_LIBCRYPTO) /* Add all algorithms known by SSL */ #if OPENSSL_VERSION_NUMBER >= 0x00905100L OpenSSL_add_all_algorithms(); #else SSLeay_add_all_algorithms(); #endif #endif /* USE_X509 && USE_LIBCRYPTO */ } isakmpd-20041012.orig/isakmp_num.cst0000644000175000017500000001455310133045740017443 0ustar jdivejdive00000000000000# $OpenBSD: isakmp_num.cst,v 1.10 2004/08/10 15:59:10 ho Exp $ # $EOM: isakmp_num.cst,v 1.3 2000/05/17 03:09:50 angelos Exp $ # # Copyright (c) 1998, 2001 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # XXX Please fill in references to the drafts, chapter & verse for each # constant group below. # Also think about ranges, can they be specified differently? Can we use # these constants for validity checks? # ISAKMP payload type. ISAKMP_PAYLOAD NONE 0 SA 1 PROPOSAL 2 TRANSFORM 3 KEY_EXCH 4 ID 5 CERT 6 CERT_REQ 7 HASH 8 SIG 9 NONCE 10 NOTIFY 11 DELETE 12 VENDOR 13 # XXX the following are not quite legitimate according to the IETF process ATTRIBUTE 14 # IKE Mode-Config attribute SAK 15 # RFC 3547, SA KEK Payload SAT 16 # RFC 3547, SA TEK Payload KD 17 # RFC 3547, Key Download SEQ 18 # RFC 3547, Sequence Number POP 19 # RFC 3547, Proof of possession RESERVED_MIN 20 RESERVED_MAX 127 PRIVATE_MIN 128 # XXX values from draft-ietf-ipsec-nat-t-ike-01,02,03. Later drafts specify # XXX NAT_D as payload 15 and NAT_OA as 16, but these are allocated by RFC # XXX 3547 as seen above. NAT_D 130 # NAT Discovery payload NAT_OA 131 # NAT Original Address payload PRIVATE_MAX 255 . # ISAKMP exchange types. ISAKMP_EXCH NONE 0 BASE 1 ID_PROT 2 AUTH_ONLY 3 AGGRESSIVE 4 INFO 5 # XXX the following are not quite legitimate according to the IETF process TRANSACTION 6 FUTURE_MIN 7 FUTURE_MAX 31 DOI_MIN 32 DOI_MAX 255 . # ISAKMP flags. ISAKMP_FLAGS ENC 1 COMMIT 2 AUTH_ONLY 4 . # ISAKMP certificate encoding. ISAKMP_CERTENC NONE 0 PKCS 1 PGP 2 DNS 3 X509_SIG 4 X509_KE 5 KERBEROS 6 CRL 7 ARL 8 SPKI 9 X509_ATTR 10 KEYNOTE 11 HASH_URL_PKIX_CERT 12 HASH_URL_PKIX_BUNDLE 13 RESERVED_MIN 14 RESERVED_MAX 255 . # ISAKMP Notify message types. ISAKMP_NOTIFY INVALID_PAYLOAD_TYPE 1 DOI_NOT_SUPPORTED 2 SITUATION_NOT_SUPPORTED 3 INVALID_COOKIE 4 INVALID_MAJOR_VERSION 5 INVALID_MINOR_VERSION 6 INVALID_EXCHANGE_TYPE 7 INVALID_FLAGS 8 INVALID_MESSAGE_ID 9 INVALID_PROTOCOL_ID 10 INVALID_SPI 11 INVALID_TRANSFORM_ID 12 ATTRIBUTES_NOT_SUPPORTED 13 NO_PROPOSAL_CHOSEN 14 BAD_PROPOSAL_SYNTAX 15 PAYLOAD_MALFORMED 16 INVALID_KEY_INFORMATION 17 INVALID_ID_INFORMATION 18 INVALID_CERT_ENCODING 19 INVALID_CERTIFICATE 20 CERT_TYPE_UNSUPPORTED 21 INVALID_CERT_AUTHORITY 22 INVALID_HASH_INFORMATION 23 AUTHENTICATION_FAILED 24 INVALID_SIGNATURE 25 ADDRESS_NOTIFICATION 26 NOTIFY_SA_LIFETIME 27 CERTIFICATE_UNAVAILABLE 28 UNSUPPORTED_EXCHANGE_TYPE 29 UNEQUAL_PAYLOAD_LENGTHS 30 RESERVED_MIN 31 RESERVED_MAX 8191 PRIVATE_MIN 8192 PRIVATE_MAX 16383 STATUS_CONNECTED 16384 STATUS_RESERVED1_MIN 16385 STATUS_RESERVED1_MAX 24575 STATUS_DOI_MIN 24576 STATUS_DOI_MAX 32767 STATUS_PRIVATE_MIN 32768 STATUS_DPD_R_U_THERE 36136 STATUS_DPD_R_U_THERE_ACK 36137 STATUS_PRIVATE_MAX 40959 STATUS_RESERVED2_MIN 40960 STATUS_RESERVED2_MAX 65535 . # ISAKMP V2 Notify payload types ISAKMP_V2_NOTIFY UNSUPPORTED_CRITICAL_PAYLOAD 1 INVALID_IKE_SPI 4 INVALID_MAJOR_VERSION 5 INVALID_SYNTAX 7 INVALID_MESSAGE_ID 9 INVALID_SPI 11 NO_PROPOSAL_CHOSEN 14 AUTHENTICATION_FAILED 24 SINGLE_PAIR_REQUIRED 34 NO_ADDITIONAL_SAS 35 INTERNAL_ADDRESS_FAILURE 36 FAILED_CP_REQUIRED 37 TS_UNACCEPTABLE 38 RESERVED_MIN 39 RESERVED_MAX 8191 PRIVATE_MIN 8192 PRIVATE_MAX 16383 STATUS_RESERVED1_MIN 16384 STATUS_RESERVED1_MAX 24577 STATUS_INITIAL_CONTACT 24578 STATUS_SET_WINDOW_SIZE 24579 STATUS_ADDITIONAL_IS_POSSIBLE 24580 STATUS_IPCOMP_SUPPORTED 24581 STATUS_NAT_DETECTION_SOURCE_IP 24582 STATUS_NAT_DETECTION_DESTINATION_IP 24583 STATUS_COOKIE 24584 STATUS_USE_TRANSPORT_MODE 24585 STATUS_HTTP_CERT_LOOKUP_SUPPORTED 24586 STATUS_RESERVED2_MIN 24587 STATUS_RESERVED2_MAX 40959 STATUS_PRIVATE_MIN 40960 STATUS_PRIVATE_MAX 65535 . # ISAKMP DOI Identifier. ISAKMP_DOI ISAKMP 0 . # ISAKMP Protocol ID. ISAKMP_PROTO ISAKMP 1 . # ISAKMP transaction message type. ISAKMP_CFG REQUEST 1 REPLY 2 SET 3 ACK 4 FUTURE_MIN 5 FUTURE_MAX 127 PRIVATE_MIN 128 PRIVATE_MAX 255 . # ISAKMP configuration attributes. ISAKMP_CFG_ATTR INTERNAL_IP4_ADDRESS 1 INTERNAL_IP4_NETMASK 2 INTERNAL_IP4_DNS 3 INTERNAL_IP4_NBNS 4 INTERNAL_ADDRESS_EXPIRY 5 INTERNAL_IP4_DHCP 6 APPLICATION_VERSION 7 INTERNAL_IP6_ADDRESS 8 INTERNAL_IP6_NETMASK 9 INTERNAL_IP6_DNS 10 INTERNAL_IP6_NBNS 11 INTERNAL_IP6_DHCP 12 INTERNAL_IP4_SUBNET 13 SUPPORTED_ATTRIBUTES 14 INTERNAL_IP6_SUBNET 15 FUTURE_MIN 16 FUTURE_MAX 16383 PRIVATE_MIN 16384 PRIVATE_MAX 32767 . # ISAKMP EAP ISAKMP_EAP_CODE REQUEST 1 RESPONSE 2 SUCCESS 3 FAILURE 4 . # ISAKMP EAP Types (RFC2284) ISAKMP_EAP_TYPE IDENTITY 1 NOTIFICATION 2 NAK 3 # Response only MD5_CHALLENGE 4 OTP 5 TOKEN 6 # Generic token card . isakmpd-20041012.orig/connection.h0000644000175000017500000000414010133045740017064 0ustar jdivejdive00000000000000/* $OpenBSD: connection.h,v 1.5 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: connection.h,v 1.6 1999/06/07 00:10:48 ho Exp $ */ /* * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999 Hakan 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * The connection module deals with connections that should always be up. */ #ifndef _CONNECTION_H_ #define _CONNECTION_H_ #include extern int connection_exist(char *); extern void connection_init(void); extern char *connection_passive_lookup_by_ids(u_int8_t *, u_int8_t *); extern void connection_reinit(void); extern void connection_report(void); extern int connection_setup(char *); extern int connection_record_passive(char *); extern void connection_teardown(char *); #endif /* _CONNECTION_H_ */ isakmpd-20041012.orig/crypto.h0000644000175000017500000001311510133045740016247 0ustar jdivejdive00000000000000/* $OpenBSD: crypto.h,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */ /* $EOM: crypto.h,v 1.12 2000/10/15 21:56:41 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _CRYPTO_H_ #define _CRYPTO_H_ #if defined (__APPLE__) #include #ifdef USE_BLOWFISH #include #endif #ifdef USE_CAST #include #endif #else #include #ifdef USE_BLOWFISH #include #endif #ifdef USE_CAST #include #endif #endif /* __APPLE__ */ #ifdef USE_AES #include #endif #define USE_32BIT #if defined (USE_64BIT) #define XOR64(x,y) *(u_int64_t *)(x) ^= *(u_int64_t *)(y); #define SET64(x,y) *(u_int64_t *)(x) = *(u_int64_t *)(y); #elif defined (USE_32BIT) #define XOR64(x,y) *(u_int32_t *)(x) ^= *(u_int32_t *)(y); \ *(u_int32_t *)((u_int8_t *)(x) + 4) ^= *(u_int32_t *)((u_int8_t *)(y) + 4); #define SET64(x,y) *(u_int32_t *)(x) = *(u_int32_t *)(y); \ *(u_int32_t *)((u_int8_t *)(x) + 4) = *(u_int32_t *)((u_int8_t *)(y) + 4); #else #define XOR8(x,y,i) (x)[i] ^= (y)[i]; #define XOR64(x,y) XOR8(x,y,0); XOR8(x,y,1); XOR8(x,y,2); XOR8(x,y,3); \ XOR8(x,y,4); XOR8(x,y,5); XOR8(x,y,6); XOR8(x,y,7); #define SET8(x,y,i) (x)[i] = (y)[i]; #define SET64(x,y) SET8(x,y,0); SET8(x,y,1); SET8(x,y,2); SET8(x,y,3); \ SET8(x,y,4); SET8(x,y,5); SET8(x,y,6); SET8(x,y,7); #endif /* USE_64BIT */ #define SET_32BIT_BIG(x,y) (x)[3]= (y); (x)[2]= (y) >> 8; \ (x)[1] = (y) >> 16; (x)[0]= (y) >> 24; #define GET_32BIT_BIG(x) (u_int32_t)(x)[3] | ((u_int32_t)(x)[2] << 8) | \ ((u_int32_t)(x)[1] << 16)| ((u_int32_t)(x)[0] << 24); /* * This is standard for all block ciphers we use at the moment. * Keep MAXBLK uptodate. */ #define BLOCKSIZE 8 #ifdef USE_AES #define MAXBLK AES_BLOCK_SIZE #else #define MAXBLK BLOCKSIZE #endif struct keystate { struct crypto_xf *xf; /* Back pointer */ u_int16_t ebytes; /* Number of encrypted bytes */ u_int16_t dbytes; /* Number of decrypted bytes */ time_t life; /* Creation time */ u_int8_t iv[MAXBLK]; /* Next IV to use */ u_int8_t iv2[MAXBLK]; u_int8_t *riv, *liv; union { des_key_schedule desks[3]; #ifdef USE_BLOWFISH blf_ctx blfks; #endif #ifdef USE_CAST cast_key castks; #endif #ifdef USE_AES AES_KEY aesks[2]; #endif } keydata; }; #define ks_des keydata.desks #define ks_blf keydata.blfks #define ks_cast keydata.castks #define ks_aes keydata.aesks /* * Information about the cryptotransform. * * XXX - In regards to the IV (Initialization Vector) the drafts are * completly fucked up and specify a MUST as how it is derived, so * we also have to provide for that. I just don't know where. * Furthermore is this enum needed at all? It seems to be Oakley IDs * only anyhow, and we already have defines for that in ipsec_doi.h. */ enum transform { DES_CBC = 1, /* This is a MUST */ IDEA_CBC = 2, /* Licensed, DONT use */ BLOWFISH_CBC = 3, RC5_R16_B64_CBC = 4, /* Licensed, DONT use */ TRIPLEDES_CBC = 5, /* This is a SHOULD */ CAST_CBC = 6, AES_CBC = 7 }; enum cryptoerr { EOKAY, /* No error */ ENOCRYPTO, /* A none crypto related error, see errno */ EWEAKKEY, /* A weak key was found in key setup */ EKEYLEN /* The key length was invalid for the cipher */ }; struct crypto_xf { enum transform id; /* Oakley ID */ char *name; /* Transform Name */ u_int16_t keymin, keymax; /* Possible Keying Bytes */ u_int16_t blocksize; /* Need to keep IV in the state */ struct keystate *state; /* Key information, can also be passed sep. */ enum cryptoerr (*init)(struct keystate *, u_int8_t *, u_int16_t); void (*encrypt)(struct keystate *, u_int8_t *, u_int16_t); void (*decrypt)(struct keystate *, u_int8_t *, u_int16_t); }; extern struct keystate *crypto_clone_keystate(struct keystate *); extern void crypto_decrypt(struct keystate *, u_int8_t *, u_int16_t); extern void crypto_encrypt(struct keystate *, u_int8_t *, u_int16_t); extern struct crypto_xf *crypto_get(enum transform); extern struct keystate *crypto_init(struct crypto_xf *, u_int8_t *, u_int16_t, enum cryptoerr *); extern void crypto_init_iv(struct keystate *, u_int8_t *, size_t); extern void crypto_update_iv(struct keystate *); #endif /* _CRYPTO_H_ */ isakmpd-20041012.orig/prf.h0000644000175000017500000000443710133045740015525 0ustar jdivejdive00000000000000/* $OpenBSD: prf.h,v 1.10 2004/04/15 18:39:26 deraadt Exp $ */ /* $EOM: prf.h,v 1.1 1998/07/11 20:06:22 provos Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 2001 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _PRF_H_ #define _PRF_H_ /* Enumeration of possible PRF - Pseudo-Random Functions. */ enum prfs { PRF_HMAC = 0 /* No PRFs in drafts, this is the default */ }; struct prf { enum prfs type; /* Type of PRF */ void *prfctx; /* Context for PRF */ u_int8_t blocksize; /* The blocksize of PRF */ void (*Init) (void *); void (*Update) (void *, unsigned char *, unsigned int); void (*Final) (unsigned char *, void *); }; struct prf_hash_ctx { struct hash *hash; /* Hash type to use */ void *ctx, *ctx2; /* Contexts we need for later */ }; struct prf *prf_alloc(enum prfs, int, unsigned char *, unsigned int); void prf_free(struct prf *); #endif /* _PRF_H_ */ isakmpd-20041012.orig/hash.c0000644000175000017500000001004010133045740015637 0ustar jdivejdive00000000000000/* $OpenBSD: hash.c,v 1.17 2004/06/14 09:55:41 ho Exp $ */ /* $EOM: hash.c,v 1.10 1999/04/17 23:20:34 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #if defined (__APPLE__) #include #include #else #include #include #endif /* __APPLE__ */ #include "sysdep.h" #include "hash.h" #include "log.h" void hmac_init(struct hash *, unsigned char *, unsigned int); void hmac_final(unsigned char *, struct hash *); /* Temporary hash contexts. */ static union { MD5_CTX md5ctx; SHA1_CTX sha1ctx; } Ctx, Ctx2; /* Temporary hash digest. */ static unsigned char digest[HASH_MAX]; /* Encapsulation of hash functions. */ static struct hash hashes[] = { { HASH_MD5, 5, MD5_SIZE, (void *)&Ctx.md5ctx, digest, sizeof(MD5_CTX), (void *)&Ctx2.md5ctx, (void (*)(void *))MD5Init, (void (*)(void *, unsigned char *, unsigned int))MD5Update, (void (*)(unsigned char *, void *))MD5Final, hmac_init, hmac_final }, { HASH_SHA1, 6, SHA1_SIZE, (void *)&Ctx.sha1ctx, digest, sizeof(SHA1_CTX), (void *)&Ctx2.sha1ctx, (void (*)(void *))SHA1Init, (void (*)(void *, unsigned char *, unsigned int))SHA1Update, (void (*)(unsigned char *, void *))SHA1Final, hmac_init, hmac_final }, }; struct hash * hash_get(enum hashes hashtype) { size_t i; LOG_DBG((LOG_CRYPTO, 60, "hash_get: requested algorithm %d", hashtype)); for (i = 0; i < sizeof hashes / sizeof hashes[0]; i++) if (hashtype == hashes[i].type) return &hashes[i]; return 0; } /* * Initial a hash for HMAC usage this requires a special init function. * ctx, ctx2 hold the contexts, if you want to use the hash object for * something else in the meantime, be sure to store the contexts somewhere. */ void hmac_init(struct hash *hash, unsigned char *okey, unsigned int len) { unsigned int i, blocklen = HMAC_BLOCKLEN; unsigned char key[HMAC_BLOCKLEN]; memset(key, 0, blocklen); if (len > blocklen) { /* Truncate key down to blocklen */ hash->Init(hash->ctx); hash->Update(hash->ctx, okey, len); hash->Final(key, hash->ctx); } else { memcpy(key, okey, len); } /* HMAC I and O pad computation */ for (i = 0; i < blocklen; i++) key[i] ^= HMAC_IPAD_VAL; hash->Init(hash->ctx); hash->Update(hash->ctx, key, blocklen); for (i = 0; i < blocklen; i++) key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL); hash->Init(hash->ctx2); hash->Update(hash->ctx2, key, blocklen); memset(key, 0, blocklen); } /* * HMAC Final function */ void hmac_final(unsigned char *dgst, struct hash *hash) { hash->Final(dgst, hash->ctx); hash->Update(hash->ctx2, dgst, hash->hashsize); hash->Final(dgst, hash->ctx2); } isakmpd-20041012.orig/transport.c0000644000175000017500000002774110133045740016770 0ustar jdivejdive00000000000000/* $OpenBSD: transport.c,v 1.30 2004/08/08 19:11:06 deraadt Exp $ */ /* $EOM: transport.c,v 1.43 2000/10/10 12:36:39 provos Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. * Copyright (c) 2001, 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include "sysdep.h" #include "conf.h" #include "exchange.h" #include "log.h" #include "message.h" #include "sa.h" #include "timer.h" #include "transport.h" #include "virtual.h" /* If no retransmit limit is given, use this as a default. */ #define RETRANSMIT_DEFAULT 10 LIST_HEAD(transport_list, transport) transport_list; LIST_HEAD(transport_method_list, transport_vtbl) transport_method_list; /* Call the reinit function of the various transports. */ void transport_reinit(void) { struct transport_vtbl *method; for (method = LIST_FIRST(&transport_method_list); method; method = LIST_NEXT(method, link)) if (method->reinit) method->reinit(); } /* Initialize the transport maintenance module. */ void transport_init(void) { LIST_INIT(&transport_list); LIST_INIT(&transport_method_list); } /* Register another transport T. */ void transport_setup(struct transport *t, int toplevel) { if (toplevel) { /* Only the toplevel (virtual) transport has sendqueues. */ LOG_DBG((LOG_TRANSPORT, 70, "transport_setup: virtual transport %p", t)); TAILQ_INIT(&t->sendq); TAILQ_INIT(&t->prio_sendq); t->refcnt = 0; } else { /* udp and udp_encap trp goes into the transport list. */ LOG_DBG((LOG_TRANSPORT, 70, "transport_setup: added %p to transport list", t)); LIST_INSERT_HEAD(&transport_list, t, link); t->refcnt = 1; } t->flags = 0; } /* Add a referer to transport T. */ void transport_reference(struct transport *t) { t->refcnt++; LOG_DBG((LOG_TRANSPORT, 95, "transport_reference: transport %p now has %d references", t, t->refcnt)); } /* * Remove a referer from transport T, removing all of T when no referers left. */ void transport_release(struct transport *t) { LOG_DBG((LOG_TRANSPORT, 95, "transport_release: transport %p had %d references", t, t->refcnt)); if (--t->refcnt) return; LOG_DBG((LOG_TRANSPORT, 70, "transport_release: freeing %p", t)); t->vtbl->remove(t); } void transport_report(void) { struct virtual_transport *v; struct transport *t; struct message *msg; for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) { LOG_DBG((LOG_REPORT, 0, "transport_report: transport %p flags %x refcnt %d", t, t->flags, t->refcnt)); /* XXX Report sth on the virtual transport? */ t->vtbl->report(t); /* * This is the reason message_dump_raw lives outside * message.c. */ v = (struct virtual_transport *)t->virtual; if ((v->encap_is_active && v->encap == t) || (!v->encap_is_active && v->main == t)) { for (msg = TAILQ_FIRST(&t->virtual->prio_sendq); msg; msg = TAILQ_NEXT(msg, link)) message_dump_raw("udp_report(prio)", msg, LOG_REPORT); for (msg = TAILQ_FIRST(&t->virtual->sendq); msg; msg = TAILQ_NEXT(msg, link)) message_dump_raw("udp_report", msg, LOG_REPORT); } } } int transport_prio_sendqs_empty(void) { struct transport *t; for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) if (TAILQ_FIRST(&t->virtual->prio_sendq)) return 0; return 1; } /* Register another transport method T. */ void transport_method_add(struct transport_vtbl *t) { LIST_INSERT_HEAD(&transport_method_list, t, link); } /* Apply a function FUNC on all registered (non-toplevel) transports. */ void transport_map(void (*func) (struct transport *)) { struct transport *t; for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) (*func) (t); } /* * Build up a file descriptor set FDS with all transport descriptors we want * to read from. Return the number of file descriptors select(2) needs to * check in order to cover the ones we setup in here. */ int transport_fd_set(fd_set * fds) { struct transport *t; int n; int max = -1; for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) if (t->virtual->flags & TRANSPORT_LISTEN) { n = t->vtbl->fd_set(t, fds, 1); if (n > max) max = n; LOG_DBG((LOG_TRANSPORT, 95, "transport_fd_set: " "transport %p (virtual %p) fd %d", t, t->virtual, n)); } return max + 1; } /* * Build up a file descriptor set FDS with all the descriptors belonging to * transport where messages are queued for transmittal. Return the number * of file descriptors select(2) needs to check in order to cover the ones * we setup in here. */ int transport_pending_wfd_set(fd_set * fds) { struct transport *t; int n; int max = -1; for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) { if (TAILQ_FIRST(&t->virtual->sendq) || TAILQ_FIRST(&t->virtual->prio_sendq)) { n = t->vtbl->fd_set(t, fds, 1); LOG_DBG((LOG_TRANSPORT, 95, "transport_pending_wfd_set: " "transport %p (virtual %p) fd %d pending", t, t->virtual, n)); if (n > max) max = n; } } return max + 1; } /* * For each transport with a file descriptor in FDS, try to get an * incoming message and start processing it. */ void transport_handle_messages(fd_set *fds) { struct transport *t; for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) { if ((t->flags & TRANSPORT_LISTEN) && (*t->vtbl->fd_isset)(t, fds)) { (*t->virtual->vtbl->handle_message)(t); (*t->vtbl->fd_set)(t, fds, 0); } } } /* * Send the first queued message on the transports found whose file * descriptor is in FDS and has messages queued. Remove the fd bit from * FDS as soon as one message has been sent on it so other transports * sharing the socket won't get service without an intervening select * call. Perhaps a fairness strategy should be implemented between * such transports. Now early transports in the list will potentially * be favoured to later ones sharing the file descriptor. */ void transport_send_messages(fd_set * fds) { struct transport *t, *next; struct message *msg; struct exchange *exchange; struct timeval expiration; int expiry, ok_to_drop_message; /* * Reference all transports first so noone will disappear while in * use. */ for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) transport_reference(t->virtual); for (t = LIST_FIRST(&transport_list); t; t = LIST_NEXT(t, link)) { if ((TAILQ_FIRST(&t->virtual->sendq) || TAILQ_FIRST(&t->virtual->prio_sendq)) && t->vtbl->fd_isset(t, fds)) { /* Remove fd bit. */ t->vtbl->fd_set(t, fds, 0); /* Prefer a message from the prioritized sendq. */ if (TAILQ_FIRST(&t->virtual->prio_sendq)) { msg = TAILQ_FIRST(&t->virtual->prio_sendq); TAILQ_REMOVE(&t->virtual->prio_sendq, msg, link); } else { msg = TAILQ_FIRST(&t->virtual->sendq); TAILQ_REMOVE(&t->virtual->sendq, msg, link); } msg->flags &= ~MSG_IN_TRANSIT; exchange = msg->exchange; exchange->in_transit = 0; /* * We disregard the potential error message here, * hoping that the retransmit will go better. * XXX Consider a retry/fatal error discriminator. */ t->virtual->vtbl->send_message(msg, 0); msg->xmits++; /* * This piece of code has been proven to be quite * delicate. Think twice for before altering. * Here's an outline: * * If this message is not the one which finishes an * exchange, check if we have reached the number of * retransmit before queuing it up for another. * * If it is a finishing message we still may have to * keep it around for an on-demand retransmit when * seeing a duplicate of our peer's previous message. * */ if ((msg->flags & MSG_LAST) == 0) { if (msg->xmits > conf_get_num("General", "retransmits", RETRANSMIT_DEFAULT)) { log_print("transport_send_messages: " "giving up on message %p, " "exchange %s", msg, exchange->name ? exchange->name : ""); /* Be more verbose here. */ if (exchange->phase == 1) { log_print( "transport_send_messages: " "either this message did " "not reach the other " "peer"); if (exchange->initiator) log_print("transport_send_messages: " "or the response" "message did not " "reach us back"); else log_print("transport_send_messages: " "or this is an " "attempted IKE " "scan"); } exchange->last_sent = 0; #ifdef notyet exchange_free(exchange); exchange = 0; #endif } else { gettimeofday(&expiration, 0); /* * XXX Calculate from round trip * timings and a backoff func. */ expiry = msg->xmits * 2 + 5; expiration.tv_sec += expiry; LOG_DBG((LOG_TRANSPORT, 30, "transport_send_messages: " "message %p scheduled for " "retransmission %d in %d secs", msg, msg->xmits, expiry)); if (msg->retrans) timer_remove_event(msg->retrans); msg->retrans = timer_add_event("message_send_expire", (void (*) (void *)) message_send_expire, msg, &expiration); /* * If we cannot retransmit, we * cannot... */ exchange->last_sent = msg->retrans ? msg : 0; } } else exchange->last_sent = exchange->last_received ? msg : 0; /* * If this message is not referred to for later * retransmission it will be ok for us to drop it * after the post-send function. But as the post-send * function may remove the exchange, we need to * remember this fact here. */ ok_to_drop_message = exchange->last_sent == 0; /* * If this is not a retransmit call post-send * functions that allows parallel work to be done * while the network and peer does their share of * the job. Note that a post-send function may take * away the exchange we belong to, but only if no * retransmits are possible. */ if (msg->xmits == 1) message_post_send(msg); if (ok_to_drop_message) message_free(msg); } } for (t = LIST_FIRST(&transport_list); t; t = next) { next = LIST_NEXT(t, link); transport_release(t->virtual); } } /* * Textual search after the transport method denoted by NAME, then create * a transport connected to the peer with address ADDR, given in a transport- * specific string format. */ struct transport * transport_create(char *name, char *addr) { struct transport_vtbl *method; for (method = LIST_FIRST(&transport_method_list); method; method = LIST_NEXT(method, link)) if (strcmp(method->name, name) == 0) return (*method->create) (addr); return 0; } isakmpd-20041012.orig/gmp_util.h0000644000175000017500000000346410133045740016555 0ustar jdivejdive00000000000000/* $OpenBSD: gmp_util.h,v 1.8 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: gmp_util.h,v 1.4 2000/05/08 13:42:11 ho Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 2000 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _GMP_UTIL_H_ #define _GMP_UTIL_H_ #include "math_mp.h" u_int32_t mpz_sizeinoctets(math_mp_t); void mpz_getraw(u_int8_t *, math_mp_t, u_int32_t); void mpz_setraw(math_mp_t, u_int8_t *, u_int32_t); #endif /* _GMP_UTIL_H_ */ isakmpd-20041012.orig/app.c0000644000175000017500000000406310133045740015504 0ustar jdivejdive00000000000000/* $OpenBSD: app.c,v 1.9 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: app.c,v 1.6 1999/05/01 20:21:06 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * XXX This is just a wrapper module for now. Later we might handle many * applications simultaneously but right now, we assume one system-dependent * one only. */ #include "sysdep.h" #include "app.h" #include "log.h" int app_socket; /* Set this to not get any applications setup. */ int app_none = 0; /* Initialize applications. */ void app_init(void) { if (app_none) return; app_socket = sysdep_app_open(); if (app_socket == -1) log_fatal("app_init: cannot open connection to application"); } void app_handler(void) { sysdep_app_handler(app_socket); } isakmpd-20041012.orig/isakmp_doi.h0000644000175000017500000000316010133045740017045 0ustar jdivejdive00000000000000/* $OpenBSD: isakmp_doi.h,v 1.5 2004/04/15 18:39:26 deraadt Exp $ */ /* $EOM: isakmp_doi.h,v 1.1 1998/07/07 23:20:29 niklas Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _ISAKMP_DOI_H_ #define _ISAKMP_DOI_H_ extern void isakmp_doi_init(void); #endif /* _ISAKMP_DOI_H_ */ isakmpd-20041012.orig/math_ec2n.c0000644000175000017500000001645010133045740016567 0ustar jdivejdive00000000000000/* $OpenBSD: math_ec2n.c,v 1.11 2004/05/23 18:17:56 hshoexer Exp $ */ /* $EOM: math_ec2n.c,v 1.9 1999/04/20 09:23:31 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include "sysdep.h" #include "math_2n.h" #include "math_ec2n.h" void ec2np_init(ec2np_ptr n) { b2n_init(n->x); b2n_init(n->y); n->inf = 0; } void ec2np_clear(ec2np_ptr n) { b2n_clear(n->x); b2n_clear(n->y); } int ec2np_set(ec2np_ptr d, ec2np_ptr n) { if (d == n) return 0; d->inf = n->inf; if (b2n_set(d->x, n->x)) return -1; return b2n_set(d->y, n->y); } /* Group */ void ec2ng_init(ec2ng_ptr n) { b2n_init(n->a); b2n_init(n->b); b2n_init(n->p); } void ec2ng_clear(ec2ng_ptr n) { b2n_clear(n->a); b2n_clear(n->b); b2n_clear(n->p); } int ec2ng_set(ec2ng_ptr d, ec2ng_ptr n) { if (b2n_set(d->a, n->a)) return -1; if (b2n_set(d->b, n->b)) return -1; return b2n_set(d->p, n->p); } /* Arithmetic functions */ int ec2np_right(b2n_ptr n, ec2np_ptr p, ec2ng_ptr g) { b2n_t temp; b2n_init(temp); /* First calc x**3 + ax**2 + b */ if (b2n_square(n, p->x)) goto fail; if (b2n_mod(n, n, g->p)) goto fail; if (b2n_mul(temp, g->a, n)) /* a*x**2 */ goto fail; if (b2n_mod(temp, temp, g->p)) goto fail; if (b2n_mul(n, n, p->x))/* x**3 */ goto fail; if (b2n_mod(n, n, g->p)) goto fail; if (b2n_add(n, n, temp)) goto fail; if (b2n_add(n, n, g->b)) goto fail; b2n_clear(temp); return 0; fail: b2n_clear(temp); return -1; } int ec2np_ison(ec2np_ptr p, ec2ng_ptr g) { int res; b2n_t x, y, temp; if (p->inf) return 1; b2n_init(x); b2n_init(y); b2n_init(temp); /* First calc x**3 + ax**2 + b */ if (ec2np_right(x, p, g)) goto fail; /* Now calc y**2 + xy */ if (b2n_square(y, p->y)) goto fail; if (b2n_mod(y, y, g->p)) goto fail; if (b2n_mul(temp, p->y, p->x)) goto fail; if (b2n_mod(temp, temp, g->p)) goto fail; if (b2n_add(y, y, temp)) goto fail; res = !b2n_cmp(x, y); b2n_clear(x); b2n_clear(y); b2n_clear(temp); return res; fail: b2n_clear(x); b2n_clear(y); b2n_clear(temp); return -1; } int ec2np_find_y(ec2np_ptr p, ec2ng_ptr g) { b2n_t right; b2n_init(right); if (ec2np_right(right, p, g)) /* Right sight of equation */ goto fail; if (b2n_mul_inv(p->y, p->x, g->p)) goto fail; if (b2n_square(p->y, p->y)) goto fail; if (b2n_mod(p->y, p->y, g->p)) goto fail; if (b2n_mul(right, right, p->y)) /* x^-2 * right */ goto fail; if (b2n_mod(right, right, g->p)) goto fail; if (b2n_sqrt(p->y, right, g->p)) /* Find root */ goto fail; if (b2n_mul(p->y, p->y, p->x)) goto fail; if (b2n_mod(p->y, p->y, g->p)) goto fail; b2n_clear(right); return 0; fail: b2n_clear(right); return -1; } int ec2np_add(ec2np_ptr d, ec2np_ptr a, ec2np_ptr b, ec2ng_ptr g) { b2n_t lambda, temp; ec2np_t pn; /* Check for Neutral Element */ if (b->inf) return ec2np_set(d, a); if (a->inf) return ec2np_set(d, b); if (!b2n_cmp(a->x, b->x) && (b2n_cmp(a->y, b->y) || !b2n_cmp_null(a->x))) { d->inf = 1; if (b2n_set_null(d->x)) return -1; return b2n_set_null(d->y); } b2n_init(lambda); b2n_init(temp); ec2np_init(pn); if (b2n_cmp(a->x, b->x)) { if (b2n_add(temp, a->x, b->x)) goto fail; if (b2n_add(lambda, a->y, b->y)) goto fail; if (b2n_div_mod(lambda, lambda, temp, g->p)) goto fail; if (b2n_square(pn->x, lambda)) goto fail; if (b2n_mod(pn->x, pn->x, g->p)) goto fail; if (b2n_add(pn->x, pn->x, lambda)) goto fail; if (b2n_add(pn->x, pn->x, g->a)) goto fail; if (b2n_add(pn->x, pn->x, a->x)) goto fail; if (b2n_add(pn->x, pn->x, b->x)) goto fail; } else { if (b2n_div_mod(lambda, b->y, b->x, g->p)) goto fail; if (b2n_add(lambda, lambda, b->x)) goto fail; if (b2n_square(pn->x, lambda)) goto fail; if (b2n_mod(pn->x, pn->x, g->p)) goto fail; if (b2n_add(pn->x, pn->x, lambda)) goto fail; if (b2n_add(pn->x, pn->x, g->a)) goto fail; } if (b2n_add(pn->y, b->x, pn->x)) goto fail; if (b2n_mul(pn->y, pn->y, lambda)) goto fail; if (b2n_mod(pn->y, pn->y, g->p)) goto fail; if (b2n_add(pn->y, pn->y, pn->x)) goto fail; if (b2n_add(pn->y, pn->y, b->y)) goto fail; EC2NP_SWAP(d, pn); ec2np_clear(pn); b2n_clear(lambda); b2n_clear(temp); return 0; fail: ec2np_clear(pn); b2n_clear(lambda); b2n_clear(temp); return -1; } int ec2np_mul(ec2np_ptr d, ec2np_ptr a, b2n_ptr e, ec2ng_ptr g) { int i, j, bits, start; b2n_t h, k; ec2np_t q, mina; if (!b2n_cmp_null(e)) { d->inf = 1; if (b2n_set_null(d->x)) return -1; return b2n_set_null(d->y); } b2n_init(h); b2n_init(k); ec2np_init(q); ec2np_init(mina); if (ec2np_set(q, a)) goto fail; /* Create the point -a. */ if (ec2np_set(mina, a)) goto fail; if (b2n_add(mina->y, mina->y, mina->x)) goto fail; if (b2n_set(k, e)) goto fail; if (b2n_3mul(h, k)) goto fail; if (b2n_resize(k, h->chunks)) goto fail; /* * This is low level but can not be avoided, since we have to do single * bit checks on h and k. */ bits = b2n_sigbit(h); if ((bits & CHUNK_MASK) == 1) { start = ((CHUNK_MASK + bits) >> CHUNK_SHIFTS) - 2; bits = CHUNK_BITS; } else { start = ((CHUNK_MASK + bits) >> CHUNK_SHIFTS) - 1; bits = ((bits - 1) & CHUNK_MASK); } /* * This is the addition, subtraction method which is faster because * we avoid one out of three additions (mean). */ for (i = start; i >= 0; i--) for (j = (i == start ? bits : CHUNK_BITS) - 1; j >= 0; j--) if (i > 0 || j > 0) { if (ec2np_add(q, q, q, g)) goto fail; if ((h->limp[i] & b2n_mask[j]) && !(k->limp[i] & b2n_mask[j])) { if (ec2np_add(q, q, a, g)) goto fail; } else if (!(h->limp[i] & b2n_mask[j]) && (k->limp[i] & b2n_mask[j])) if (ec2np_add(q, q, mina, g)) goto fail; } EC2NP_SWAP(d, q); b2n_clear(k); b2n_clear(h); ec2np_clear(q); ec2np_clear(mina); return 0; fail: b2n_clear(k); b2n_clear(h); ec2np_clear(q); ec2np_clear(mina); return -1; } isakmpd-20041012.orig/isakmp_fld.fld0000644000175000017500000000734510133045740017366 0ustar jdivejdive00000000000000# $OpenBSD: isakmp_fld.fld,v 1.8 2004/06/20 15:24:05 ho Exp $ # $EOM: isakmp_fld.fld,v 1.5 1999/04/25 13:38:22 niklas Exp $ # # Copyright (c) 1998, 2001 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # XXX There are num-declared fields below that really are csts. # The ISAKMP message header. ISAKMP_HDR # XXX I want a way to specify COOKIES as an overlay of ICOOKIE + RCOOKIE ICOOKIE raw 8 RCOOKIE raw 8 NEXT_PAYLOAD cst 1 isakmp_payload_cst VERSION num 1 EXCH_TYPE cst 1 ike_exch_cst,isakmp_exch_cst FLAGS mask 1 isakmp_flags_cst MESSAGE_ID raw 4 LENGTH num 4 . # Generic payload header. ISAKMP_GEN NEXT_PAYLOAD cst 1 isakmp_payload_cst RESERVED ign 1 LENGTH num 2 . # ISAKMP data attributes ISAKMP_ATTR TYPE num 2 ike_attr_cst,ipsec_attr_cst LENGTH_VALUE num 2 VALUE raw . # Security association payload. ISAKMP_SA : ISAKMP_GEN DOI num 4 isakmp_doi_cst,ipsec_doi_cst SIT raw . # Proposal payload. ISAKMP_PROP : ISAKMP_GEN NO num 1 PROTO cst 1 isakmp_proto_cst,ipsec_proto_cst SPI_SZ num 1 NTRANSFORMS num 1 SPI raw . # Transform payload. ISAKMP_TRANSFORM : ISAKMP_GEN NO num 1 ID num 1 RESERVED ign 2 SA_ATTRS raw . # Key exchange payload. ISAKMP_KE : ISAKMP_GEN DATA raw . # Identification payload. ISAKMP_ID : ISAKMP_GEN TYPE num 1 DOI_DATA raw 3 DATA raw . # Certificate payload. ISAKMP_CERT : ISAKMP_GEN ENCODING cst 1 isakmp_certenc_cst DATA raw . # Certificate request payload. ISAKMP_CERTREQ : ISAKMP_GEN TYPE cst 1 isakmp_certenc_cst AUTHORITY raw . # Hash payload. ISAKMP_HASH : ISAKMP_GEN DATA raw . # Signature payload. ISAKMP_SIG : ISAKMP_GEN DATA raw . # Nonce payload. ISAKMP_NONCE : ISAKMP_GEN DATA raw . # Notify payload. ISAKMP_NOTIFY : ISAKMP_GEN DOI cst 4 isakmp_doi_cst,ipsec_doi_cst PROTO cst 1 isakmp_proto_cst SPI_SZ num 1 MSG_TYPE cst 2 isakmp_notify_cst,ipsec_notify_cst SPI raw . # Delete payload. ISAKMP_DELETE : ISAKMP_GEN DOI cst 4 isakmp_doi_cst,ipsec_doi_cst PROTO cst 1 isakmp_proto_cst SPI_SZ num 1 NSPIS num 2 SPI raw . # Vendor ID payload. ISAKMP_VENDOR : ISAKMP_GEN ID raw . # Attribute payload. ISAKMP_ATTRIBUTE : ISAKMP_GEN TYPE num 1 isakmp_cfg_cst RESERVED ign 1 ID num 2 ATTRS raw . # NAT Discovery payload. ISAKMP_NAT_D : ISAKMP_GEN DATA raw . # NAT Original Address payload. ISAKMP_NAT_OA : ISAKMP_GEN TYPE num 1 RESERVED ign 3 DATA raw . isakmpd-20041012.orig/app.h0000644000175000017500000000332010133045740015504 0ustar jdivejdive00000000000000/* $OpenBSD: app.h,v 1.7 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: app.h,v 1.4 1999/04/02 00:58:16 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _APP_H_ #define _APP_H_ extern int app_socket; extern int app_none; extern void app_conf_init_hook(void); extern void app_handler(void); extern void app_init(void); #endif /* _APP_H_ */ isakmpd-20041012.orig/ipsec_num.cst0000644000175000017500000001300210133045740017246 0ustar jdivejdive00000000000000# $OpenBSD: ipsec_num.cst,v 1.15 2004/04/28 14:40:00 ho Exp $ # $EOM: ipsec_num.cst,v 1.5 2000/10/13 17:56:52 angelos Exp $ # # Copyright (c) 1998 Niklas Hallqvist. All rights reserved. # Copyright (c) 2003 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # XXX Please fill in references to the drafts, chapter & verse for each # constant group below. # IPSEC DOI Identifier. IPSEC_DOI IPSEC 1 . # IPSEC SA attributes IPSEC_ATTR SA_LIFE_TYPE 1 SA_LIFE_DURATION 2 GROUP_DESCRIPTION 3 ENCAPSULATION_MODE 4 AUTHENTICATION_ALGORITHM 5 KEY_LENGTH 6 KEY_ROUNDS 7 COMPRESS_DICTIONARY_SIZE 8 COMPRESS_PRIVATE_ALGORITHM 9 ECN_TUNNEL 10 . # IPSEC SA duration. IPSEC_DURATION SECONDS 1 KILOBYTES 2 . # IPSEC encapsulation mode. IPSEC_ENCAP TUNNEL 1 TRANSPORT 2 FUTURE_UDP_ENCAP_TUNNEL 3 # XXX Not yet assigned FUTURE_UDP_ENCAP_TRANSPORT 4 # XXX Not yet assigned UDP_ENCAP_TUNNEL 61443 # draft-ietf-ipsec-nat-t-ike UDP_ENCAP_TRANSPORT 61443 # draft-ietf-ipsec-nat-t-ike . # IPSEC authentication algorithm. IPSEC_AUTH HMAC_MD5 1 HMAC_SHA 2 DES_MAC 3 KPDK 4 HMAC_SHA2_256 5 HMAC_SHA2_384 6 HMAC_SHA2_512 7 HMAC_RIPEMD 8 . # IPSEC ID types. IPSEC_ID IPV4_ADDR 1 FQDN 2 USER_FQDN 3 IPV4_ADDR_SUBNET 4 IPV6_ADDR 5 IPV6_ADDR_SUBNET 6 IPV4_RANGE 7 IPV6_RANGE 8 DER_ASN1_DN 9 DER_ASN1_GN 10 KEY_ID 11 . # IKE SA attributes IKE_ATTR ENCRYPTION_ALGORITHM 1 ike_encrypt_cst HASH_ALGORITHM 2 ike_hash_cst AUTHENTICATION_METHOD 3 ike_auth_cst GROUP_DESCRIPTION 4 ike_group_desc_cst GROUP_TYPE 5 ike_group_cst GROUP_PRIME 6 GROUP_GENERATOR_1 7 GROUP_GENERATOR_2 8 GROUP_CURVE_A 9 GROUP_CURVE_B 10 LIFE_TYPE 11 ike_duration_cst LIFE_DURATION 12 PRF 13 ike_prf_cst KEY_LENGTH 14 FIELD_SIZE 15 GROUP_ORDER 16 BLOCK_SIZE 17 . # XXX Fill in reserved ranges for the attributes below. # IKE encryption algorithm. IKE_ENCRYPT DES_CBC 1 IDEA_CBC 2 BLOWFISH_CBC 3 RC5_R16_B64_CBC 4 3DES_CBC 5 CAST_CBC 6 AES_CBC 7 . # IKE hash algorithm. IKE_HASH MD5 1 SHA 2 TIGER 3 SHA2_256 4 SHA2_384 5 SHA2_512 6 . # IKE authentication method. IKE_AUTH PRE_SHARED 1 DSS 2 RSA_SIG 3 RSA_ENC 4 RSA_ENC_REV 5 EL_GAMAL_ENC 6 EL_GAMAL_ENC_REV 7 ECDSA_SIG 8 . # IKE group description. IKE_GROUP_DESC MODP_768 1 MODP_1024 2 EC2N_155 3 EC2N_185 4 MODP_1536 5 EC2N_163sect 6 EC2N_163K 7 EC2N_283sect 8 EC2N_283K 9 EC2N_409sect 10 EC2N_409K 11 EC2N_571sect 12 EC2N_571K 13 MODP_2048 14 MODP_3072 15 MODP_4096 16 MODP_6144 17 MODP_8192 18 . # IKE Group type. IKE_GROUP MODP 1 ECP 2 EC2N 3 . # IKE SA duration. IKE_DURATION SECONDS 1 KILOBYTES 2 . # IKE Pseudo random function. No defined so far. IKE_PRF . # IPSEC Situation bits. IPSEC_SIT IDENTITY_ONLY 1 SECRECY 2 INTEGRITY 4 . # IPSEC security protocol IDs. IPSEC_PROTO IPSEC_AH 2 IPSEC_ESP 3 IPCOMP 4 . # IPSEC ISAKMP transform IDs. IPSEC_TRANSFORM KEY_IKE 1 . # IPSEC AH transform IDs. IPSEC_AH MD5 2 SHA 3 DES 4 SHA2_256 5 SHA2_384 6 SHA2_512 7 RIPEMD 8 . # IPSEC ESP transform IDs. IPSEC_ESP DES_IV64 1 DES 2 3DES 3 RC5 4 IDEA 5 CAST 6 BLOWFISH 7 3IDEA 8 DES_IV32 9 RC4 10 NULL 11 AES 12 AES_128_CTR 13 AES_MARS 249 AES_RC6 250 AES_RIJNDAEL 251 AES_SERPENT 252 AES_TWOFISH 253 . # IPSEC IPCOMP transform IDs IPSEC_IPCOMP OUI 1 DEFLATE 2 LZS 3 V42BIS 4 . # IPSEC notify message types. IPSEC_NOTIFY RESPONDER_LIFETIME 24576 REPLAY_STATUS 24577 INITIAL_CONTACT 24578 . # IKE exchange types. IKE_EXCH QUICK_MODE 32 NEW_GROUP_MODE 33 . isakmpd-20041012.orig/nat_traversal.h0000644000175000017500000000332510133045740017576 0ustar jdivejdive00000000000000/* $OpenBSD: nat_traversal.h,v 1.2 2004/06/21 23:27:10 ho Exp $ */ /* * Copyright (c) 2004 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. * * 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. */ #ifndef _NAT_TRAVERSAL_H_ #define _NAT_TRAVERSAL_H_ void nat_t_init(void); int nat_t_add_vendor_payloads(struct message *); void nat_t_check_vendor_payload(struct message *, struct payload *); int nat_t_exchange_add_nat_d(struct message *); int nat_t_exchange_check_nat_d(struct message *); void nat_t_setup_keepalive(struct sa *); #endif /* _NAT_TRAVERSAL_H_ */ isakmpd-20041012.orig/exchange.c0000644000175000017500000014447110133045740016516 0ustar jdivejdive00000000000000/* $OpenBSD: exchange.c,v 1.104 2004/09/17 13:53:08 ho Exp $ */ /* $EOM: exchange.c,v 1.143 2000/12/04 00:02:25 angelos Exp $ */ /* * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2001 Angelos D. Keromytis. All rights reserved. * Copyright (c) 1999, 2000, 2002 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include "sysdep.h" #include "cert.h" #include "conf.h" #include "connection.h" #include "constants.h" #include "cookie.h" #include "crypto.h" #include "doi.h" #include "exchange.h" #include "ipsec_num.h" #include "isakmp.h" #ifdef USE_ISAKMP_CFG #include "isakmp_cfg.h" #endif #include "libcrypto.h" #include "log.h" #include "message.h" #include "timer.h" #include "transport.h" #include "ipsec.h" #include "sa.h" #include "util.h" #include "key.h" /* Initial number of bits from the cookies used as hash. */ #define INITIAL_BUCKET_BITS 6 /* * Don't try to use more bits than this as a hash. * We only XOR 16 bits so going above that means changing the code below * too. */ #define MAX_BUCKET_BITS 16 #ifdef USE_DEBUG static void exchange_dump(char *, struct exchange *); #endif static void exchange_free_aux(void *); #if 0 static void exchange_resize(void); #endif static struct exchange *exchange_lookup_active(char *, int); static LIST_HEAD(exchange_list, exchange) *exchange_tab; /* Works both as a maximum index and a mask. */ static int bucket_mask; /* * Validation scripts used to test messages for correct content of * payloads depending on the exchange type. */ int16_t script_base[] = { ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */ ISAKMP_PAYLOAD_NONCE, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */ ISAKMP_PAYLOAD_NONCE, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_KEY_EXCH, /* Initiator -> responder. */ ISAKMP_PAYLOAD_ID, EXCHANGE_SCRIPT_AUTH, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_KEY_EXCH, /* Responder -> initiator. */ ISAKMP_PAYLOAD_ID, EXCHANGE_SCRIPT_AUTH, EXCHANGE_SCRIPT_END }; int16_t script_identity_protection[] = { ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */ EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */ EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_KEY_EXCH, /* Initiator -> responder. */ ISAKMP_PAYLOAD_NONCE, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_KEY_EXCH, /* Responder -> initiator. */ ISAKMP_PAYLOAD_NONCE, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_ID, /* Initiator -> responder. */ EXCHANGE_SCRIPT_AUTH, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_ID, /* Responder -> initiator. */ EXCHANGE_SCRIPT_AUTH, EXCHANGE_SCRIPT_END }; int16_t script_authentication_only[] = { ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */ ISAKMP_PAYLOAD_NONCE, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */ ISAKMP_PAYLOAD_NONCE, ISAKMP_PAYLOAD_ID, EXCHANGE_SCRIPT_AUTH, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_ID, /* Initiator -> responder. */ EXCHANGE_SCRIPT_AUTH, EXCHANGE_SCRIPT_END }; #ifdef USE_AGGRESSIVE int16_t script_aggressive[] = { ISAKMP_PAYLOAD_SA, /* Initiator -> responder. */ ISAKMP_PAYLOAD_KEY_EXCH, ISAKMP_PAYLOAD_NONCE, ISAKMP_PAYLOAD_ID, EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_SA, /* Responder -> initiator. */ ISAKMP_PAYLOAD_KEY_EXCH, ISAKMP_PAYLOAD_NONCE, ISAKMP_PAYLOAD_ID, EXCHANGE_SCRIPT_AUTH, EXCHANGE_SCRIPT_SWITCH, EXCHANGE_SCRIPT_AUTH, /* Initiator -> responder. */ EXCHANGE_SCRIPT_END }; #endif /* USE_AGGRESSIVE */ int16_t script_informational[] = { EXCHANGE_SCRIPT_INFO, /* Initiator -> responder. */ EXCHANGE_SCRIPT_END }; /* * Check what exchange SA is negotiated with and return a suitable validation * script. */ int16_t * exchange_script(struct exchange *exchange) { switch (exchange->type) { case ISAKMP_EXCH_BASE: return script_base; case ISAKMP_EXCH_ID_PROT: return script_identity_protection; case ISAKMP_EXCH_AUTH_ONLY: return script_authentication_only; #ifdef USE_AGGRESSIVE case ISAKMP_EXCH_AGGRESSIVE: return script_aggressive; #endif case ISAKMP_EXCH_INFO: return script_informational; #ifdef USE_ISAKMP_CFG case ISAKMP_EXCH_TRANSACTION: return script_transaction; #endif default: if (exchange->type >= ISAKMP_EXCH_DOI_MIN && exchange->type <= ISAKMP_EXCH_DOI_MAX) return exchange->doi->exchange_script(exchange->type); } return 0; } /* * Validate the message MSG's contents wrt what payloads the exchange type * requires at this point in the dialogoue. Return -1 if the validation fails, * 0 if it succeeds and the script is not finished and 1 if it's ready. */ static int exchange_validate(struct message *msg) { struct exchange *exchange = msg->exchange; int16_t *pc = exchange->exch_pc; while (*pc != EXCHANGE_SCRIPT_END && *pc != EXCHANGE_SCRIPT_SWITCH) { LOG_DBG((LOG_EXCHANGE, 90, "exchange_validate: checking for required %s", *pc >= ISAKMP_PAYLOAD_NONE ? constant_name(isakmp_payload_cst, *pc) : constant_name(exchange_script_cst, *pc))); /* Check for existence of the required payloads. */ if ((*pc > 0 && !payload_first(msg, *pc)) || (*pc == EXCHANGE_SCRIPT_AUTH && !payload_first(msg, ISAKMP_PAYLOAD_HASH) && !payload_first(msg, ISAKMP_PAYLOAD_SIG)) || (*pc == EXCHANGE_SCRIPT_INFO && ((!payload_first(msg, ISAKMP_PAYLOAD_NOTIFY) && !payload_first(msg, ISAKMP_PAYLOAD_DELETE)) || (payload_first(msg, ISAKMP_PAYLOAD_DELETE) && !payload_first(msg, ISAKMP_PAYLOAD_HASH))))) { /* Missing payload. */ LOG_DBG((LOG_MESSAGE, 70, "exchange_validate: msg %p requires missing %s", msg, *pc >= ISAKMP_PAYLOAD_NONE ? constant_name(isakmp_payload_cst, *pc) : constant_name(exchange_script_cst, *pc))); return -1; } pc++; } if (*pc == EXCHANGE_SCRIPT_END) /* Cleanup. */ return 1; return 0; } /* Feed unhandled payloads to the DOI for handling. Help for exchange_run(). */ static void exchange_handle_leftover_payloads(struct message *msg) { struct exchange *exchange = msg->exchange; struct doi *doi = exchange->doi; struct payload *p; int i; for (i = ISAKMP_PAYLOAD_SA; i < payload_index_max; i++) { if (i == ISAKMP_PAYLOAD_PROPOSAL || i == ISAKMP_PAYLOAD_TRANSFORM) continue; for (p = payload_first(msg, i); p; p = TAILQ_NEXT(p, link)) { if (p->flags & PL_MARK) continue; if (!doi->handle_leftover_payload || doi->handle_leftover_payload(msg, i, p)) LOG_DBG((LOG_EXCHANGE, 10, "exchange_run: unexpected payload %s", constant_name(isakmp_payload_cst, i))); } } } /* * Run the exchange script from a point given by the "program counter" * upto either the script's end or a transmittal of a message. If we are * at the point of a reception of a message, that message should be handed * in here in the MSG argument. Otherwise we are the initiator and should * expect MSG to be a half-cooked message without payloads. */ void exchange_run(struct message *msg) { struct exchange *exchange = msg->exchange; struct doi *doi = exchange->doi; int (*handler)(struct message *) = exchange->initiator ? doi->initiator : doi->responder; int done = 0; while (!done) { /* * It's our turn if we're either the initiator on an even step, * or the responder on an odd step of the dialogue. */ if (exchange->initiator ^ (exchange->step % 2)) { done = 1; if (exchange->step) msg = message_alloc_reply(msg); message_setup_header(msg, exchange->type, 0, exchange->message_id); if (handler(msg)) { /* * This can happen when transient starvation * of memory occurs. * XXX The peer's retransmit ought to * kick-start this exchange again. If he's * stopped retransmitting he's likely dropped * the SA at his side so we need to do that * too, i.e. implement automatic SA teardown * after a certain amount of inactivity. */ log_print("exchange_run: doi->%s (%p) failed", exchange->initiator ? "initiator" : "responder", msg); message_free(msg); return; } switch (exchange_validate(msg)) { case 1: /* * The last message of a multi-message * exchange should not be retransmitted other * than "on-demand", i.e. if we see * retransmits of the last message of the peer * later. */ msg->flags |= MSG_LAST; if (exchange->step > 0) { if (exchange->last_sent) message_free(exchange->last_sent); exchange->last_sent = msg; } /* * After we physically have sent our last * message we need to do SA-specific * finalization, like telling our application * the SA is ready to be used, or issuing a * CONNECTED notify if we set the COMMIT bit. */ message_register_post_send(msg, exchange_finalize); /* Fallthrough. */ case 0: /* XXX error handling. */ message_send(msg); break; default: log_print("exchange_run: exchange_validate " "failed, DOI error"); exchange_free(exchange); message_free(msg); return; } } else { done = exchange_validate(msg); switch (done) { case 0: case 1: /* Feed the message to the DOI. */ if (handler(msg)) { /* * Trust the peer to retransmit. * XXX We have to implement SA aging * with automatic teardown. */ message_free(msg); return; } /* * Go over the yet unhandled payloads and feed * them to DOI for handling. */ exchange_handle_leftover_payloads(msg); /* * We have advanced the state. If we have * been processing an incoming message, record * that message as the one to do duplication * tests against. */ if (exchange->last_received) message_free(exchange->last_received); exchange->last_received = msg; if (exchange->flags & EXCHANGE_FLAG_ENCRYPT) crypto_update_iv(exchange->keystate); if (done) { exchange_finalize(msg); return; } break; case -1: log_print("exchange_run: exchange_validate " "failed"); /* * XXX Is this the best error notification * type? */ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return; } } LOG_DBG((LOG_EXCHANGE, 40, "exchange_run: exchange %p finished step %d, advancing...", exchange, exchange->step)); exchange->step++; while (*exchange->exch_pc != EXCHANGE_SCRIPT_SWITCH && *exchange->exch_pc != EXCHANGE_SCRIPT_END) exchange->exch_pc++; exchange->exch_pc++; } } void exchange_init(void) { int i; bucket_mask = (1 << INITIAL_BUCKET_BITS) - 1; exchange_tab = malloc((bucket_mask + 1) * sizeof(struct exchange_list)); if (!exchange_tab) log_fatal("exchange_init: out of memory"); for (i = 0; i <= bucket_mask; i++) LIST_INIT(&exchange_tab[i]); } #if 0 /* XXX Currently unused. */ static void exchange_resize(void) { struct exchange_list *new_tab; int new_mask = (bucket_mask + 1) * 2 - 1; int i; new_tab = realloc(exchange_tab, (new_mask + 1) * sizeof(struct exchange_list)); if (!new_tab) return; for (i = bucket_mask + 1; i <= new_mask; i++) LIST_INIT(&new_tab[i]); bucket_mask = new_mask; /* XXX Rehash existing entries. */ } #endif /* Lookup a phase 1 exchange out of just the initiator cookie. */ struct exchange * exchange_lookup_from_icookie(u_int8_t * cookie) { struct exchange *exchange; int i; for (i = 0; i <= bucket_mask; i++) for (exchange = LIST_FIRST(&exchange_tab[i]); exchange; exchange = LIST_NEXT(exchange, link)) if (memcmp(exchange->cookies, cookie, ISAKMP_HDR_ICOOKIE_LEN) == 0 && exchange->phase == 1) return exchange; return 0; } /* Lookup an exchange out of the name and phase. */ struct exchange * exchange_lookup_by_name(char *name, int phase) { struct exchange *exchange; int i; /* If we search for nothing, we will find nothing. */ if (!name) return 0; for (i = 0; i <= bucket_mask; i++) for (exchange = LIST_FIRST(&exchange_tab[i]); exchange; exchange = LIST_NEXT(exchange, link)) { LOG_DBG((LOG_EXCHANGE, 90, "exchange_lookup_by_name: %s == %s && %d == %d?", name, exchange->name ? exchange->name : "", phase, exchange->phase)); /* * Match by name, but don't select finished exchanges, * i.e where MSG_LAST are set in last_sent msg. */ if (exchange->name && strcasecmp(exchange->name, name) == 0 && exchange->phase == phase && (!exchange->last_sent || (exchange->last_sent->flags & MSG_LAST) == 0)) return exchange; } return 0; } /* Lookup an exchange out of the name, phase and step > 1. */ static struct exchange * exchange_lookup_active(char *name, int phase) { struct exchange *exchange; int i; /* XXX Almost identical to exchange_lookup_by_name. */ if (!name) return 0; for (i = 0; i <= bucket_mask; i++) for (exchange = LIST_FIRST(&exchange_tab[i]); exchange; exchange = LIST_NEXT(exchange, link)) { LOG_DBG((LOG_EXCHANGE, 90, "exchange_lookup_active: %s == %s && %d == %d?", name, exchange->name ? exchange->name : "", phase, exchange->phase)); if (exchange->name && strcasecmp(exchange->name, name) == 0 && exchange->phase == phase) { if (exchange->step > 1) return exchange; else LOG_DBG((LOG_EXCHANGE, 80, "exchange_lookup_active: avoided " "early (pre-step 1) exchange %p", exchange)); } } return 0; } static void exchange_enter(struct exchange *exchange) { u_int16_t bucket = 0; u_int8_t *cp; int i; /* XXX We might resize if we are crossing a certain threshold */ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2) { cp = exchange->cookies + i; /* Doing it this way avoids alignment problems. */ bucket ^= cp[0] | cp[1] << 8; } for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2) { cp = exchange->message_id + i; /* Doing it this way avoids alignment problems. */ bucket ^= cp[0] | cp[1] << 8; } bucket &= bucket_mask; LIST_INSERT_HEAD(&exchange_tab[bucket], exchange, link); } /* * Lookup the exchange given by the header fields MSG. PHASE2 is false when * looking for phase 1 exchanges and true otherwise. */ struct exchange * exchange_lookup(u_int8_t *msg, int phase2) { struct exchange *exchange; u_int16_t bucket = 0; u_int8_t *cp; int i; /* * We use the cookies to get bits to use as an index into exchange_tab, * as at least one (our cookie) is a good hash, xoring all the bits, * 16 at a time, and then masking, should do. Doing it this way means * we can validate cookies very fast thus delimiting the effects of * "Denial of service"-attacks using packet flooding. */ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2) { cp = msg + ISAKMP_HDR_COOKIES_OFF + i; /* Doing it this way avoids alignment problems. */ bucket ^= cp[0] | cp[1] << 8; } if (phase2) for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2) { cp = msg + ISAKMP_HDR_MESSAGE_ID_OFF + i; /* Doing it this way avoids alignment problems. */ bucket ^= cp[0] | cp[1] << 8; } bucket &= bucket_mask; for (exchange = LIST_FIRST(&exchange_tab[bucket]); exchange && (memcmp(msg + ISAKMP_HDR_COOKIES_OFF, exchange->cookies, ISAKMP_HDR_COOKIES_LEN) != 0 || (phase2 && memcmp(msg + ISAKMP_HDR_MESSAGE_ID_OFF, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN) != 0) || (!phase2 && !zero_test(msg + ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN))); exchange = LIST_NEXT(exchange, link)) ; return exchange; } /* * Create a phase PHASE exchange where INITIATOR denotes our role. DOI * is the domain of interpretation identifier and TYPE tells what exchange * type to use per either the DOI document or the ISAKMP spec proper. * NSA tells how many SAs we should pre-allocate, and should be zero * when we have the responder role. */ static struct exchange * exchange_create(int phase, int initiator, int doi, int type) { struct exchange *exchange; struct timeval expiration; int delta; /* * We want the exchange zeroed for exchange_free to be able to find * out what fields have been filled-in. */ exchange = calloc(1, sizeof *exchange); if (!exchange) { log_error("exchange_create: calloc (1, %lu) failed", (unsigned long)sizeof *exchange); return 0; } exchange->phase = phase; exchange->step = 0; exchange->initiator = initiator; memset(exchange->cookies, 0, ISAKMP_HDR_COOKIES_LEN); memset(exchange->message_id, 0, ISAKMP_HDR_MESSAGE_ID_LEN); exchange->doi = doi_lookup(doi); exchange->type = type; exchange->policy_id = -1; exchange->exch_pc = exchange_script(exchange); exchange->last_sent = exchange->last_received = 0; TAILQ_INIT(&exchange->sa_list); TAILQ_INIT(&exchange->aca_list); /* Allocate the DOI-specific structure and initialize it to zeroes. */ if (exchange->doi->exchange_size) { exchange->data = calloc(1, exchange->doi->exchange_size); if (!exchange->data) { log_error("exchange_create: calloc (1, %lu) failed", (unsigned long)exchange->doi->exchange_size); exchange_free(exchange); return 0; } } gettimeofday(&expiration, 0); delta = conf_get_num("General", "Exchange-max-time", EXCHANGE_MAX_TIME); expiration.tv_sec += delta; exchange->death = timer_add_event("exchange_free_aux", exchange_free_aux, exchange, &expiration); if (!exchange->death) { /* If we don't give up we might start leaking... */ exchange_free_aux(exchange); return 0; } return exchange; } struct exchange_finalization_node { void (*first)(struct exchange *, void *, int); void *first_arg; void (*second)(struct exchange *, void *, int); void *second_arg; }; /* Run the finalization functions of ARG. */ static void exchange_run_finalizations(struct exchange *exchange, void *arg, int fail) { struct exchange_finalization_node *node = arg; node->first(exchange, node->first_arg, fail); node->second(exchange, node->second_arg, fail); free(node); } /* * Add a finalization function FINALIZE with argument ARG to the tail * of the finalization function list of EXCHANGE. */ static void exchange_add_finalization(struct exchange *exchange, void (*finalize)(struct exchange *, void *, int), void *arg) { struct exchange_finalization_node *node; if (!finalize) return; if (!exchange->finalize) { exchange->finalize = finalize; exchange->finalize_arg = arg; return; } node = malloc(sizeof *node); if (!node) { log_error("exchange_add_finalization: malloc (%lu) failed", (unsigned long)sizeof *node); free(arg); return; } node->first = exchange->finalize; node->first_arg = exchange->finalize_arg; node->second = finalize; node->second_arg = arg; exchange->finalize = exchange_run_finalizations; exchange->finalize_arg = node; } #ifdef USE_ISAKMP_CFG static void exchange_establish_transaction(struct exchange *exchange, void *arg, int fail) { /* Establish a TRANSACTION exchange. */ struct exchange_finalization_node *node = (struct exchange_finalization_node *)arg; struct sa *isakmp_sa = sa_lookup_by_name((char *) node->second_arg, 1); if (isakmp_sa && !fail) exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_TRANSACTION, 0, 0, node->first, node->first_arg); free(node); } #endif /* USE_ISAKMP_CFG */ /* Establish a phase 1 exchange. */ void exchange_establish_p1(struct transport *t, u_int8_t type, u_int32_t doi, char *name, void *args, void (*finalize)(struct exchange *, void *, int), void *arg) { struct exchange *exchange; struct message *msg; #ifdef USE_ISAKMP_CFG struct conf_list *flags; struct conf_list_node *flag; #endif char *tag = 0; char *str; if (name) { /* If no exchange type given, fetch from the configuration. */ if (type == 0) { /* * XXX Similar code can be found in * exchange_setup_p1. Share? */ /* Find out our phase 1 mode. */ tag = conf_get_str(name, "Configuration"); if (!tag) { /* Use default setting. */ tag = CONF_DFLT_TAG_PHASE1_CONFIG; } /* Figure out the DOI. XXX Factor out? */ str = conf_get_str(tag, "DOI"); if (!str || strcasecmp(str, "IPSEC") == 0) doi = IPSEC_DOI_IPSEC; else if (strcasecmp(str, "ISAKMP") == 0) doi = ISAKMP_DOI_ISAKMP; else { log_print("exchange_establish_p1: " "DOI \"%s\" unsupported", str); return; } /* What exchange type do we want? */ str = conf_get_str(tag, "EXCHANGE_TYPE"); if (!str) { log_print("exchange_establish_p1: " "no \"EXCHANGE_TYPE\" tag in [%s] section", tag); return; } type = constant_value(isakmp_exch_cst, str); if (!type) { log_print("exchange_setup_p1: " "unknown exchange type %s", str); return; } } } exchange = exchange_create(1, 1, doi, type); if (!exchange) { /* XXX Do something here? */ return; } if (name) { exchange->name = strdup(name); if (!exchange->name) { log_error("exchange_establish_p1: " "strdup (\"%s\") failed", name); exchange_free(exchange); return; } } exchange->policy = name ? conf_get_str(name, "Configuration") : 0; if (!exchange->policy && name) exchange->policy = CONF_DFLT_TAG_PHASE1_CONFIG; #ifdef USE_ISAKMP_CFG if (name && (flags = conf_get_list(name, "Flags")) != NULL) { for (flag = TAILQ_FIRST(&flags->fields); flag; flag = TAILQ_NEXT(flag, link)) if (strcasecmp(flag->field, "ikecfg") == 0) { struct exchange_finalization_node *node; node = calloc(1, (unsigned long)sizeof *node); if (!node) { log_print("exchange_establish_p1: " "calloc (1, %lu) failed", (unsigned long)sizeof(*node)); exchange_free(exchange); return; } /* * Insert this finalization inbetween * the original. */ node->first = finalize; node->first_arg = arg; node->second_arg = name; exchange_add_finalization(exchange, exchange_establish_transaction, node); finalize = 0; } conf_free_list(flags); } #endif /* USE_ISAKMP_CFG */ exchange_add_finalization(exchange, finalize, arg); cookie_gen(t, exchange, exchange->cookies, ISAKMP_HDR_ICOOKIE_LEN); exchange_enter(exchange); #ifdef USE_DEBUG exchange_dump("exchange_establish_p1", exchange); #endif msg = message_alloc(t, 0, ISAKMP_HDR_SZ); if (!msg) { log_print("exchange_establish_p1: message_alloc () failed"); exchange_free(exchange); return; } msg->exchange = exchange; /* Do not create SA for an information or transaction exchange. */ if (exchange->type != ISAKMP_EXCH_INFO && exchange->type != ISAKMP_EXCH_TRANSACTION) { /* * Don't install a transport into this SA as it will be an * INADDR_ANY address in the local end, which is not good at * all. Let the reply packet install the transport instead. */ sa_create(exchange, 0); msg->isakmp_sa = TAILQ_FIRST(&exchange->sa_list); if (!msg->isakmp_sa) { /* XXX Do something more here? */ message_free(msg); exchange_free(exchange); return; } sa_reference(msg->isakmp_sa); } msg->extra = args; exchange_run(msg); } /* Establish a phase 2 exchange. XXX With just one SA for now. */ void exchange_establish_p2(struct sa *isakmp_sa, u_int8_t type, char *name, void *args, void (*finalize)(struct exchange *, void *, int), void *arg) { struct exchange *exchange; struct message *msg; u_int32_t doi = ISAKMP_DOI_ISAKMP; u_int32_t seq = 0; int i; char *tag, *str; if (isakmp_sa) doi = isakmp_sa->doi->id; if (name) { /* Find out our phase 2 modes. */ tag = conf_get_str(name, "Configuration"); if (!tag) { log_print("exchange_establish_p2: " "no configuration for peer \"%s\"", name); return; } seq = (u_int32_t)conf_get_num(name, "Acquire-ID", 0); /* Figure out the DOI. */ str = conf_get_str(tag, "DOI"); if (!str || strcasecmp(str, "IPSEC") == 0) doi = IPSEC_DOI_IPSEC; else if (strcasecmp(str, "ISAKMP") == 0) doi = ISAKMP_DOI_ISAKMP; else { log_print("exchange_establish_p2: " "DOI \"%s\" unsupported", str); return; } /* What exchange type do we want? */ if (!type) { str = conf_get_str(tag, "EXCHANGE_TYPE"); if (!str) { log_print("exchange_establish_p2: " "no \"EXCHANGE_TYPE\" tag in [%s] section", tag); return; } /* XXX IKE dependent. */ type = constant_value(ike_exch_cst, str); if (!type) { log_print("exchange_establish_p2: unknown " "exchange type %s", str); return; } } } exchange = exchange_create(2, 1, doi, type); if (!exchange) { /* XXX Do something here? */ return; } if (name) { exchange->name = strdup(name); if (!exchange->name) { log_error("exchange_establish_p2: " "strdup (\"%s\") failed", name); exchange_free(exchange); return; } } exchange->policy = name ? conf_get_str(name, "Configuration") : 0; exchange->finalize = finalize; exchange->finalize_arg = arg; exchange->seq = seq; memcpy(exchange->cookies, isakmp_sa->cookies, ISAKMP_HDR_COOKIES_LEN); getrandom(exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); exchange->flags |= EXCHANGE_FLAG_ENCRYPT; #if defined (USE_NAT_TRAVERSAL) if (isakmp_sa->flags & SA_FLAG_NAT_T_ENABLE) exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE; if (isakmp_sa->flags & SA_FLAG_NAT_T_KEEPALIVE) exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE; #endif exchange_enter(exchange); #ifdef USE_DEBUG exchange_dump("exchange_establish_p2", exchange); #endif /* * Do not create SA's for informational exchanges. * XXX How to handle new group mode? */ if (exchange->type != ISAKMP_EXCH_INFO && exchange->type != ISAKMP_EXCH_TRANSACTION) { /* XXX Number of SAs should come from the args structure. */ for (i = 0; i < 1; i++) if (sa_create(exchange, isakmp_sa->transport)) { exchange_free(exchange); return; } } msg = message_alloc(isakmp_sa->transport, 0, ISAKMP_HDR_SZ); msg->isakmp_sa = isakmp_sa; sa_reference(isakmp_sa); msg->extra = args; /* This needs to be done late or else get_keystate won't work right. */ msg->exchange = exchange; exchange_run(msg); } /* Out of an incoming phase 1 message, setup an exchange. */ struct exchange * exchange_setup_p1(struct message *msg, u_int32_t doi) { struct transport *t = msg->transport; struct exchange *exchange; struct sockaddr *dst; #ifdef USE_ISAKMP_CFG struct conf_list *flags; struct conf_list_node *flag; #endif char *name = 0, *policy = 0, *str; u_int32_t want_doi; u_int8_t type; /* XXX Similar code can be found in exchange_establish_p1. Share? */ /* * Unless this is an informational exchange, look up our policy for * this peer. */ type = GET_ISAKMP_HDR_EXCH_TYPE(msg->iov[0].iov_base); if (type != ISAKMP_EXCH_INFO) { /* * Find out our inbound phase 1 mode. */ t->vtbl->get_dst(t, &dst); if (sockaddr2text(dst, &str, 0) == -1) return 0; name = conf_get_str("Phase 1", str); free(str); if (name) { /* * If another phase 1 exchange is ongoing don't bother * returning the call. However, we will need to * continue responding if our phase 1 exchange is * still waiting for step 1 (i.e still half-open). */ if (exchange_lookup_active(name, 1)) return 0; } else { name = conf_get_str("Phase 1", "Default"); if (!name) { log_print("exchange_setup_p1: no \"Default\" " "tag in [Phase 1] section"); return 0; } } policy = conf_get_str(name, "Configuration"); if (!policy) policy = CONF_DFLT_TAG_PHASE1_CONFIG; /* Figure out the DOI. */ str = conf_get_str(policy, "DOI"); if (!str || strcasecmp(str, "IPSEC") == 0) want_doi = IPSEC_DOI_IPSEC; else if (strcasecmp(str, "ISAKMP") == 0) want_doi = ISAKMP_DOI_ISAKMP; else { log_print("exchange_setup_p1: " "DOI \"%s\" unsupported", str); return 0; } if (want_doi != doi) { /* XXX Should I tell what DOI I got? */ log_print("exchange_setup_p1: expected %s DOI", str); return 0; } /* What exchange type do we want? */ str = conf_get_str(policy, "EXCHANGE_TYPE"); if (!str) { log_print("exchange_setup_p1: no \"EXCHANGE_TYPE\" " "tag in [%s] section", policy); return 0; } type = constant_value(isakmp_exch_cst, str); if (!type) { log_print("exchange_setup_p1: " "unknown exchange type %s", str); return 0; } if (type != GET_ISAKMP_HDR_EXCH_TYPE(msg->iov[0].iov_base)) { log_print("exchange_setup_p1: " "expected exchange type %s got %s", str, constant_name(isakmp_exch_cst, GET_ISAKMP_HDR_EXCH_TYPE(msg->iov[0].iov_base))); return 0; } } exchange = exchange_create(1, 0, doi, type); if (!exchange) return 0; exchange->name = name ? strdup(name) : 0; if (name && !exchange->name) { log_error("exchange_setup_p1: strdup (\"%s\") failed", name); exchange_free(exchange); return 0; } exchange->policy = policy; #ifdef USE_ISAKMP_CFG if (name && (flags = conf_get_list(name, "Flags")) != NULL) { for (flag = TAILQ_FIRST(&flags->fields); flag; flag = TAILQ_NEXT(flag, link)) if (strcasecmp(flag->field, "ikecfg") == 0) { struct exchange_finalization_node *node; node = calloc(1, (unsigned long)sizeof *node); if (!node) { log_print("exchange_establish_p1: " "calloc (1, %lu) failed", (unsigned long)sizeof(*node)); exchange_free(exchange); return 0; } /* * Insert this finalization inbetween * the original. */ node->first = 0; node->first_arg = 0; node->second_arg = name; exchange_add_finalization(exchange, exchange_establish_transaction, node); } conf_free_list(flags); } #endif cookie_gen(msg->transport, exchange, exchange->cookies + ISAKMP_HDR_ICOOKIE_LEN, ISAKMP_HDR_RCOOKIE_LEN); GET_ISAKMP_HDR_ICOOKIE(msg->iov[0].iov_base, exchange->cookies); exchange_enter(exchange); #ifdef USE_DEBUG exchange_dump("exchange_setup_p1", exchange); #endif return exchange; } /* Out of an incoming phase 2 message, setup an exchange. */ struct exchange * exchange_setup_p2(struct message *msg, u_int8_t doi) { struct exchange *exchange; u_int8_t *buf = msg->iov[0].iov_base; exchange = exchange_create(2, 0, doi, GET_ISAKMP_HDR_EXCH_TYPE(buf)); if (!exchange) return 0; GET_ISAKMP_HDR_ICOOKIE(buf, exchange->cookies); GET_ISAKMP_HDR_RCOOKIE(buf, exchange->cookies + ISAKMP_HDR_ICOOKIE_LEN); GET_ISAKMP_HDR_MESSAGE_ID(buf, exchange->message_id); #if defined (USE_NAT_TRAVERSAL) if (msg->isakmp_sa->flags & SA_FLAG_NAT_T_ENABLE) exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE; if (msg->isakmp_sa->flags & SA_FLAG_NAT_T_KEEPALIVE) exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE; #endif exchange_enter(exchange); #ifdef USE_DEBUG exchange_dump("exchange_setup_p2", exchange); #endif return exchange; } /* Dump interesting data about an exchange. */ static void exchange_dump_real(char *header, struct exchange *exchange, int class, int level) { struct sa *sa; char buf[LOG_SIZE]; /* Don't risk overflowing the final log buffer. */ size_t bufsize_max = LOG_SIZE - strlen(header) - 32; LOG_DBG((class, level, "%s: %p %s %s policy %s phase %d doi %d exchange %d step %d", header, exchange, exchange->name ? exchange->name : "", exchange->policy ? exchange->policy : "", exchange->initiator ? "initiator" : "responder", exchange->phase, exchange->doi->id, exchange->type, exchange->step)); LOG_DBG((class, level, "%s: icookie %08x%08x rcookie %08x%08x", header, decode_32(exchange->cookies), decode_32(exchange->cookies + 4), decode_32(exchange->cookies + 8), decode_32(exchange->cookies + 12))); /* Include phase 2 SA list for this exchange */ if (exchange->phase == 2) { snprintf(buf, bufsize_max, "sa_list "); for (sa = TAILQ_FIRST(&exchange->sa_list); sa && strlen(buf) < bufsize_max; sa = TAILQ_NEXT(sa, next)) snprintf(buf + strlen(buf), bufsize_max - strlen(buf), "%p ", sa); if (sa) strlcat(buf, "...", bufsize_max); } else buf[0] = '\0'; LOG_DBG((class, level, "%s: msgid %08x %s", header, decode_32(exchange->message_id), buf)); } #ifdef USE_DEBUG static void exchange_dump(char *header, struct exchange *exchange) { exchange_dump_real(header, exchange, LOG_EXCHANGE, 10); } #endif void exchange_report(void) { struct exchange *exchange; int i; for (i = 0; i <= bucket_mask; i++) for (exchange = LIST_FIRST(&exchange_tab[i]); exchange; exchange = LIST_NEXT(exchange, link)) exchange_dump_real("exchange_report", exchange, LOG_REPORT, 0); } /* * Release all resources this exchange is using *except* for the "death" * event. When removing an exchange from the expiration handler that event * will be dealt with therein instead. */ static void exchange_free_aux(void *v_exch) { struct exchange *exchange = v_exch; struct sa *sa, *next_sa; struct cert_handler *handler; LOG_DBG((LOG_EXCHANGE, 80, "exchange_free_aux: freeing exchange %p", exchange)); if (exchange->last_received) message_free(exchange->last_received); if (exchange->last_sent) message_free(exchange->last_sent); if (exchange->in_transit && exchange->in_transit != exchange->last_sent) message_free(exchange->in_transit); if (exchange->nonce_i) free(exchange->nonce_i); if (exchange->nonce_r) free(exchange->nonce_r); if (exchange->id_i) free(exchange->id_i); if (exchange->id_r) free(exchange->id_r); if (exchange->keystate) free(exchange->keystate); if (exchange->doi && exchange->doi->free_exchange_data) exchange->doi->free_exchange_data(exchange->data); if (exchange->data) free(exchange->data); if (exchange->name) free(exchange->name); if (exchange->recv_cert) { handler = cert_get(exchange->recv_certtype); if (handler) handler->cert_free(exchange->recv_cert); } if (exchange->sent_cert) { handler = cert_get(exchange->sent_certtype); if (handler) handler->cert_free(exchange->sent_cert); } if (exchange->recv_key) key_free(exchange->recv_keytype, ISAKMP_KEYTYPE_PUBLIC, exchange->recv_key); if (exchange->keynote_key) free(exchange->keynote_key); /* This is just a string */ #if defined (POLICY) || defined (KEYNOTE) if (exchange->policy_id != -1) kn_close(exchange->policy_id); #endif exchange_free_aca_list(exchange); LIST_REMOVE(exchange, link); /* Tell potential finalize routine we never got there. */ if (exchange->finalize) exchange->finalize(exchange, exchange->finalize_arg, 1); /* Remove any SAs that have not been disassociated from us. */ for (sa = TAILQ_FIRST(&exchange->sa_list); sa; sa = next_sa) { next_sa = TAILQ_NEXT(sa, next); /* One for the reference in exchange->sa_list. */ sa_release(sa); /* And two more for the expiration and SA linked list. */ sa_free(sa); } free(exchange); } /* Release all resources this exchange is using. */ void exchange_free(struct exchange *exchange) { if (exchange->death) timer_remove_event(exchange->death); exchange_free_aux(exchange); } /* * Upgrade the phase 1 exchange and its ISAKMP SA with the rcookie of our * peer (found in his recently sent message MSG). */ void exchange_upgrade_p1(struct message *msg) { struct exchange *exchange = msg->exchange; LIST_REMOVE(exchange, link); GET_ISAKMP_HDR_RCOOKIE(msg->iov[0].iov_base, exchange->cookies + ISAKMP_HDR_ICOOKIE_LEN); exchange_enter(exchange); sa_isakmp_upgrade(msg); } static int exchange_check_old_sa(struct sa *sa, void *v_arg) { struct sa *new_sa = v_arg; char res1[1024]; if (sa == new_sa || !sa->name || !(sa->flags & SA_FLAG_READY) || (sa->flags & SA_FLAG_REPLACED)) return 0; if (sa->phase != new_sa->phase || new_sa->name == 0 || strcasecmp(sa->name, new_sa->name)) return 0; if (sa->initiator) strlcpy(res1, ipsec_decode_ids("%s %s", sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), sizeof res1); else strlcpy(res1, ipsec_decode_ids("%s %s", sa->id_r, sa->id_r_len, sa->id_i, sa->id_i_len, 0), sizeof res1); LOG_DBG((LOG_EXCHANGE, 30, "checking whether new SA replaces existing SA with IDs %s", res1)); if (new_sa->initiator) return strcasecmp(res1, ipsec_decode_ids("%s %s", new_sa->id_i, new_sa->id_i_len, new_sa->id_r, new_sa->id_r_len, 0)) == 0; else return strcasecmp(res1, ipsec_decode_ids("%s %s", new_sa->id_r, new_sa->id_r_len, new_sa->id_i, new_sa->id_i_len, 0)) == 0; } void exchange_finalize(struct message *msg) { struct exchange *exchange = msg->exchange; struct sa *sa, *old_sa; struct proto *proto; struct conf_list *attrs; struct conf_list_node *attr; struct cert_handler *handler; int i; char *id_doi, *id_trp; #ifdef USE_DEBUG exchange_dump("exchange_finalize", exchange); #endif /* Copy the ID from phase 1 to exchange or phase 2 SA. */ if (msg->isakmp_sa) { if (exchange->id_i && exchange->id_r) { ipsec_clone_id(&msg->isakmp_sa->id_i, &msg->isakmp_sa->id_i_len, exchange->id_i, exchange->id_i_len); ipsec_clone_id(&msg->isakmp_sa->id_r, &msg->isakmp_sa->id_r_len, exchange->id_r, exchange->id_r_len); } else if (msg->isakmp_sa->id_i && msg->isakmp_sa->id_r) { ipsec_clone_id(&exchange->id_i, &exchange->id_i_len, msg->isakmp_sa->id_i, msg->isakmp_sa->id_i_len); ipsec_clone_id(&exchange->id_r, &exchange->id_r_len, msg->isakmp_sa->id_r, msg->isakmp_sa->id_r_len); } } /* * Walk over all the SAs and noting them as ready. If we set the * COMMIT bit, tell the peer each SA is connected. * * XXX The decision should really be based on if a SA was installed * successfully. */ for (sa = TAILQ_FIRST(&exchange->sa_list); sa; sa = TAILQ_NEXT(sa, next)) { /* Move over the name to the SA. */ sa->name = exchange->name ? strdup(exchange->name) : 0; if (exchange->flags & EXCHANGE_FLAG_I_COMMITTED) { for (proto = TAILQ_FIRST(&sa->protos); proto; proto = TAILQ_NEXT(proto, link)) for (i = 0; i < 2; i++) message_send_notification(exchange->last_received, msg->isakmp_sa, ISAKMP_NOTIFY_STATUS_CONNECTED, proto, i); } /* * Locate any old SAs and mark them replaced * (SA_FLAG_REPLACED). */ sa->initiator = exchange->initiator; while ((old_sa = sa_find(exchange_check_old_sa, sa)) != 0) sa_mark_replaced(old_sa); /* Setup the SA flags. */ sa->flags |= SA_FLAG_READY; if (exchange->name) { attrs = conf_get_list(exchange->name, "Flags"); if (attrs) { for (attr = TAILQ_FIRST(&attrs->fields); attr; attr = TAILQ_NEXT(attr, link)) sa->flags |= sa_flag(attr->field); conf_free_list(attrs); } /* 'Connections' should stay alive. */ if (connection_exist(exchange->name)) { sa->flags |= SA_FLAG_STAYALIVE; /* * ISAKMP SA of this connection should also * stay alive. */ if (exchange->phase == 2 && msg->isakmp_sa) msg->isakmp_sa->flags |= SA_FLAG_STAYALIVE; } } sa->seq = exchange->seq; sa->exch_type = exchange->type; } /* * If this was an phase 1 SA negotiation, save the keystate in the * ISAKMP SA structure for future initialization of phase 2 exchanges' * keystates. Also save the Phase 1 ID and authentication * information. */ if (exchange->phase == 1 && msg->isakmp_sa) { msg->isakmp_sa->keystate = exchange->keystate; exchange->keystate = 0; msg->isakmp_sa->recv_certtype = exchange->recv_certtype; msg->isakmp_sa->sent_certtype = exchange->sent_certtype; msg->isakmp_sa->recv_keytype = exchange->recv_keytype; msg->isakmp_sa->recv_key = exchange->recv_key; msg->isakmp_sa->keynote_key = exchange->keynote_key; /* Reset. */ exchange->recv_key = 0; exchange->keynote_key = 0; msg->isakmp_sa->policy_id = exchange->policy_id; exchange->policy_id = -1; msg->isakmp_sa->initiator = exchange->initiator; if (exchange->recv_certtype && exchange->recv_cert) { handler = cert_get(exchange->recv_certtype); if (handler) msg->isakmp_sa->recv_cert = handler->cert_dup(exchange->recv_cert); } if (exchange->sent_certtype) { handler = cert_get(exchange->sent_certtype); if (handler) msg->isakmp_sa->sent_cert = handler->cert_dup(exchange->sent_cert); } if (exchange->doi) id_doi = exchange->doi->decode_ids( "initiator id %s, responder id %s", exchange->id_i, exchange->id_i_len, exchange->id_r, exchange->id_r_len, 0); else id_doi = ""; if (msg->isakmp_sa->transport) id_trp = msg->isakmp_sa->transport->vtbl->decode_ids(msg->isakmp_sa->transport); else id_trp = ""; #if defined (USE_NAT_TRAVERSAL) if (exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) msg->isakmp_sa->flags |= SA_FLAG_NAT_T_ENABLE; if (exchange->flags & EXCHANGE_FLAG_NAT_T_KEEPALIVE) msg->isakmp_sa->flags |= SA_FLAG_NAT_T_KEEPALIVE; #endif LOG_DBG((LOG_EXCHANGE, 10, "exchange_finalize: phase 1 done: %s, %s", id_doi, id_trp)); log_verbose("isakmpd: phase 1 done: %s, %s", id_doi, id_trp); } exchange->doi->finalize_exchange(msg); if (exchange->finalize) exchange->finalize(exchange, exchange->finalize_arg, 0); exchange->finalize = 0; /* * There is no reason to keep the SAs connected to us anymore, in fact * it can hurt us if we have short lifetimes on the SAs and we try * to call exchange_report, where the SA list will be walked and * references to freed SAs can occur. */ while (TAILQ_FIRST(&exchange->sa_list)) { sa = TAILQ_FIRST(&exchange->sa_list); if (exchange->id_i && exchange->id_r) { ipsec_clone_id(&sa->id_i, &sa->id_i_len, exchange->id_i, exchange->id_i_len); ipsec_clone_id(&sa->id_r, &sa->id_r_len, exchange->id_r, exchange->id_r_len); } TAILQ_REMOVE(&exchange->sa_list, sa, next); sa_release(sa); } /* If we have nothing to retransmit we can safely remove ourselves. */ if (!exchange->last_sent) exchange_free(exchange); } /* Stash a nonce into the exchange data. */ static int exchange_nonce(struct exchange *exchange, int peer, size_t nonce_sz, u_int8_t *buf) { u_int8_t **nonce; size_t *nonce_len; int initiator = exchange->initiator ^ peer; char header[32]; nonce = initiator ? &exchange->nonce_i : &exchange->nonce_r; nonce_len = initiator ? &exchange->nonce_i_len : &exchange->nonce_r_len; *nonce_len = nonce_sz; *nonce = malloc(nonce_sz); if (!*nonce) { log_error("exchange_nonce: malloc (%lu) failed", (unsigned long)nonce_sz); return -1; } memcpy(*nonce, buf, nonce_sz); snprintf(header, sizeof header, "exchange_nonce: NONCE_%c", initiator ? 'i' : 'r'); LOG_DBG_BUF((LOG_EXCHANGE, 80, header, *nonce, nonce_sz)); return 0; } /* Generate our NONCE. */ int exchange_gen_nonce(struct message *msg, size_t nonce_sz) { struct exchange *exchange = msg->exchange; u_int8_t *buf; buf = malloc(ISAKMP_NONCE_SZ + nonce_sz); if (!buf) { log_error("exchange_gen_nonce: malloc (%lu) failed", ISAKMP_NONCE_SZ + (unsigned long)nonce_sz); return -1; } getrandom(buf + ISAKMP_NONCE_DATA_OFF, nonce_sz); if (message_add_payload(msg, ISAKMP_PAYLOAD_NONCE, buf, ISAKMP_NONCE_SZ + nonce_sz, 1)) { free(buf); return -1; } return exchange_nonce(exchange, 0, nonce_sz, buf + ISAKMP_NONCE_DATA_OFF); } /* Save the peer's NONCE. */ int exchange_save_nonce(struct message *msg) { struct payload *noncep; struct exchange *exchange = msg->exchange; noncep = payload_first(msg, ISAKMP_PAYLOAD_NONCE); noncep->flags |= PL_MARK; return exchange_nonce(exchange, 1, GET_ISAKMP_GEN_LENGTH(noncep->p) - ISAKMP_NONCE_DATA_OFF, noncep->p + ISAKMP_NONCE_DATA_OFF); } /* Save the peer's CERT REQuests. */ int exchange_save_certreq(struct message *msg) { struct payload *cp = payload_first(msg, ISAKMP_PAYLOAD_CERT_REQ); struct exchange *exchange = msg->exchange; struct certreq_aca *aca; for (; cp; cp = TAILQ_NEXT(cp, link)) { cp->flags |= PL_MARK; aca = certreq_decode(GET_ISAKMP_CERTREQ_TYPE(cp->p), cp->p + ISAKMP_CERTREQ_AUTHORITY_OFF, GET_ISAKMP_GEN_LENGTH(cp->p) - ISAKMP_CERTREQ_AUTHORITY_OFF); if (aca) TAILQ_INSERT_TAIL(&exchange->aca_list, aca, link); } return 0; } /* Free the list of pending CERTREQs. */ void exchange_free_aca_list(struct exchange *exchange) { struct certreq_aca *aca; for (aca = TAILQ_FIRST(&exchange->aca_list); aca; aca = TAILQ_FIRST(&exchange->aca_list)) { if (aca->data) { if (aca->handler) aca->handler->free_aca(aca->data); free(aca->data); } TAILQ_REMOVE(&exchange->aca_list, aca, link); free(aca); } } /* Obtain certificates from acceptable certification authority. */ int exchange_add_certs(struct message *msg) { struct exchange *exchange = msg->exchange; struct certreq_aca *aca; u_int8_t *cert = 0, *new_cert = 0; u_int32_t certlen; u_int8_t *id; size_t id_len; id = exchange->initiator ? exchange->id_r : exchange->id_i; id_len = exchange->initiator ? exchange->id_r_len : exchange->id_i_len; /* * Without IDs we cannot handle this yet. Keep the aca_list around for * a later step/retry to see if we got the ID by then. * Note: A 'return -1' breaks X509-auth interop in the responder case * with some IPsec clients that send CERTREQs early (such as * the SSH Sentinel). */ if (!id) return 0; for (aca = TAILQ_FIRST(&exchange->aca_list); aca; aca = TAILQ_NEXT(aca, link)) { /* XXX? If we can not satisfy a CERTREQ we drop the message. */ if (!aca->handler->cert_obtain(id, id_len, aca->data, &cert, &certlen)) { log_print("exchange_add_certs: could not obtain cert " "for a type %d cert request", aca->id); if (cert) free(cert); return -1; } new_cert = realloc(cert, ISAKMP_CERT_SZ + certlen); if (!new_cert) { log_error("exchange_add_certs: realloc (%p, %d) " "failed", cert, ISAKMP_CERT_SZ + certlen); if (cert) free(cert); return -1; } cert = new_cert; memmove(cert + ISAKMP_CERT_DATA_OFF, cert, certlen); SET_ISAKMP_CERT_ENCODING(cert, aca->id); if (message_add_payload(msg, ISAKMP_PAYLOAD_CERT, cert, ISAKMP_CERT_SZ + certlen, 1)) { free(cert); return -1; } } /* We dont need the CERT REQs any more, they are answered. */ exchange_free_aca_list(exchange); return 0; } static void exchange_establish_finalize(struct exchange *exchange, void *arg, int fail) { char *name = arg; LOG_DBG((LOG_EXCHANGE, 20, "exchange_establish_finalize: " "finalizing exchange %p with arg %p (%s) & fail = %d", exchange, arg, name ? name : "", fail)); if (!fail) exchange_establish(name, 0, 0); free(name); } /* * Establish an exchange named NAME, and record the FINALIZE function * taking ARG as an argument to be run after the exchange is ready. */ void exchange_establish(char *name, void (*finalize)(struct exchange *, void *, int), void *arg) { struct transport *transport; struct sa *isakmp_sa; struct exchange *exchange; int phase; char *trpt, *peer; phase = conf_get_num(name, "Phase", 0); /* * First of all, never try to establish anything if another exchange * of the same kind is running. */ exchange = exchange_lookup_by_name(name, phase); if (exchange) { LOG_DBG((LOG_EXCHANGE, 40, "exchange_establish: %s exchange already exists as %p", name, exchange)); exchange_add_finalization(exchange, finalize, arg); return; } switch (phase) { case 1: trpt = conf_get_str(name, "Transport"); if (!trpt) { /* Phase 1 transport defaults to "udp". */ trpt = ISAKMP_DEFAULT_TRANSPORT; } transport = transport_create(trpt, name); if (!transport) { log_print("exchange_establish: transport \"%s\" for " "peer \"%s\" could not be created", trpt, name); return; } exchange_establish_p1(transport, 0, 0, name, 0, finalize, arg); break; case 2: peer = conf_get_str(name, "ISAKMP-peer"); if (!peer) { log_print("exchange_establish: No ISAKMP-peer given " "for \"%s\"", name); return; } isakmp_sa = sa_lookup_by_name(peer, 1); if (!isakmp_sa) { name = strdup(name); if (!name) { log_error("exchange_establish: " "strdup (\"%s\") failed", name); return; } if (conf_get_num(peer, "Phase", 0) != 1) { log_print("exchange_establish: " "[%s]:ISAKMP-peer's (%s) phase is not 1", name, peer); return; } /* * XXX We're losing information here (what the * original finalize routine was. As a result, if an * exchange does not manage to get through, there may * be application-specific information that won't get * cleaned up, since no error signalling will be done. * This is the case with dynamic SAs and PFKEY. */ exchange_establish(peer, exchange_establish_finalize, name); exchange = exchange_lookup_by_name(peer, 1); /* * If the exchange was correctly initialized, add the * original finalization routine; otherwise, call it * directly. */ if (exchange) exchange_add_finalization(exchange, finalize, arg); else finalize(0, arg, 1); /* Indicate failure */ return; } else exchange_establish_p2(isakmp_sa, 0, name, 0, finalize, arg); break; default: log_print("exchange_establish: " "peer \"%s\" does not have a correct phase (%d)", name, phase); break; } } isakmpd-20041012.orig/ike_auth.h0000644000175000017500000000355310133045740016525 0ustar jdivejdive00000000000000/* $OpenBSD: ike_auth.h,v 1.5 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: ike_auth.h,v 1.5 1998/08/16 19:55:24 provos Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _IKE_AUTH_H_ #define _IKE_AUTH_H_ #include struct exchange; struct ike_auth { u_int16_t id; u_int8_t *(*gen_skeyid) (struct exchange *, size_t *); int (*decode_hash) (struct message *); int (*encode_hash) (struct message *); }; extern struct ike_auth *ike_auth_get(u_int16_t); #endif /* _IKE_AUTH_H_ */ isakmpd-20041012.orig/key.c0000644000175000017500000001137310133045740015516 0ustar jdivejdive00000000000000/* $OpenBSD: key.c,v 1.19 2004/09/17 13:53:08 ho Exp $ */ /* * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) * * Copyright (c) 2000-2001 Angelos D. Keromytis. * * Permission to use, copy, and modify this software with or without fee * is hereby granted, provided that this entire notice is included in * all copies of any software which is or includes a copy or * modification of this software. * You may use this code under the GNU public license if you so wish. Please * contribute changes back to the authors under this freer than GPL license * so that we may further the use of strong encryption without limitations to * all. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR * PURPOSE. */ #include #include #include "sysdep.h" #include "key.h" #include "libcrypto.h" #include "log.h" #include "util.h" #ifdef USE_X509 #include "x509.h" #endif void key_free(int type, int private, void *key) { switch (type) { case ISAKMP_KEY_PASSPHRASE: free(key); break; case ISAKMP_KEY_RSA: #ifdef USE_X509 RSA_free(key); break; #endif case ISAKMP_KEY_NONE: default: log_error("key_free: unknown/unsupportedkey type %d", type); break; } } /* Convert from internal form to serialized */ void key_serialize(int type, int private, void *key, u_int8_t **data, size_t *datalenp) { #ifdef USE_X509 u_int8_t *p; size_t datalen; #endif switch (type) { case ISAKMP_KEY_PASSPHRASE: *datalenp = strlen((char *)key); *data = (u_int8_t *)strdup((char *)key); break; case ISAKMP_KEY_RSA: #ifdef USE_X509 switch (private) { case ISAKMP_KEYTYPE_PUBLIC: datalen = i2d_RSAPublicKey((RSA *)key, NULL); *data = p = malloc(datalen); if (!p) { log_error("key_serialize: malloc (%lu) failed", (unsigned long)datalen); return; } *datalenp = i2d_RSAPublicKey((RSA *) key, &p); break; case ISAKMP_KEYTYPE_PRIVATE: datalen = i2d_RSAPrivateKey((RSA *)key, NULL); *data = p = malloc(datalen); if (!p) { log_error("key_serialize: malloc (%lu) failed", (unsigned long)datalen); return; } *datalenp = i2d_RSAPrivateKey((RSA *)key, &p); break; } #endif break; default: log_error("key_serialize: unknown/unsupported key type %d", type); break; } } /* Convert from serialized to printable */ char * key_printable(int type, int private, u_int8_t *data, int datalen) { #ifdef USE_X509 char *s; int i; #endif switch (type) { case ISAKMP_KEY_PASSPHRASE: return strdup((char *)data); case ISAKMP_KEY_RSA: #ifdef USE_X509 s = malloc(datalen * 2 + 1); if (!s) { log_error("key_printable: malloc (%d) failed", datalen * 2 + 1); return 0; } for (i = 0; i < datalen; i++) snprintf(s + (2 * i), 2 * (datalen - i) + 1, "%02x", data[i]); return s; #endif default: log_error("key_printable: unknown/unsupported key type %d", type); return 0; } } /* Convert from serialized to internal. */ void * key_internalize(int type, int private, u_int8_t *data, int datalen) { switch (type) { case ISAKMP_KEY_PASSPHRASE: return strdup((char *)data); case ISAKMP_KEY_RSA: #ifdef USE_X509 switch (private) { #if OPENSSL_VERSION_NUMBER >= 0x00907000L case ISAKMP_KEYTYPE_PUBLIC: return d2i_RSAPublicKey(NULL, (const u_int8_t **)&data, datalen); case ISAKMP_KEYTYPE_PRIVATE: return d2i_RSAPrivateKey(NULL, (const u_int8_t **)&data, datalen); #else case ISAKMP_KEYTYPE_PUBLIC: return d2i_RSAPublicKey(NULL, &data, datalen); case ISAKMP_KEYTYPE_PRIVATE: return d2i_RSAPrivateKey(NULL, &data, datalen); #endif default: log_error("key_internalize: not public or private " "RSA key passed"); return 0; } break; #endif /* USE_X509 */ default: log_error("key_internalize: unknown/unsupported key type %d", type); break; } return 0; } /* Convert from printable to serialized */ void key_from_printable(int type, int private, char *key, u_int8_t **data, u_int32_t *datalenp) { #ifdef USE_X509 u_int32_t datalen; #endif switch (type) { case ISAKMP_KEY_PASSPHRASE: *datalenp = strlen(key); *data = (u_int8_t *) strdup(key); break; case ISAKMP_KEY_RSA: #ifdef USE_X509 datalen = (strlen(key) + 1) / 2; /* Round up, just in case */ *data = malloc(datalen); if (!*data) { log_error("key_from_printable: malloc (%d) failed", datalen); *datalenp = 0; return; } *datalenp = hex2raw(key, *data, datalen); break; #endif default: log_error("key_from_printable: " "unknown/unsupported key type %d", type); *data = NULL; *datalenp = 0; break; } } isakmpd-20041012.orig/sa.c0000644000175000017500000007524610133045740015342 0ustar jdivejdive00000000000000/* $OpenBSD: sa.c,v 1.86 2004/08/10 15:59:10 ho Exp $ */ /* $EOM: sa.c,v 1.112 2000/12/12 00:22:52 niklas Exp $ */ /* * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2001 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2003, 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #if defined (USE_KEYNOTE) || defined (USE_POLICY) #include #include #endif /* USE_KEYNOTE || USE_POLICY */ #include "sysdep.h" #include "attribute.h" #include "conf.h" #include "connection.h" #include "cookie.h" #include "doi.h" #include "exchange.h" #include "isakmp.h" #include "log.h" #include "message.h" #include "monitor.h" #include "sa.h" #include "timer.h" #include "transport.h" #include "util.h" #include "cert.h" #include "policy.h" #include "key.h" #include "ipsec.h" #include "ipsec_num.h" /* Initial number of bits from the cookies used as hash. */ #define INITIAL_BUCKET_BITS 6 /* * Don't try to use more bits than this as a hash. * We only XOR 16 bits so going above that means changing the code below * too. */ #define MAX_BUCKET_BITS 16 #if 0 static void sa_resize(void); #endif static void sa_soft_expire(void *); static void sa_hard_expire(void *); static LIST_HEAD(sa_list, sa) *sa_tab; /* Works both as a maximum index and a mask. */ static int bucket_mask; void sa_init(void) { int i; bucket_mask = (1 << INITIAL_BUCKET_BITS) - 1; sa_tab = malloc((bucket_mask + 1) * sizeof(struct sa_list)); if (!sa_tab) log_fatal("sa_init: malloc (%lu) failed", (bucket_mask + 1) * (unsigned long)sizeof(struct sa_list)); for (i = 0; i <= bucket_mask; i++) LIST_INIT(&sa_tab[i]); } #if 0 /* XXX We don't yet resize. */ static void sa_resize(void) { int new_mask = (bucket_mask + 1) * 2 - 1; int i; struct sa_list *new_tab; new_tab = realloc(sa_tab, (new_mask + 1) * sizeof(struct sa_list)); if (!new_tab) return; sa_tab = new_tab; for (i = bucket_mask + 1; i <= new_mask; i++) LIST_INIT(&sa_tab[i]); bucket_mask = new_mask; /* XXX Rehash existing entries. */ } #endif /* Lookup an SA with the help from a user-supplied checking function. */ struct sa * sa_find(int (*check) (struct sa*, void *), void *arg) { int i; struct sa *sa; for (i = 0; i <= bucket_mask; i++) for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = LIST_NEXT(sa, link)) if (check(sa, arg)) { LOG_DBG((LOG_SA, 90, "sa_find: return SA %p", sa)); return sa; } LOG_DBG((LOG_SA, 90, "sa_find: no SA matched query")); return 0; } /* Check if SA is an ISAKMP SA with an initiator cookie equal to ICOOKIE. */ static int sa_check_icookie(struct sa *sa, void *icookie) { return sa->phase == 1 && memcmp(sa->cookies, icookie, ISAKMP_HDR_ICOOKIE_LEN) == 0; } /* Lookup an ISAKMP SA out of just the initiator cookie. */ struct sa * sa_lookup_from_icookie(u_int8_t *cookie) { return sa_find(sa_check_icookie, cookie); } struct name_phase_arg { char *name; u_int8_t phase; }; /* Check if SA has the name and phase given by V_ARG. */ static int sa_check_name_phase(struct sa *sa, void *v_arg) { struct name_phase_arg *arg = v_arg; return sa->name && strcasecmp(sa->name, arg->name) == 0 && sa->phase == arg->phase && !(sa->flags & SA_FLAG_REPLACED); } /* Lookup an SA by name, case-independent, and phase. */ struct sa * sa_lookup_by_name(char *name, int phase) { struct name_phase_arg arg; arg.name = name; arg.phase = phase; return sa_find(sa_check_name_phase, &arg); } struct addr_arg { struct sockaddr *addr; socklen_t len; int phase; int flags; }; /* * Check if SA is ready and has a peer with an address equal the one given * by V_ADDR. Furthermore if we are searching for a specific phase, check * that too. */ static int sa_check_peer(struct sa *sa, void *v_addr) { struct addr_arg *addr = v_addr; struct sockaddr *dst; if (!sa->transport || (sa->flags & SA_FLAG_READY) == 0 || (addr->phase && addr->phase != sa->phase)) return 0; sa->transport->vtbl->get_dst(sa->transport, &dst); return sysdep_sa_len(dst) == addr->len && memcmp(dst, addr->addr, sysdep_sa_len(dst)) == 0; } struct dst_isakmpspi_arg { struct sockaddr *dst; u_int8_t *spi; /* must be ISAKMP_SPI_SIZE octets */ }; /* * Check if SA matches what we are asking for through V_ARG. It has to * be a finished phaes 1 (ISAKMP) SA. */ static int isakmp_sa_check(struct sa *sa, void *v_arg) { struct dst_isakmpspi_arg *arg = v_arg; struct sockaddr *dst, *src; if (sa->phase != 1 || !(sa->flags & SA_FLAG_READY)) return 0; /* verify address is either src or dst for this sa */ sa->transport->vtbl->get_dst(sa->transport, &dst); sa->transport->vtbl->get_src(sa->transport, &src); if (memcmp(src, arg->dst, sysdep_sa_len(src)) && memcmp(dst, arg->dst, sysdep_sa_len(dst))) return 0; /* match icookie+rcookie against spi */ if (memcmp(sa->cookies, arg->spi, ISAKMP_HDR_COOKIES_LEN) == 0) return 1; return 0; } /* * Find an ISAKMP SA with a "name" of DST & SPI. */ struct sa * sa_lookup_isakmp_sa(struct sockaddr *dst, u_int8_t *spi) { struct dst_isakmpspi_arg arg; arg.dst = dst; arg.spi = spi; return sa_find(isakmp_sa_check, &arg); } /* Lookup a ready SA by the peer's address. */ struct sa * sa_lookup_by_peer(struct sockaddr *dst, socklen_t dstlen) { struct addr_arg arg; arg.addr = dst; arg.len = dstlen; arg.phase = 0; return sa_find(sa_check_peer, &arg); } /* Lookup a ready ISAKMP SA given its peer address. */ struct sa * sa_isakmp_lookup_by_peer(struct sockaddr *dst, socklen_t dstlen) { struct addr_arg arg; arg.addr = dst; arg.len = dstlen; arg.phase = 1; return sa_find(sa_check_peer, &arg); } int sa_enter(struct sa *sa) { u_int16_t bucket = 0; int i; u_int8_t *cp; /* XXX We might resize if we are crossing a certain threshold */ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2) { cp = sa->cookies + i; /* Doing it this way avoids alignment problems. */ bucket ^= cp[0] | cp[1] << 8; } for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2) { cp = sa->message_id + i; /* Doing it this way avoids alignment problems. */ bucket ^= cp[0] | cp[1] << 8; } bucket &= bucket_mask; LIST_INSERT_HEAD(&sa_tab[bucket], sa, link); sa_reference(sa); LOG_DBG((LOG_SA, 70, "sa_enter: SA %p added to SA list", sa)); return 1; } /* * Lookup the SA given by the header fields MSG. PHASE2 is false when * looking for phase 1 SAa and true otherwise. */ struct sa * sa_lookup_by_header(u_int8_t *msg, int phase2) { return sa_lookup(msg + ISAKMP_HDR_COOKIES_OFF, phase2 ? msg + ISAKMP_HDR_MESSAGE_ID_OFF : 0); } /* * Lookup the SA given by the COOKIES and possibly the MESSAGE_ID unless * a null pointer, meaning we are looking for phase 1 SAs. */ struct sa * sa_lookup(u_int8_t *cookies, u_int8_t *message_id) { u_int16_t bucket = 0; int i; struct sa *sa; u_int8_t *cp; /* * We use the cookies to get bits to use as an index into sa_tab, as at * least one (our cookie) is a good hash, xoring all the bits, 16 at a * time, and then masking, should do. Doing it this way means we can * validate cookies very fast thus delimiting the effects of "Denial of * service"-attacks using packet flooding. */ for (i = 0; i < ISAKMP_HDR_COOKIES_LEN; i += 2) { cp = cookies + i; /* Doing it this way avoids alignment problems. */ bucket ^= cp[0] | cp[1] << 8; } if (message_id) for (i = 0; i < ISAKMP_HDR_MESSAGE_ID_LEN; i += 2) { cp = message_id + i; /* Doing it this way avoids alignment problems. */ bucket ^= cp[0] | cp[1] << 8; } bucket &= bucket_mask; for (sa = LIST_FIRST(&sa_tab[bucket]); sa && (memcmp(cookies, sa->cookies, ISAKMP_HDR_COOKIES_LEN) != 0 || (message_id && memcmp(message_id, sa->message_id, ISAKMP_HDR_MESSAGE_ID_LEN) != 0) || (!message_id && !zero_test(sa->message_id, ISAKMP_HDR_MESSAGE_ID_LEN))); sa = LIST_NEXT(sa, link)) ; return sa; } /* Create an SA. */ int sa_create(struct exchange *exchange, struct transport *t) { struct sa *sa; /* * We want the SA zeroed for sa_free to be able to find out what fields * have been filled-in. */ sa = calloc(1, sizeof *sa); if (!sa) { log_error("sa_create: calloc (1, %lu) failed", (unsigned long)sizeof *sa); return -1; } sa->transport = t; if (t) transport_reference(t); sa->phase = exchange->phase; memcpy(sa->cookies, exchange->cookies, ISAKMP_HDR_COOKIES_LEN); memcpy(sa->message_id, exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); sa->doi = exchange->doi; sa->policy_id = -1; if (sa->doi->sa_size) { /* * Allocate the DOI-specific structure and initialize it to * zeroes. */ sa->data = calloc(1, sa->doi->sa_size); if (!sa->data) { log_error("sa_create: calloc (1, %lu) failed", (unsigned long)sa->doi->sa_size); free(sa); return -1; } } TAILQ_INIT(&sa->protos); sa_enter(sa); TAILQ_INSERT_TAIL(&exchange->sa_list, sa, next); sa_reference(sa); LOG_DBG((LOG_SA, 60, "sa_create: sa %p phase %d added to exchange %p (%s)", sa, sa->phase, exchange, exchange->name ? exchange->name : "")); return 0; } /* * Dump the internal state of SA to the report channel, with HEADER * prepended to each line. */ void sa_dump(int cls, int level, char *header, struct sa *sa) { struct proto *proto; char spi_header[80]; int i; LOG_DBG((cls, level, "%s: %p %s phase %d doi %d flags 0x%x", header, sa, sa->name ? sa->name : "", sa->phase, sa->doi->id, sa->flags)); LOG_DBG((cls, level, "%s: icookie %08x%08x rcookie %08x%08x", header, decode_32(sa->cookies), decode_32(sa->cookies + 4), decode_32(sa->cookies + 8), decode_32(sa->cookies + 12))); LOG_DBG((cls, level, "%s: msgid %08x refcnt %d", header, decode_32(sa->message_id), sa->refcnt)); LOG_DBG((cls, level, "%s: life secs %llu kb %llu", header, sa->seconds, sa->kilobytes)); for (proto = TAILQ_FIRST(&sa->protos); proto; proto = TAILQ_NEXT(proto, link)) { LOG_DBG((cls, level, "%s: suite %d proto %d", header, proto->no, proto->proto)); LOG_DBG((cls, level, "%s: spi_sz[0] %d spi[0] %p spi_sz[1] %d spi[1] %p", header, proto->spi_sz[0], proto->spi[0], proto->spi_sz[1], proto->spi[1])); LOG_DBG((cls, level, "%s: %s, %s", header, !sa->doi ? "" : sa->doi->decode_ids("initiator id: %s, responder id: %s", sa->id_i, sa->id_i_len, sa->id_r, sa->id_r_len, 0), !sa->transport ? "" : sa->transport->vtbl->decode_ids(sa->transport))); for (i = 0; i < 2; i++) if (proto->spi[i]) { snprintf(spi_header, sizeof spi_header, "%s: spi[%d]", header, i); LOG_DBG_BUF((cls, level, spi_header, proto->spi[i], proto->spi_sz[i])); } } } /* * Display the SA's two SPI values. */ static void report_spi(FILE *fd, const u_int8_t *buf, size_t sz, int spi) { #define SBUFSZ (2 * 32 + 9) char s[SBUFSZ]; size_t i, j; for (i = j = 0; i < sz;) { snprintf(s + j, sizeof s - j, "%02x", buf[i++]); j += 2; if (i % 4 == 0) { if (i % 32 == 0) { s[j] = '\0'; fprintf(fd, "%s", s); j = 0; } else s[j++] = ' '; } } if (j) { s[j] = '\0'; fprintf(fd, "SPI %d: %s\n", spi, s); } } /* * Display the transform names to file. * Structure is taken from pf_key_v2.c, pf_key_v2_set_spi. * Transform names are taken from /usr/src/sys/crypto/xform.c. */ static void report_proto(FILE *fd, struct proto *proto) { struct ipsec_proto *iproto = proto->data; int keylen, hashlen; switch (proto->proto) { case IPSEC_PROTO_IPSEC_ESP: keylen = ipsec_esp_enckeylength(proto); hashlen = ipsec_esp_authkeylength(proto); fprintf(fd, "Transform: IPsec ESP\n"); fprintf(fd, "Encryption key length: %d\n", keylen); fprintf(fd, "Authentication key length: %d\n", hashlen); fprintf(fd, "Encryption algorithm: "); switch (proto->id) { case IPSEC_ESP_DES: case IPSEC_ESP_DES_IV32: case IPSEC_ESP_DES_IV64: fprintf(fd, "DES\n"); break; case IPSEC_ESP_3DES: fprintf(fd, "3DES\n"); break; case IPSEC_ESP_AES: fprintf(fd, "AES-128 (CBC)\n"); break; case IPSEC_ESP_AES_128_CTR: fprintf(fd, "AES-128 (CTR)\n"); break; case IPSEC_ESP_CAST: fprintf(fd, "Cast-128\n"); break; case IPSEC_ESP_BLOWFISH: fprintf(fd, "Blowfish\n"); break; default: fprintf(fd, "unknown (%d)\n", proto->id); } fprintf(fd, "Authentication algorithm: "); switch (iproto->auth) { case IPSEC_AUTH_HMAC_MD5: fprintf(fd, "HMAC-MD5\n"); break; case IPSEC_AUTH_HMAC_SHA: fprintf(fd, "HMAC-SHA1\n"); break; case IPSEC_AUTH_HMAC_RIPEMD: fprintf(fd, "HMAC-RIPEMD-160\n"); break; case IPSEC_AUTH_HMAC_SHA2_256: fprintf(fd, "HMAC-SHA2-256\n"); break; case IPSEC_AUTH_HMAC_SHA2_384: fprintf(fd, "HMAC-SHA2-384\n"); break; case IPSEC_AUTH_HMAC_SHA2_512: fprintf(fd, "HMAC-SHA2-512\n"); break; case IPSEC_AUTH_DES_MAC: case IPSEC_AUTH_KPDK: /* XXX We should be supporting KPDK */ fprintf(fd, "unknown (%d)", iproto->auth); break; default: fprintf(fd, "none\n"); } break; case IPSEC_PROTO_IPSEC_AH: hashlen = ipsec_ah_keylength(proto); fprintf(fd, "Transform: IPsec AH\n"); fprintf(fd, "Encryption not used.\n"); fprintf(fd, "Authentication key length: %d\n", hashlen); fprintf(fd, "Authentication algorithm: "); switch (proto->id) { case IPSEC_AH_MD5: fprintf(fd, "HMAC-MD5\n"); break; case IPSEC_AH_SHA: fprintf(fd, "HMAC-SHA1\n"); break; case IPSEC_AH_RIPEMD: fprintf(fd, "HMAC-RIPEMD-160\n"); break; case IPSEC_AH_SHA2_256: fprintf(fd, "HMAC-SHA2-256\n"); break; case IPSEC_AH_SHA2_384: fprintf(fd, "HMAC-SHA2-384\n"); break; case IPSEC_AH_SHA2_512: fprintf(fd, "HMAC-SHA2-512\n"); break; default: fprintf(fd, "unknown (%d)", proto->id); } break; default: fprintf(fd, "report_proto: invalid proto %d\n", proto->proto); } } /* Report all the SAs to the report channel. */ void sa_report(void) { struct sa *sa; int i; for (i = 0; i <= bucket_mask; i++) for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = LIST_NEXT(sa, link)) sa_dump(LOG_REPORT, 0, "sa_report", sa); } /* * Print an SA's connection details to file SA_FILE. */ static void sa_dump_all(FILE *fd, struct sa *sa) { struct proto *proto; int i; /* SA name and phase. */ fprintf(fd, "SA name: %s", sa->name ? sa->name : ""); fprintf(fd, " (Phase %d)\n", sa->phase); /* Source and destination IPs. */ fprintf(fd, sa->transport == NULL ? "" : sa->transport->vtbl->decode_ids(sa->transport)); fprintf(fd, "\n"); /* Transform information. */ for (proto = TAILQ_FIRST(&sa->protos); proto; proto = TAILQ_NEXT(proto, link)) { /* SPI values. */ for (i = 0; i < 2; i++) if (proto->spi[i]) report_spi(fd, proto->spi[i], proto->spi_sz[i], i); else fprintf(fd, "SPI %d not defined.", i); /* Proto values. */ report_proto(fd, proto); /* SA separator. */ fprintf(fd, "\n"); } } /* Report info of all SAs to file 'fd'. */ void sa_report_all(FILE *fd) { struct sa *sa; int i; for (i = 0; i <= bucket_mask; i++) for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = LIST_NEXT(sa, link)) if (sa->phase == 1) fprintf(fd, "SA name: none (phase 1)\n\n"); else sa_dump_all(fd, sa); } /* Free the protocol structure pointed to by PROTO. */ void proto_free(struct proto *proto) { struct proto_attr *pa; struct sa *sa = proto->sa; int i; for (i = 0; i < 2; i++) if (proto->spi[i]) { if (sa->doi->delete_spi) sa->doi->delete_spi(sa, proto, i); free(proto->spi[i]); } TAILQ_REMOVE(&sa->protos, proto, link); if (proto->data) { if (sa->doi && sa->doi->free_proto_data) sa->doi->free_proto_data(proto->data); free(proto->data); } if (proto->xf_cnt) while ((pa = TAILQ_FIRST(&proto->xfs)) != NULL) { if (pa->attrs) free(pa->attrs); TAILQ_REMOVE(&proto->xfs, pa, next); free(pa); } LOG_DBG((LOG_SA, 90, "proto_free: freeing %p", proto)); free(proto); } /* Release all resources this SA is using. */ void sa_free(struct sa *sa) { if (sa->death) { timer_remove_event(sa->death); sa->death = 0; sa->refcnt--; } if (sa->soft_death) { timer_remove_event(sa->soft_death); sa->soft_death = 0; sa->refcnt--; } sa_remove(sa); } /* Remove the SA from the hash table of live SAs. */ void sa_remove(struct sa *sa) { LIST_REMOVE(sa, link); LOG_DBG((LOG_SA, 70, "sa_remove: SA %p removed from SA list", sa)); sa_release(sa); } /* Raise the reference count of SA. */ void sa_reference(struct sa *sa) { sa->refcnt++; LOG_DBG((LOG_SA, 80, "sa_reference: SA %p now has %d references", sa, sa->refcnt)); } /* Release a reference to SA. */ void sa_release(struct sa *sa) { struct cert_handler *handler; struct proto *proto; LOG_DBG((LOG_SA, 80, "sa_release: SA %p had %d references", sa, sa->refcnt)); if (--sa->refcnt) return; LOG_DBG((LOG_SA, 60, "sa_release: freeing SA %p", sa)); while ((proto = TAILQ_FIRST(&sa->protos)) != 0) proto_free(proto); if (sa->data) { if (sa->doi && sa->doi->free_sa_data) sa->doi->free_sa_data(sa->data); free(sa->data); } if (sa->id_i) free(sa->id_i); if (sa->id_r) free(sa->id_r); if (sa->recv_cert) { handler = cert_get(sa->recv_certtype); if (handler) handler->cert_free(sa->recv_cert); } if (sa->sent_cert) { handler = cert_get(sa->sent_certtype); if (handler) handler->cert_free(sa->sent_cert); } if (sa->recv_key) key_free(sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC, sa->recv_key); if (sa->keynote_key) free(sa->keynote_key); /* This is just a string */ #if defined (USE_POLICY) || defined (USE_KEYNOTE) if (sa->policy_id != -1) kn_close(sa->policy_id); #endif if (sa->name) free(sa->name); if (sa->keystate) free(sa->keystate); #if defined (USE_NAT_TRAVERSAL) if (sa->nat_t_keepalive) timer_remove_event(sa->nat_t_keepalive); #endif #if defined (USE_DPD) if (sa->dpd_event) timer_remove_event(sa->dpd_event); #endif if (sa->transport) transport_release(sa->transport); free(sa); } /* * Rehash the ISAKMP SA this MSG is negotiating with the responder cookie * filled in. */ void sa_isakmp_upgrade(struct message *msg) { struct sa *sa = TAILQ_FIRST(&msg->exchange->sa_list); sa_remove(sa); GET_ISAKMP_HDR_RCOOKIE(msg->iov[0].iov_base, sa->cookies + ISAKMP_HDR_ICOOKIE_LEN); /* * We don't install a transport in the initiator case as we don't know * what local address will be chosen. Do it now instead. */ sa->transport = msg->transport; transport_reference(sa->transport); sa_enter(sa); } #define ATTRS_SIZE (IKE_ATTR_BLOCK_SIZE + 1) /* XXX Should be dynamic. */ struct attr_validation_state { u_int8_t *attrp[ATTRS_SIZE]; u_int8_t checked[ATTRS_SIZE]; int phase; /* IKE (1) or IPSEC (2) attrs? */ int mode; /* 0 = 'load', 1 = check */ }; /* Validate an attribute. Return 0 on match. */ static int sa_validate_xf_attrs(u_int16_t type, u_int8_t *value, u_int16_t len, void *arg) { struct attr_validation_state *avs = (struct attr_validation_state *)arg; LOG_DBG((LOG_SA, 95, "sa_validate_xf_attrs: phase %d mode %d type %d " "len %d", avs->phase, avs->mode, type, len)); /* Make sure the phase and type are valid. */ if (avs->phase == 1) { if (type < IKE_ATTR_ENCRYPTION_ALGORITHM || type > IKE_ATTR_BLOCK_SIZE) return 1; } else if (avs->phase == 2) { if (type < IPSEC_ATTR_SA_LIFE_TYPE || type > IPSEC_ATTR_ECN_TUNNEL) return 1; } else return 1; if (avs->mode == 0) { /* Load attrs. */ avs->attrp[type] = value; return 0; } /* Checking for a missing attribute is an immediate failure. */ if (!avs->attrp[type]) return 1; /* Match the loaded attribute against this one, mark it as checked. */ avs->checked[type]++; return memcmp(avs->attrp[type], value, len); } /* * This function is used to validate the returned proposal (protection suite) * we get from the responder against a proposal we sent. Only run as initiator. * We return 0 if a match is found (in any transform of this proposal), 1 * otherwise. Also see note in sa_add_transform() below. */ static int sa_validate_proto_xf(struct proto *match, struct payload *xf, int phase) { struct attr_validation_state *avs; struct proto_attr *pa; int found = 0; size_t i; u_int8_t xf_id; if (!match->xf_cnt) return 0; if (match->proto != GET_ISAKMP_PROP_PROTO(xf->context->p)) { LOG_DBG((LOG_SA, 70, "sa_validate_proto_xf: proto %p (#%d) " "protocol mismatch", match, match->no)); return 1; } avs = (struct attr_validation_state *)calloc(1, sizeof *avs); if (!avs) { log_error("sa_validate_proto_xf: calloc (1, %lu)", (unsigned long)sizeof *avs); return 1; } avs->phase = phase; /* Load the "proposal candidate" attribute set. */ (void) attribute_map(xf->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF, GET_ISAKMP_GEN_LENGTH(xf->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, sa_validate_xf_attrs, avs); xf_id = GET_ISAKMP_TRANSFORM_ID(xf->p); /* Check against the transforms we suggested. */ avs->mode++; for (pa = TAILQ_FIRST(&match->xfs); pa && !found; pa = TAILQ_NEXT(pa, next)) { if (xf_id != GET_ISAKMP_TRANSFORM_ID(pa->attrs)) continue; memset(avs->checked, 0, sizeof avs->checked); if (attribute_map(pa->attrs + ISAKMP_TRANSFORM_SA_ATTRS_OFF, pa->len - ISAKMP_TRANSFORM_SA_ATTRS_OFF, sa_validate_xf_attrs, avs) == 0) found++; LOG_DBG((LOG_SA, 80, "sa_validate_proto_xf: attr_map " "xf %p proto %p pa %p found %d", xf, match, pa, found)); if (!found) continue; /* * Require all attributes present and checked. XXX perhaps * not? */ for (i = 0; i < sizeof avs->checked; i++) if (avs->attrp[i] && !avs->checked[i]) found = 0; LOG_DBG((LOG_SA, 80, "sa_validate_proto_xf: req_attr " "xf %p proto %p pa %p found %d", xf, match, pa, found)); } free(avs); return found ? 0 : 1; } /* * Register the chosen transform XF into SA. As a side effect set PROTOP * to point at the corresponding proto structure. INITIATOR is true if we * are the initiator. */ int sa_add_transform(struct sa *sa, struct payload *xf, int initiator, struct proto **protop) { struct proto *proto; struct payload *prop = xf->context; *protop = 0; if (!initiator) { proto = calloc(1, sizeof *proto); if (!proto) log_error("sa_add_transform: calloc (1, %lu) failed", (unsigned long)sizeof *proto); } else { /* * RFC 2408, section 4.2 states the responder SHOULD use the * proposal number from the initiator (i.e us), in it's * selected proposal to make this lookup easier. Most vendors * follow this. One noted exception is the CiscoPIX (and * perhaps other Cisco products). * * We start by matching on the proposal number, as before. */ for (proto = TAILQ_FIRST(&sa->protos); proto && proto->no != GET_ISAKMP_PROP_NO(prop->p); proto = TAILQ_NEXT(proto, link)) ; /* * If we did not find a match, search through all proposals * and xforms. */ if (!proto || sa_validate_proto_xf(proto, xf, sa->phase) != 0) for (proto = TAILQ_FIRST(&sa->protos); proto && sa_validate_proto_xf(proto, xf, sa->phase) != 0; proto = TAILQ_NEXT(proto, link)) ; } if (!proto) return -1; *protop = proto; /* Allocate DOI-specific part. */ if (!initiator) { proto->data = calloc(1, sa->doi->proto_size); if (!proto->data) { log_error("sa_add_transform: calloc (1, %lu) failed", (unsigned long)sa->doi->proto_size); goto cleanup; } } proto->no = GET_ISAKMP_PROP_NO(prop->p); proto->proto = GET_ISAKMP_PROP_PROTO(prop->p); proto->spi_sz[0] = GET_ISAKMP_PROP_SPI_SZ(prop->p); if (proto->spi_sz[0]) { proto->spi[0] = malloc(proto->spi_sz[0]); if (!proto->spi[0]) goto cleanup; memcpy(proto->spi[0], prop->p + ISAKMP_PROP_SPI_OFF, proto->spi_sz[0]); } proto->chosen = xf; proto->sa = sa; proto->id = GET_ISAKMP_TRANSFORM_ID(xf->p); if (!initiator) TAILQ_INSERT_TAIL(&sa->protos, proto, link); /* Let the DOI get at proto for initializing its own data. */ if (sa->doi->proto_init) sa->doi->proto_init(proto, 0); LOG_DBG((LOG_SA, 80, "sa_add_transform: " "proto %p no %d proto %d chosen %p sa %p id %d", proto, proto->no, proto->proto, proto->chosen, proto->sa, proto->id)); return 0; cleanup: if (!initiator) { if (proto->data) free(proto->data); free(proto); } *protop = 0; return -1; } /* Delete an SA. Tell the peer if NOTIFY is set. */ void sa_delete(struct sa *sa, int notify) { /* Don't bother notifying of Phase 1 SA deletes. */ if (sa->phase != 1 && notify) message_send_delete(sa); sa_free(sa); } /* Teardown all SAs. */ void sa_teardown_all(void) { int i; struct sa *sa, *next = 0; LOG_DBG((LOG_SA, 70, "sa_teardown_all:")); /* Get Phase 2 SAs. */ for (i = 0; i <= bucket_mask; i++) for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = next) { next = LIST_NEXT(sa, link); if (sa->phase == 2) { /* * Teardown the phase 2 SAs by name, similar * to ui_teardown. */ LOG_DBG((LOG_SA, 70, "sa_teardown_all: tearing down SA %s", sa->name)); connection_teardown(sa->name); sa_delete(sa, 1); } } } /* * This function will get called when we are closing in on the death time of SA */ static void sa_soft_expire(void *v_sa) { struct sa *sa = v_sa; sa->soft_death = 0; sa_release(sa); if ((sa->flags & (SA_FLAG_STAYALIVE | SA_FLAG_REPLACED)) == SA_FLAG_STAYALIVE) exchange_establish(sa->name, 0, 0); else /* * Start to watch the use of this SA, so a renegotiation can * happen as soon as it is shown to be alive. */ sa->flags |= SA_FLAG_FADING; } /* SA has passed its best before date. */ static void sa_hard_expire(void *v_sa) { struct sa *sa = v_sa; sa->death = 0; sa_release(sa); if ((sa->flags & (SA_FLAG_STAYALIVE | SA_FLAG_REPLACED)) == SA_FLAG_STAYALIVE) exchange_establish(sa->name, 0, 0); sa_delete(sa, 1); } void sa_reinit(void) { struct sa *sa; char *tag; int i; /* For now; only do this if we have the proper tag configured. */ tag = conf_get_str("General", "Renegotiate-on-HUP"); if (!tag) return; LOG_DBG((LOG_SA, 30, "sa_reinit: renegotiating active connections")); /* * Get phase 2 SAs. Soft expire those without active exchanges. Do * not touch a phase 2 SA where the soft expiration is not set, ie. * the SA is not yet established. */ for (i = 0; i <= bucket_mask; i++) for (sa = LIST_FIRST(&sa_tab[i]); sa; sa = LIST_NEXT(sa, link)) if (sa->phase == 2) if (exchange_lookup_by_name(sa->name, sa->phase) == 0 && sa->soft_death) { timer_remove_event(sa->soft_death); sa_soft_expire(sa); } } /* * Get an SA attribute's flag value out of textual description. */ int sa_flag(char *attr) { static struct sa_flag_map { char *name; int flag; } sa_flag_map[] = { { "active-only", SA_FLAG_ACTIVE_ONLY }, /* * Below this point are flags that are internal to the * implementation. */ { "__ondemand", SA_FLAG_ONDEMAND }, { "ikecfg", SA_FLAG_IKECFG }, }; size_t i; for (i = 0; i < sizeof sa_flag_map / sizeof sa_flag_map[0]; i++) if (strcasecmp(attr, sa_flag_map[i].name) == 0) return sa_flag_map[i].flag; log_print("sa_flag: attribute \"%s\" unknown", attr); return 0; } /* Mark SA as replaced. */ void sa_mark_replaced(struct sa *sa) { LOG_DBG((LOG_SA, 60, "sa_mark_replaced: SA %p (%s) marked as replaced", sa, sa->name ? sa->name : "unnamed")); sa->flags |= SA_FLAG_REPLACED; } /* * Setup expiration timers for SA. This is used for ISAKMP SAs, but also * possible to use for application SAs if the application does not deal * with expirations itself. An example is the Linux FreeS/WAN KLIPS IPsec * stack. */ int sa_setup_expirations(struct sa *sa) { struct timeval expiration; u_int64_t seconds = sa->seconds; /* * Set the soft timeout to a random percentage between 85 & 95 of * the negotiated lifetime to break strictly synchronized * renegotiations. This works better when the randomization is on the * order of processing plus network-roundtrip times, or larger. * I.e. it depends on configuration and negotiated lifetimes. * It is not good to do the decrease on the hard timeout, because then * we may drop our SA before our peer. * XXX Better scheme to come? */ if (!sa->soft_death) { gettimeofday(&expiration, 0); /* * XXX This should probably be configuration controlled * somehow. */ seconds = sa->seconds * (850 + sysdep_random() % 100) / 1000; LOG_DBG((LOG_TIMER, 95, "sa_setup_expirations: SA %p soft timeout in %llu seconds", sa, seconds)); expiration.tv_sec += seconds; sa->soft_death = timer_add_event("sa_soft_expire", sa_soft_expire, sa, &expiration); if (!sa->soft_death) { /* If we don't give up we might start leaking... */ sa_delete(sa, 1); return -1; } sa_reference(sa); } if (!sa->death) { gettimeofday(&expiration, 0); LOG_DBG((LOG_TIMER, 95, "sa_setup_expirations: SA %p hard timeout in %llu seconds", sa, sa->seconds)); expiration.tv_sec += sa->seconds; sa->death = timer_add_event("sa_hard_expire", sa_hard_expire, sa, &expiration); if (!sa->death) { /* If we don't give up we might start leaking... */ sa_delete(sa, 1); return -1; } sa_reference(sa); } return 0; } isakmpd-20041012.orig/policy.h0000644000175000017500000000571010133045740016230 0ustar jdivejdive00000000000000/* $OpenBSD: policy.h,v 1.15 2004/06/25 20:25:34 hshoexer Exp $ */ /* $EOM: policy.h,v 1.12 2000/09/28 12:53:27 niklas Exp $ */ /* * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2000 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _POLICY_H_ #define _POLICY_H_ #if defined (USE_KEYNOTE) #define CREDENTIAL_FILE "credentials" #define PRIVATE_KEY_FILE "private_key" #endif extern int ignore_policy; extern int policy_asserts_num; extern int x509_policy_asserts_num; extern int x509_policy_asserts_num_alloc; extern char **policy_asserts; extern char **x509_policy_asserts; extern struct exchange *policy_exchange; extern struct sa *policy_sa; extern struct sa *policy_isakmp_sa; extern void policy_init(void); extern char *policy_callback(char *); extern int keynote_cert_init(void); extern void *keynote_cert_get(u_int8_t *, u_int32_t); extern int keynote_cert_validate(void *); extern int keynote_cert_insert(int, void *); extern void keynote_cert_free(void *); extern int keynote_certreq_validate(u_int8_t *, u_int32_t); extern void *keynote_certreq_decode(u_int8_t *, u_int32_t); extern void keynote_free_aca(void *); extern int keynote_cert_obtain(u_int8_t *, size_t, void *, u_int8_t **, u_int32_t *); extern int keynote_cert_get_subjects(void *, int *, u_int8_t ***, u_int32_t **); extern int keynote_cert_get_key(void *, void *); extern void *keynote_cert_dup(void *); extern void keynote_serialize(void *, u_int8_t **, u_int32_t *); extern char *keynote_printable(void *); extern void *keynote_from_printable(char *); #endif /* _POLICY_H_ */ isakmpd-20041012.orig/connection.c0000644000175000017500000002762010133045740017067 0ustar jdivejdive00000000000000/* $OpenBSD: connection.c,v 1.29 2004/06/14 09:55:41 ho Exp $ */ /* $EOM: connection.c,v 1.28 2000/11/23 12:21:18 niklas Exp $ */ /* * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999 Hakan 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include "sysdep.h" #include "conf.h" #include "connection.h" #include "doi.h" #include "ipsec.h" /* XXX isakmp.h only required for compare_ids(). */ #include "isakmp.h" #include "log.h" #include "timer.h" #include "util.h" /* How often should we check that connections we require to be up, are up? */ #define CHECK_INTERVAL 60 static void connection_passive_teardown(char *); struct connection { TAILQ_ENTRY(connection) link; char *name; struct event *ev; }; struct connection_passive { TAILQ_ENTRY(connection_passive) link; char *name; u_int8_t *local_id, *remote_id; size_t local_sz, remote_sz; #if 0 /* XXX Potential additions to 'connection_passive'. */ char *isakmp_peer; struct sa *sa; /* XXX "Soft" ref to active sa? */ struct timeval sa_expiration; /* XXX *sa may expire. */ #endif }; TAILQ_HEAD(connection_head, connection) connections; TAILQ_HEAD(passive_head, connection_passive) connections_passive; /* * This is where we setup all the connections we want there right from the * start. */ void connection_init(void) { struct conf_list *conns, *attrs; struct conf_list_node *conn, *attr = NULL; /* * Passive connections normally include: all "active" connections that * are not flagged "Active-Only", plus all connections listed in * the 'Passive-Connections' list. */ TAILQ_INIT(&connections); TAILQ_INIT(&connections_passive); conns = conf_get_list("Phase 2", "Connections"); if (conns) { for (conn = TAILQ_FIRST(&conns->fields); conn; conn = TAILQ_NEXT(conn, link)) { if (connection_setup(conn->field)) log_print("connection_init: could not setup " "\"%s\"", conn->field); /* XXX Break/abort here if connection_setup failed? */ /* * XXX This code (i.e. the attribute lookup) seems * like a likely candidate for factoring out into a * function of its own. */ attrs = conf_get_list(conn->field, "Flags"); if (attrs) for (attr = TAILQ_FIRST(&attrs->fields); attr; attr = TAILQ_NEXT(attr, link)) if (strcasecmp("active-only", attr->field) == 0) break; if (!attrs || (attrs && !attr)) if (connection_record_passive(conn->field)) log_print("connection_init: could not " "record connection \"%s\"", conn->field); if (attrs) conf_free_list(attrs); } conf_free_list(conns); } conns = conf_get_list("Phase 2", "Passive-Connections"); if (conns) { for (conn = TAILQ_FIRST(&conns->fields); conn; conn = TAILQ_NEXT(conn, link)) if (connection_record_passive(conn->field)) log_print("connection_init: could not record " "passive connection \"%s\"", conn->field); conf_free_list(conns); } } /* Check the connection in VCONN and schedule another check later. */ static void connection_checker(void *vconn) { struct timeval now; struct connection *conn = vconn; gettimeofday(&now, 0); now.tv_sec += conf_get_num("General", "check-interval", CHECK_INTERVAL); conn->ev = timer_add_event("connection_checker", connection_checker, conn, &now); if (!conn->ev) log_print("connection_checker: could not add timer event"); sysdep_connection_check(conn->name); } /* Find the connection named NAME. */ static struct connection * connection_lookup(char *name) { struct connection *conn; for (conn = TAILQ_FIRST(&connections); conn; conn = TAILQ_NEXT(conn, link)) if (strcasecmp(conn->name, name) == 0) return conn; return 0; } /* Does the connection named NAME exist? */ int connection_exist(char *name) { return (connection_lookup(name) != 0); } /* Find the passive connection named NAME. */ static struct connection_passive * connection_passive_lookup_by_name(char *name) { struct connection_passive *conn; for (conn = TAILQ_FIRST(&connections_passive); conn; conn = TAILQ_NEXT(conn, link)) if (strcasecmp(conn->name, name) == 0) return conn; return 0; } /* * IDs of different types cannot be the same. * XXX Rename to ipsec_compare_id, and move to ipsec.c ? */ static int compare_ids(u_int8_t *id1, u_int8_t *id2, size_t idlen) { int id1_type, id2_type; id1_type = GET_ISAKMP_ID_TYPE(id1); id2_type = GET_ISAKMP_ID_TYPE(id2); return id1_type == id2_type ? memcmp(id1 + ISAKMP_ID_DATA_OFF, id2 + ISAKMP_ID_DATA_OFF, idlen - ISAKMP_ID_DATA_OFF) : -1; } /* Find the connection named with matching IDs. */ char * connection_passive_lookup_by_ids(u_int8_t *id1, u_int8_t *id2) { struct connection_passive *conn; for (conn = TAILQ_FIRST(&connections_passive); conn; conn = TAILQ_NEXT(conn, link)) { if (!conn->remote_id) continue; /* * If both IDs match what we have saved, return the name. * Don't bother in which order they are. */ if ((compare_ids(id1, conn->local_id, conn->local_sz) == 0 && compare_ids(id2, conn->remote_id, conn->remote_sz) == 0) || (compare_ids(id1, conn->remote_id, conn->remote_sz) == 0 && compare_ids(id2, conn->local_id, conn->local_sz) == 0)) { LOG_DBG((LOG_MISC, 60, "connection_passive_lookup_by_ids: " "returned \"%s\"", conn->name)); return conn->name; } } /* * In the road warrior case, we do not know the remote ID. In that * case we will just match against the local ID. */ for (conn = TAILQ_FIRST(&connections_passive); conn; conn = TAILQ_NEXT(conn, link)) { if (!conn->remote_id) continue; if (compare_ids(id1, conn->local_id, conn->local_sz) == 0 || compare_ids(id2, conn->local_id, conn->local_sz) == 0) { LOG_DBG((LOG_MISC, 60, "connection passive_lookup_by_ids: returned \"%s\"" " only matched local id", conn->name)); return conn->name; } } LOG_DBG((LOG_MISC, 60, "connection_passive_lookup_by_ids: no match")); return 0; } /* * Setup NAME to be a connection that should be up "always", i.e. if it dies, * for whatever reason, it should be tried to be brought up, over and over * again. */ int connection_setup(char *name) { struct connection *conn = 0; struct timeval now; /* Check for trials to add duplicate connections. */ if (connection_lookup(name)) { LOG_DBG((LOG_MISC, 10, "connection_setup: cannot add \"%s\" twice", name)); return 0; } conn = calloc(1, sizeof *conn); if (!conn) { log_error("connection_setup: calloc (1, %lu) failed", (unsigned long)sizeof *conn); goto fail; } conn->name = strdup(name); if (!conn->name) { log_error("connection_setup: strdup (\"%s\") failed", name); goto fail; } gettimeofday(&now, 0); conn->ev = timer_add_event("connection_checker", connection_checker, conn, &now); if (!conn->ev) { log_print("connection_setup: could not add timer event"); goto fail; } TAILQ_INSERT_TAIL(&connections, conn, link); return 0; fail: if (conn) { if (conn->name) free(conn->name); free(conn); } return -1; } int connection_record_passive(char *name) { struct connection_passive *conn; char *local_id, *remote_id; if (connection_passive_lookup_by_name(name)) { LOG_DBG((LOG_MISC, 10, "connection_record_passive: cannot add \"%s\" twice", name)); return 0; } local_id = conf_get_str(name, "Local-ID"); if (!local_id) { log_print("connection_record_passive: " "\"Local-ID\" is missing from section [%s]", name); return -1; } /* If the remote id lookup fails we defer it to later */ remote_id = conf_get_str(name, "Remote-ID"); conn = calloc(1, sizeof *conn); if (!conn) { log_error("connection_record_passive: calloc (1, %lu) failed", (unsigned long)sizeof *conn); return -1; } conn->name = strdup(name); if (!conn->name) { log_error("connection_record_passive: strdup (\"%s\") failed", name); goto fail; } /* XXX IPsec DOI-specific. */ conn->local_id = ipsec_build_id(local_id, &conn->local_sz); if (!conn->local_id) goto fail; if (remote_id) { conn->remote_id = ipsec_build_id(remote_id, &conn->remote_sz); if (!conn->remote_id) goto fail; } else conn->remote_id = 0; TAILQ_INSERT_TAIL(&connections_passive, conn, link); LOG_DBG((LOG_MISC, 60, "connection_record_passive: passive connection \"%s\" added", conn->name)); return 0; fail: if (conn->local_id) free(conn->local_id); if (conn->name) free(conn->name); free(conn); return -1; } /* Remove the connection named NAME. */ void connection_teardown(char *name) { struct connection *conn; conn = connection_lookup(name); if (!conn) return; TAILQ_REMOVE(&connections, conn, link); timer_remove_event(conn->ev); free(conn->name); free(conn); } /* Remove the passive connection named NAME. */ static void connection_passive_teardown(char *name) { struct connection_passive *conn; conn = connection_passive_lookup_by_name(name); if (!conn) return; TAILQ_REMOVE(&connections_passive, conn, link); free(conn->name); free(conn->local_id); free(conn->remote_id); free(conn); } void connection_report(void) { struct connection *conn; struct timeval now; #ifdef USE_DEBUG struct connection_passive *pconn; struct doi *doi = doi_lookup(ISAKMP_DOI_ISAKMP); #endif gettimeofday(&now, 0); for (conn = TAILQ_FIRST(&connections); conn; conn = TAILQ_NEXT(conn, link)) LOG_DBG((LOG_REPORT, 0, "connection_report: connection %s next check %ld seconds", (conn->name ? conn->name : ""), conn->ev->expiration.tv_sec - now.tv_sec)); #ifdef USE_DEBUG for (pconn = TAILQ_FIRST(&connections_passive); pconn; pconn = TAILQ_NEXT(pconn, link)) LOG_DBG((LOG_REPORT, 0, "connection_report: passive connection %s %s", pconn->name, doi->decode_ids("local_id: %s, remote_id: %s", pconn->local_id, pconn->local_sz, pconn->remote_id, pconn->remote_sz, 1))); #endif } /* Reinitialize all connections (SIGHUP handling). */ void connection_reinit(void) { struct connection *conn, *next; struct connection_passive *pconn, *pnext; LOG_DBG((LOG_MISC, 30, "connection_reinit: reinitializing connection list")); /* Remove all present connections. */ for (conn = TAILQ_FIRST(&connections); conn; conn = next) { next = TAILQ_NEXT(conn, link); connection_teardown(conn->name); } for (pconn = TAILQ_FIRST(&connections_passive); pconn; pconn = pnext) { pnext = TAILQ_NEXT(pconn, link); connection_passive_teardown(pconn->name); } /* Setup new connections, as the (new) config directs. */ connection_init(); } isakmpd-20041012.orig/dh.h0000644000175000017500000000332610133045740015325 0ustar jdivejdive00000000000000/* $OpenBSD: dh.h,v 1.7 2004/05/14 08:42:56 hshoexer Exp $ */ /* $EOM: dh.h,v 1.4 1999/04/17 23:20:24 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _DH_H_ #define _DH_H_ #include struct group; int dh_getlen(struct group *); int dh_create_exchange(struct group *, u_int8_t *); int dh_create_shared(struct group *, u_int8_t *, u_int8_t *); #endif /* _DH_H_ */ isakmpd-20041012.orig/udp.h0000644000175000017500000000360510133045740015522 0ustar jdivejdive00000000000000/* $OpenBSD: udp.h,v 1.10 2004/08/03 10:54:09 ho Exp $ */ /* $EOM: udp.h,v 1.4 1998/12/22 02:23:43 niklas Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _UDP_H_ #define _UDP_H_ extern char *udp_default_port; extern char *udp_bind_port; extern int bind_family; #define BIND_FAMILY_INET4 0x0001 #define BIND_FAMILY_INET6 0x0002 struct transport *udp_bind(const struct sockaddr *); void udp_init(void); struct udp_transport { struct transport transport; struct sockaddr *src; struct sockaddr *dst; int s; }; #endif /* _UDP_H_ */ isakmpd-20041012.orig/isakmpd.c0000644000175000017500000003067210133045740016361 0ustar jdivejdive00000000000000/* $OpenBSD: isakmpd.c,v 1.68 2004/09/17 14:54:09 hshoexer Exp $ */ /* $EOM: isakmpd.c,v 1.54 2000/10/05 09:28:22 niklas Exp $ */ /* * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved. * Copyright (c) 1999, 2000, 2001 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "sysdep.h" #include "app.h" #include "conf.h" #include "connection.h" #include "init.h" #include "libcrypto.h" #include "log.h" #include "monitor.h" #include "sa.h" #include "timer.h" #include "transport.h" #include "udp.h" #include "ui.h" #include "util.h" #include "cert.h" #ifdef USE_POLICY #include "policy.h" #endif static void usage(void); /* * Set if -d is given, currently just for running in the foreground and log * to stderr instead of syslog. */ int debug = 0; /* Set when no policy file is found. */ int acquire_only = 0; /* * If we receive a SIGHUP signal, this flag gets set to show we need to * reconfigure ASAP. */ volatile sig_atomic_t sighupped = 0; /* * If we receive a USR1 signal, this flag gets set to show we need to dump * a report over our internal state ASAP. The file to report to is settable * via the -R parameter. */ volatile sig_atomic_t sigusr1ed = 0; static char *report_file = "/var/run/isakmpd.report"; /* * If we receive a USR2 signal, this flag gets set to show we need to * rehash our SA soft expiration timers to a uniform distribution. * XXX Perhaps this is a really bad idea? */ volatile sig_atomic_t sigusr2ed = 0; /* * If we receive a TERM signal, perform a "clean shutdown" of the daemon. * This includes to send DELETE notifications for all our active SAs. * Also on recv of an INT signal (Ctrl-C out of an '-d' session, typically). */ volatile sig_atomic_t sigtermed = 0; void daemon_shutdown_now(int); /* The default path of the PID file. */ static char *pid_file = "/var/run/isakmpd.pid"; #ifdef USE_DEBUG /* The path of the IKE packet capture log file. */ static char *pcap_file = 0; #endif static void usage(void) { fprintf(stderr, "usage: %s [-4] [-6] [-a] [-c config-file] [-d] [-D class=level]\n" " [-f fifo] [-i pid-file] [-K] [-n] [-p listen-port]\n" " [-P local-port] [-L] [-l packetlog-file] [-r seed]\n" " [-R report-file] [-v]\n", sysdep_progname()); exit(1); } static void parse_args(int argc, char *argv[]) { int ch; char *ep; #ifdef USE_DEBUG int cls, level; int do_packetlog = 0; #endif while ((ch = getopt(argc, argv, "46ac:dD:f:i:Knp:P:Ll:r:R:v")) != -1) { switch (ch) { case '4': bind_family |= BIND_FAMILY_INET4; break; case '6': bind_family |= BIND_FAMILY_INET6; break; case 'a': acquire_only++; break; case 'c': conf_path = optarg; break; case 'd': debug++; break; #ifdef USE_DEBUG case 'D': if (sscanf(optarg, "%d=%d", &cls, &level) != 2) { if (sscanf(optarg, "A=%d", &level) == 1) { for (cls = 0; cls < LOG_ENDCLASS; cls++) log_debug_cmd(cls, level); } else log_print("parse_args: -D argument " "unparseable: %s", optarg); } else log_debug_cmd(cls, level); break; #endif /* USE_DEBUG */ case 'f': ui_fifo = optarg; break; case 'i': pid_file = optarg; break; #ifdef USE_POLICY case 'K': ignore_policy++; break; #endif case 'n': app_none++; break; case 'p': udp_default_port = optarg; break; case 'P': udp_bind_port = optarg; break; #ifdef USE_DEBUG case 'l': pcap_file = optarg; /* Fallthrough intended. */ case 'L': do_packetlog++; break; #endif /* USE_DEBUG */ case 'r': seed = strtoul(optarg, &ep, 0); srandom(seed); if (*ep != '\0') log_fatal("parse_args: invalid numeric arg " "to -r (%s)", optarg); regrand = 1; break; case 'R': report_file = optarg; break; case 'v': verbose_logging = 1; break; case '?': default: usage(); } } argc -= optind; argv += optind; #ifdef USE_DEBUG if (do_packetlog && !pcap_file) pcap_file = PCAP_FILE_DEFAULT; #endif } static void sighup(int sig) { sighupped = 1; } /* Report internal state on SIGUSR1. */ static void report(void) { FILE *rfp, *old; mode_t old_umask; old_umask = umask(S_IRWXG | S_IRWXO); rfp = monitor_fopen(report_file, "w"); umask(old_umask); if (!rfp) { log_error("report: fopen (\"%s\", \"w\") failed", report_file); return; } /* Divert the log channel to the report file during the report. */ old = log_current(); log_to(rfp); ui_report("r"); log_to(old); fclose(rfp); } static void sigusr1(int sig) { sigusr1ed = 1; } /* Rehash soft expiration timers on SIGUSR2. */ static void rehash_timers(void) { #if 0 /* XXX - not yet */ log_print("SIGUSR2 received, rehashing soft expiration timers."); timer_rehash_timers(); #endif } static void sigusr2(int sig) { sigusr2ed = 1; } static int phase2_sa_check(struct sa *sa, void *arg) { return sa->phase == 2; } static void daemon_shutdown(void) { /* Perform a (protocol-wise) clean shutdown of the daemon. */ struct sa *sa; if (sigtermed == 1) { log_print("isakmpd: shutting down..."); /* Delete all active phase 2 SAs. */ while ((sa = sa_find(phase2_sa_check, NULL))) { /* Each DELETE is another (outgoing) message. */ sa_delete(sa, 1); } sigtermed++; } if (transport_prio_sendqs_empty()) { /* * When the prioritized transport sendq:s are empty, i.e all * the DELETE notifications have been sent, we can shutdown. */ #ifdef USE_DEBUG log_packet_stop(); #endif /* Remove FIFO and pid files. */ unlink(ui_fifo); unlink(pid_file); log_print("isakmpd: exit"); exit(0); } } /* Called on SIGTERM, SIGINT or by ui_shutdown_daemon(). */ void daemon_shutdown_now(int sig) { sigtermed = 1; } /* Write pid file. */ static void write_pid_file(void) { FILE *fp; /* Ignore errors. This will fail with USE_PRIVSEP. */ unlink(pid_file); fp = monitor_fopen(pid_file, "w"); if (fp != NULL) { if (fprintf(fp, "%ld\n", (long) getpid()) < 0) log_error("write_pid_file: failed to write PID to " "\"%.100s\"", pid_file); fclose(fp); } else log_fatal("write_pid_file: fopen (\"%.100s\", \"w\") failed", pid_file); } int main(int argc, char *argv[]) { fd_set *rfds, *wfds; int n, m; size_t mask_size; struct timeval tv, *timeout; #if defined (HAVE_CLOSEFROM) && (!defined (OpenBSD) || (OpenBSD >= 200405)) closefrom(STDERR_FILENO + 1); #else m = getdtablesize(); for (n = STDERR_FILENO + 1; n < m; n++) (void) close(n); #endif /* * Make sure init() won't alloc fd 0, 1 or 2, as daemon() will close * them. */ for (n = 0; n <= 2; n++) if (fcntl(n, F_GETFL, 0) == -1 && errno == EBADF) (void) open("/dev/null", n ? O_WRONLY : O_RDONLY, 0); for (n = 1; n < _NSIG; n++) signal(n, SIG_DFL); /* Log cmd line parsing and initialization errors to stderr. */ log_to(stderr); parse_args(argc, argv); log_init(debug); /* Open protocols and services databases. */ setprotoent(1); setservent(1); /* * Do a clean daemon shutdown on TERM/INT. These signals must be * initialized before monitor_init(). INT is only used with '-d'. */ signal(SIGTERM, daemon_shutdown_now); if (debug == 1) /* i.e '-dd' will skip this. */ signal(SIGINT, daemon_shutdown_now); /* Daemonize before forking unpriv'ed child */ if (!debug) if (daemon(0, 0)) log_fatal("main: daemon (0, 0) failed"); /* Set timezone before priv'separation */ tzset(); #if defined (USE_PRIVSEP) if (monitor_init(debug)) { /* The parent, with privileges enters infinite monitor loop. */ monitor_loop(debug); exit(0); /* Never reached. */ } /* Child process only from this point on, no privileges left. */ #endif init(); write_pid_file(); /* Reinitialize on HUP reception. */ signal(SIGHUP, sighup); /* Report state on USR1 reception. */ signal(SIGUSR1, sigusr1); /* Rehash soft expiration timers on USR2 reception. */ signal(SIGUSR2, sigusr2); #if defined (USE_DEBUG) /* If we wanted IKE packet capture to file, initialize it now. */ if (pcap_file != 0) log_packet_init(pcap_file); #endif /* Allocate the file descriptor sets just big enough. */ n = getdtablesize(); mask_size = howmany(n, NFDBITS) * sizeof(fd_mask); rfds = (fd_set *) malloc(mask_size); if (!rfds) log_fatal("main: malloc (%lu) failed", (unsigned long)mask_size); wfds = (fd_set *) malloc(mask_size); if (!wfds) log_fatal("main: malloc (%lu) failed", (unsigned long)mask_size); #if defined (USE_PRIVSEP) monitor_init_done(); #endif while (1) { /* If someone has sent SIGHUP to us, reconfigure. */ if (sighupped) { sighupped = 0; log_print("SIGHUP received"); reinit(); } /* and if someone sent SIGUSR1, do a state report. */ if (sigusr1ed) { sigusr1ed = 0; log_print("SIGUSR1 received"); report(); } /* and if someone sent SIGUSR2, do a timer rehash. */ if (sigusr2ed) { sigusr2ed = 0; log_print("SIGUSR2 received"); rehash_timers(); } /* * and if someone set 'sigtermed' (SIGTERM, SIGINT or via the * UI), this indicates we should start a controlled shutdown * of the daemon. * * Note: Since _one_ message is sent per iteration of this * enclosing while-loop, and we want to send a number of * DELETE notifications, we must loop atleast this number of * times. The daemon_shutdown() function starts by queueing * the DELETEs, all other calls just increments the * 'sigtermed' variable until it reaches a "safe" value, and * the daemon exits. */ if (sigtermed) daemon_shutdown(); /* Setup the descriptors to look for incoming messages at. */ memset(rfds, 0, mask_size); n = transport_fd_set(rfds); FD_SET(ui_socket, rfds); if (ui_socket + 1 > n) n = ui_socket + 1; /* * XXX Some day we might want to deal with an abstract * application class instead, with many instantiations * possible. */ if (!app_none && app_socket >= 0) { FD_SET(app_socket, rfds); if (app_socket + 1 > n) n = app_socket + 1; } /* Setup the descriptors that have pending messages to send. */ memset(wfds, 0, mask_size); m = transport_pending_wfd_set(wfds); if (m > n) n = m; /* Find out when the next timed event is. */ timeout = &tv; timer_next_event(&timeout); n = select(n, rfds, wfds, 0, timeout); if (n == -1) { if (errno != EINTR) { log_error("main: select"); /* * In order to give the unexpected error * condition time to resolve without letting * this process eat up all available CPU * we sleep for a short while. */ sleep(1); } } else if (n) { transport_handle_messages(rfds); transport_send_messages(wfds); if (FD_ISSET(ui_socket, rfds)) ui_handler(); if (!app_none && app_socket >= 0 && FD_ISSET(app_socket, rfds)) app_handler(); } timer_handle_expirations(); } } isakmpd-20041012.orig/message.c0000644000175000017500000022227010133045740016352 0ustar jdivejdive00000000000000/* $OpenBSD: message.c,v 1.89 2004/09/17 13:45:02 ho Exp $ */ /* $EOM: message.c,v 1.156 2000/10/10 12:36:39 provos Exp $ */ /* * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. * Copyright (c) 1999, 2000, 2001, 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include "sysdep.h" #include "attribute.h" #include "cert.h" #include "constants.h" #include "crypto.h" #include "doi.h" #ifdef USE_DPD #include "dpd.h" #endif #include "exchange.h" #include "field.h" #include "hash.h" #include "ipsec.h" #include "ipsec_num.h" #include "isakmp.h" #include "log.h" #include "message.h" #if defined (USE_NAT_TRAVERSAL) #include "nat_traversal.h" #endif #include "prf.h" #include "sa.h" #include "timer.h" #include "transport.h" #include "util.h" #include "virtual.h" #ifdef __GNUC__ #define INLINE __inline #else #define INLINE #endif /* A local set datatype, coincidentally fd_set suits our purpose fine. */ typedef fd_set set; #define ISSET FD_ISSET #define SET FD_SET #define ZERO FD_ZERO static int message_check_duplicate(struct message *); static int message_encrypt(struct message *); static int message_index_payload(struct message *, struct payload *, u_int8_t ,u_int8_t *); static int message_parse_transform(struct message *, struct payload *, u_int8_t, u_int8_t *); static u_int16_t message_payload_sz(u_int8_t); static int message_validate_attribute(struct message *, struct payload *); static int message_validate_cert(struct message *, struct payload *); static int message_validate_cert_req(struct message *, struct payload *); static int message_validate_delete(struct message *, struct payload *); static int message_validate_hash(struct message *, struct payload *); static int message_validate_id(struct message *, struct payload *); static int message_validate_key_exch(struct message *, struct payload *); static int message_validate_nat_d(struct message *, struct payload *); static int message_validate_nat_oa(struct message *, struct payload *); static int message_validate_nonce(struct message *, struct payload *); static int message_validate_notify(struct message *, struct payload *); static int message_validate_proposal(struct message *, struct payload *); static int message_validate_sa(struct message *, struct payload *); static int message_validate_sig(struct message *, struct payload *); static int message_validate_transform(struct message *, struct payload *); static int message_validate_vendor(struct message *, struct payload *); static void message_packet_log(struct message *); static int (*message_validate_payload[])(struct message *, struct payload *) = { message_validate_sa, message_validate_proposal, message_validate_transform, message_validate_key_exch, message_validate_id, message_validate_cert, message_validate_cert_req, message_validate_hash, message_validate_sig, message_validate_nonce, message_validate_notify, message_validate_delete, message_validate_vendor, message_validate_attribute, message_validate_nat_d, message_validate_nat_oa }; static struct field *fields[] = { isakmp_sa_fld, isakmp_prop_fld, isakmp_transform_fld, isakmp_ke_fld, isakmp_id_fld, isakmp_cert_fld, isakmp_certreq_fld, isakmp_hash_fld, isakmp_sig_fld, isakmp_nonce_fld, isakmp_notify_fld, isakmp_delete_fld, isakmp_vendor_fld, isakmp_attribute_fld, isakmp_nat_d_fld, isakmp_nat_oa_fld }; /* * These maps are used for indexing the payloads in msg->payloads[i]. * payload_revmap should be updated if the payloads in isakmp_num.cst change. * payload_map is populated during startup by message_init(). */ static u_int8_t payload_revmap[] = { ISAKMP_PAYLOAD_NONE, ISAKMP_PAYLOAD_SA, ISAKMP_PAYLOAD_PROPOSAL, ISAKMP_PAYLOAD_TRANSFORM, ISAKMP_PAYLOAD_KEY_EXCH, ISAKMP_PAYLOAD_ID, ISAKMP_PAYLOAD_CERT, ISAKMP_PAYLOAD_CERT_REQ, ISAKMP_PAYLOAD_HASH, ISAKMP_PAYLOAD_SIG, ISAKMP_PAYLOAD_NONCE, ISAKMP_PAYLOAD_NOTIFY, ISAKMP_PAYLOAD_DELETE, ISAKMP_PAYLOAD_VENDOR, ISAKMP_PAYLOAD_ATTRIBUTE, #ifdef notyet ISAKMP_PAYLOAD_SAK, ISAKMP_PAYLOAD_SAT, ISAKMP_PAYLOAD_KD, ISAKMP_PAYLOAD_SEQ, ISAKMP_PAYLOAD_POP #endif ISAKMP_PAYLOAD_NAT_D, ISAKMP_PAYLOAD_NAT_OA }; static u_int8_t payload_map[256]; u_int8_t payload_index_max; /* * Fields used for checking monotonic increasing of proposal and transform * numbers. */ static u_int8_t *last_sa = 0; static u_int32_t last_prop_no; static u_int8_t *last_prop = 0; static u_int32_t last_xf_no; /* * Allocate a message structure bound to transport T, and with a first * segment buffer sized SZ, copied from BUF if given. */ struct message * message_alloc(struct transport *t, u_int8_t *buf, size_t sz) { struct message *msg; int i; /* * We use calloc(3) because it zeroes the structure which we rely on in * message_free when determining what sub-allocations to free. */ msg = (struct message *)calloc(1, sizeof *msg); if (!msg) return 0; msg->iov = calloc(1, sizeof *msg->iov); if (!msg->iov) { message_free(msg); return 0; } msg->iov[0].iov_len = sz; msg->iov[0].iov_base = malloc(sz); if (!msg->iov[0].iov_base) { message_free(msg); return 0; } msg->iovlen = 1; if (buf) memcpy(msg->iov[0].iov_base, buf, sz); msg->nextp = (u_int8_t *)msg->iov[0].iov_base + ISAKMP_HDR_NEXT_PAYLOAD_OFF; msg->transport = t; transport_reference(t); msg->payload = (struct payload_head *)calloc(payload_index_max, sizeof *msg->payload); if (!msg->payload) { message_free(msg); return 0; } for (i = 0; i < payload_index_max; i++) TAILQ_INIT(&msg->payload[i]); TAILQ_INIT(&msg->post_send); LOG_DBG((LOG_MESSAGE, 90, "message_alloc: allocated %p", msg)); return msg; } /* * Allocate a message suitable for a reply to MSG. Just allocate an empty * ISAKMP header as the first segment. */ struct message * message_alloc_reply(struct message *msg) { struct message *reply; reply = message_alloc(msg->transport, 0, ISAKMP_HDR_SZ); reply->exchange = msg->exchange; reply->isakmp_sa = msg->isakmp_sa; if (msg->isakmp_sa) sa_reference(msg->isakmp_sa); return reply; } /* Free up all resources used by the MSG message. */ void message_free(struct message *msg) { u_int32_t i; struct payload *payload, *next; LOG_DBG((LOG_MESSAGE, 20, "message_free: freeing %p", msg)); if (!msg) return; if (msg->orig && msg->orig != (u_int8_t *) msg->iov[0].iov_base) free(msg->orig); if (msg->iov) { for (i = 0; i < msg->iovlen; i++) if (msg->iov[i].iov_base) free(msg->iov[i].iov_base); free(msg->iov); } if (msg->retrans) timer_remove_event(msg->retrans); if (msg->payload) { for (i = 0; i < payload_index_max; i++) for (payload = payload_first(msg, i); payload; payload = next) { next = TAILQ_NEXT(payload, link); free(payload); } free(msg->payload); } while (TAILQ_FIRST(&msg->post_send) != 0) TAILQ_REMOVE(&msg->post_send, TAILQ_FIRST(&msg->post_send), link); /* If we are on the send queue, remove us from there. */ if (msg->flags & MSG_IN_TRANSIT) TAILQ_REMOVE(msg->transport->vtbl->get_queue(msg), msg, link); if (msg->transport) transport_release(msg->transport); if (msg->isakmp_sa) sa_release(msg->isakmp_sa); free(msg); } /* * Generic ISAKMP parser. * MSG is the ISAKMP message to be parsed. NEXT is the type of the first * payload to be parsed, and it's pointed to by BUF. ACCEPTED_PAYLOADS * tells what payloads are accepted and FUNC is a pointer to a function * to be called for each payload found. Returns the total length of the * parsed payloads. */ static int message_parse_payloads(struct message *msg, struct payload *p, u_int8_t next, u_int8_t *buf, set *accepted_payloads, int (*func)(struct message *, struct payload *, u_int8_t, u_int8_t *)) { u_int8_t payload; u_int16_t len; int sz = 0; do { LOG_DBG((LOG_MESSAGE, 50, "message_parse_payloads: offset %ld payload %s", (long)(buf - (u_int8_t *) msg->iov[0].iov_base), constant_name(isakmp_payload_cst, next))); /* Does this payload's header fit? */ if (buf + ISAKMP_GEN_SZ > (u_int8_t *)msg->iov[0].iov_base + msg->iov[0].iov_len) { log_print("message_parse_payloads: short message"); message_drop(msg, ISAKMP_NOTIFY_UNEQUAL_PAYLOAD_LENGTHS, 0, 1, 1); return -1; } /* Ponder on the payload that is at BUF... */ payload = next; /* Look at the next payload's type. */ next = GET_ISAKMP_GEN_NEXT_PAYLOAD(buf); if (next >= ISAKMP_PAYLOAD_RESERVED_MIN && next <= ISAKMP_PAYLOAD_RESERVED_MAX) { log_print("message_parse_payloads: invalid next " "payload type %s in payload of type %d", constant_name(isakmp_payload_cst, next), payload); message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 1, 1); return -1; } /* Reserved fields in ISAKMP messages should be zero. */ if (GET_ISAKMP_GEN_RESERVED(buf) != 0) { log_print("message_parse_payloads: reserved field " "non-zero: %x", GET_ISAKMP_GEN_RESERVED(buf)); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } /* * Decode and validate the payload length field. */ len = GET_ISAKMP_GEN_LENGTH(buf); if (message_payload_sz(payload) == 0) { log_print("message_parse_payloads: unknown minimum " "payload size for payload type %s", constant_name(isakmp_payload_cst, payload)); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } if (len < message_payload_sz(payload)) { log_print("message_parse_payloads: payload too " "short: %u", len); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } if (buf + len > (u_int8_t *)msg->iov[0].iov_base + msg->iov[0].iov_len) { log_print("message_parse_payloads: payload too " "long: %u", len); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } /* Ignore most private payloads. */ if (next >= ISAKMP_PAYLOAD_PRIVATE_MIN && next != ISAKMP_PAYLOAD_NAT_D && next != ISAKMP_PAYLOAD_NAT_OA) { LOG_DBG((LOG_MESSAGE, 30, "message_parse_payloads: " "private next payload type %s in payload of " "type %d ignored", constant_name(isakmp_payload_cst, next), payload)); goto next_payload; } /* * Check if the current payload is one of the accepted ones at * this stage. */ if (!ISSET(payload, accepted_payloads)) { log_print("message_parse_payloads: payload type %s " "unexpected", constant_name(isakmp_payload_cst, payload)); message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 1, 1); return -1; } /* Call the payload handler specified by the caller. */ if (func(msg, p, payload, buf)) return -1; next_payload: /* Advance to next payload. */ buf += len; sz += len; } while (next != ISAKMP_PAYLOAD_NONE); return sz; } /* * Parse a proposal payload found in message MSG. PAYLOAD is always * ISAKMP_PAYLOAD_PROPOSAL and ignored in here. It's needed as the API for * message_parse_payloads requires it. BUF points to the proposal's * generic payload header. */ static int message_parse_proposal(struct message *msg, struct payload *p, u_int8_t payload, u_int8_t *buf) { set payload_set; /* Put the proposal into the proposal bucket. */ message_index_payload(msg, p, payload, buf); ZERO(&payload_set); SET(payload_revmap[ISAKMP_PAYLOAD_TRANSFORM], &payload_set); if (message_parse_payloads(msg, payload_last(msg, ISAKMP_PAYLOAD_PROPOSAL), ISAKMP_PAYLOAD_TRANSFORM, buf + ISAKMP_PROP_SPI_OFF + GET_ISAKMP_PROP_SPI_SZ(buf), &payload_set, message_parse_transform) == -1) return -1; return 0; } static int message_parse_transform(struct message *msg, struct payload *p, u_int8_t payload, u_int8_t *buf) { /* Put the transform into the transform bucket. */ message_index_payload(msg, p, payload, buf); LOG_DBG((LOG_MESSAGE, 50, "Transform %d's attributes", GET_ISAKMP_TRANSFORM_NO(buf))); #ifdef USE_DEBUG attribute_map(buf + ISAKMP_TRANSFORM_SA_ATTRS_OFF, GET_ISAKMP_GEN_LENGTH(buf) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, msg->exchange->doi->debug_attribute, msg); #endif return 0; } /* Check payloads for their required minimum size. */ static u_int16_t message_payload_sz(u_int8_t payload) { switch (payload) { case ISAKMP_PAYLOAD_SA: return ISAKMP_SA_SZ; case ISAKMP_PAYLOAD_PROPOSAL: return ISAKMP_PROP_SZ; case ISAKMP_PAYLOAD_TRANSFORM: return ISAKMP_TRANSFORM_SZ; case ISAKMP_PAYLOAD_KEY_EXCH: return ISAKMP_KE_SZ; case ISAKMP_PAYLOAD_ID: return ISAKMP_ID_SZ; case ISAKMP_PAYLOAD_CERT: return ISAKMP_CERT_SZ; case ISAKMP_PAYLOAD_CERT_REQ: return ISAKMP_CERTREQ_SZ; case ISAKMP_PAYLOAD_HASH: return ISAKMP_HASH_SZ; case ISAKMP_PAYLOAD_SIG: return ISAKMP_SIG_SZ; case ISAKMP_PAYLOAD_NONCE: return ISAKMP_NONCE_SZ; case ISAKMP_PAYLOAD_NOTIFY: return ISAKMP_NOTIFY_SZ; case ISAKMP_PAYLOAD_DELETE: return ISAKMP_DELETE_SZ; case ISAKMP_PAYLOAD_VENDOR: return ISAKMP_VENDOR_SZ; case ISAKMP_PAYLOAD_ATTRIBUTE: return ISAKMP_ATTRIBUTE_SZ; #if defined (USE_NAT_TRAVERSAL) case ISAKMP_PAYLOAD_NAT_D: return ISAKMP_NAT_D_SZ; case ISAKMP_PAYLOAD_NAT_OA: return ISAKMP_NAT_OA_SZ; #endif /* Not yet supported and any other unknown payloads. */ case ISAKMP_PAYLOAD_SAK: case ISAKMP_PAYLOAD_SAT: case ISAKMP_PAYLOAD_KD: case ISAKMP_PAYLOAD_SEQ: case ISAKMP_PAYLOAD_POP: default: return 0; } } /* Validate the attribute payload P in message MSG. */ static int message_validate_attribute(struct message *msg, struct payload *p) { #ifdef USE_ISAKMP_CFG /* If we don't have an exchange yet, create one. */ if (!msg->exchange) { if (zero_test((u_int8_t *) msg->iov[0].iov_base + ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN)) msg->exchange = exchange_setup_p1(msg, IPSEC_DOI_IPSEC); else msg->exchange = exchange_setup_p2(msg, IPSEC_DOI_IPSEC); if (!msg->exchange) { log_print("message_validate_attribute: can not " "create exchange"); message_free(msg); return -1; } } #endif return 0; } /* Validate the certificate payload P in message MSG. */ static int message_validate_cert(struct message *msg, struct payload *p) { if (GET_ISAKMP_CERT_ENCODING(p->p) >= ISAKMP_CERTENC_RESERVED_MIN) { message_drop(msg, ISAKMP_NOTIFY_INVALID_CERT_ENCODING, 0, 1, 1); return -1; } return 0; } /* Validate the certificate request payload P in message MSG. */ static int message_validate_cert_req(struct message *msg, struct payload *p) { struct cert_handler *cert; size_t len = GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_CERTREQ_AUTHORITY_OFF; if (GET_ISAKMP_CERTREQ_TYPE(p->p) >= ISAKMP_CERTENC_RESERVED_MIN) { message_drop(msg, ISAKMP_NOTIFY_INVALID_CERT_ENCODING, 0, 1, 1); return -1; } /* * Check the certificate types we support and if an acceptable * authority is included in the payload check if it can be decoded */ cert = cert_get(GET_ISAKMP_CERTREQ_TYPE(p->p)); if (!cert || (len && !cert->certreq_validate(p->p + ISAKMP_CERTREQ_AUTHORITY_OFF, len))) { message_drop(msg, ISAKMP_NOTIFY_CERT_TYPE_UNSUPPORTED, 0, 1, 1); return -1; } return 0; } /* * Validate the delete payload P in message MSG. As a side-effect, create * an exchange if we do not have one already. * * Note: DELETEs are only accepted as part of an INFORMATIONAL exchange. * exchange_validate() makes sure a HASH payload is present. Due to the order * of message validation functions in message_validate_payload[] we can be * sure that the HASH payload has been successfully validated at this point. */ static int message_validate_delete(struct message *msg, struct payload *p) { u_int8_t proto = GET_ISAKMP_DELETE_PROTO(p->p); struct doi *doi; struct sa *sa, *isakmp_sa; struct sockaddr *dst, *dst_isa; u_int32_t nspis = GET_ISAKMP_DELETE_NSPIS(p->p); u_int8_t *spis = (u_int8_t *)p->p + ISAKMP_DELETE_SPI_OFF; u_int32_t i; char *addr; /* Only accept authenticated DELETEs. */ if ((msg->flags & MSG_AUTHENTICATED) == 0) { log_print("message_validate_delete: " "got unauthenticated DELETE"); message_free(msg); return -1; } doi = doi_lookup(GET_ISAKMP_DELETE_DOI(p->p)); if (!doi) { log_print("message_validate_delete: DOI not supported"); message_free(msg); return -1; } /* If we don't have an exchange yet, create one. */ if (!msg->exchange) { if (zero_test((u_int8_t *) msg->iov[0].iov_base + ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN)) msg->exchange = exchange_setup_p1(msg, doi->id); else msg->exchange = exchange_setup_p2(msg, doi->id); if (!msg->exchange) { log_print("message_validate_delete: can not create " "exchange"); message_free(msg); return -1; } } /* Only accept DELETE as part of an INFORMATIONAL exchange. */ if (msg->exchange->type != ISAKMP_EXCH_INFO) { log_print("message_validate_delete: delete in exchange other " "than INFO: %s", constant_name(isakmp_exch_cst, msg->exchange->type)); message_free(msg); return -1; } if (proto != ISAKMP_PROTO_ISAKMP && doi->validate_proto(proto)) { log_print("message_validate_delete: protocol not supported"); message_free(msg); return -1; } /* Validate the SPIs. */ for (i = 0; i < nspis; i++) { /* Get ISAKMP SA protecting this message. */ isakmp_sa = msg->isakmp_sa; if (!isakmp_sa) { /* XXX should not happen? */ log_print("message_validate_delete: invalid spi (no " "valid ISAKMP SA found)"); message_free(msg); return -1; } isakmp_sa->transport->vtbl->get_dst(isakmp_sa->transport, &dst_isa); /* Get SA to be deleted. */ msg->transport->vtbl->get_dst(msg->transport, &dst); if (proto == ISAKMP_PROTO_ISAKMP) sa = sa_lookup_isakmp_sa(dst, spis + i * ISAKMP_HDR_COOKIES_LEN); else sa = ipsec_sa_lookup(dst, ((u_int32_t *) spis)[i], proto); if (!sa) { LOG_DBG((LOG_MESSAGE, 50, "message_validate_delete: " "invalid spi (no valid SA found)")); message_free(msg); return -1; } sa->transport->vtbl->get_dst(sa->transport, &dst); /* Destination addresses must match. */ if (dst->sa_family != dst_isa->sa_family || memcmp(sockaddr_addrdata(dst_isa), sockaddr_addrdata(dst), sockaddr_addrlen(dst))) { sockaddr2text(dst_isa, &addr, 0); log_print("message_validate_delete: invalid spi " "(illegal delete request from %s)", addr); free(addr); message_free(msg); return -1; } } return 0; } /* * Validate the hash payload P in message MSG. * XXX Currently hash payloads are processed by the particular exchanges, * except INFORMATIONAL. This should be actually done here. */ static int message_validate_hash(struct message *msg, struct payload *p) { struct sa *isakmp_sa = msg->isakmp_sa; struct ipsec_sa *isa; struct hash *hash; struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH); struct prf *prf; u_int8_t *comp_hash, *rest; u_int8_t message_id[ISAKMP_HDR_MESSAGE_ID_LEN]; size_t rest_len; /* active exchanges other than INFORMATIONAL validates hash payload. */ if (msg->exchange && (msg->exchange->type != ISAKMP_EXCH_INFO)) return 0; if (isakmp_sa == NULL) { log_print("message_validate_hash: invalid hash information"); message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 1); return -1; } isa = isakmp_sa->data; hash = hash_get(isa->hash); if (hash == NULL) { log_print("message_validate_hash: invalid hash information"); message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 1); return -1; } /* If no SKEYID_a, we can not do anything (should not happen). */ if (!isa->skeyid_a) { log_print("message_validate_hash: invalid hash information"); message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 1); return -1; } /* Allocate the prf and start calculating our HASH(1). */ LOG_DBG_BUF((LOG_MISC, 90, "message_validate_hash: SKEYID_a", isa->skeyid_a, isa->skeyid_len)); prf = prf_alloc(isa->prf_type, hash->type, isa->skeyid_a, isa->skeyid_len); if (!prf) { message_free(msg); return -1; } comp_hash = (u_int8_t *)malloc(hash->hashsize); if (!comp_hash) { log_error("message_validate_hash: malloc (%lu) failed", (unsigned long)hash->hashsize); prf_free(prf); message_free(msg); return -1; } /* This is not an active exchange. */ GET_ISAKMP_HDR_MESSAGE_ID(msg->iov[0].iov_base, message_id); prf->Init(prf->prfctx); LOG_DBG_BUF((LOG_MISC, 90, "message_validate_hash: message_id", message_id, ISAKMP_HDR_MESSAGE_ID_LEN)); prf->Update(prf->prfctx, message_id, ISAKMP_HDR_MESSAGE_ID_LEN); rest = hashp->p + GET_ISAKMP_GEN_LENGTH(hashp->p); rest_len = (GET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base) - (rest - (u_int8_t *)msg->iov[0].iov_base)); LOG_DBG_BUF((LOG_MISC, 90, "message_validate_hash: payloads after HASH(1)", rest, rest_len)); prf->Update(prf->prfctx, rest, rest_len); prf->Final(comp_hash, prf->prfctx); prf_free(prf); if (memcmp(hashp->p + ISAKMP_HASH_DATA_OFF, comp_hash, hash->hashsize)) { log_print("message_validate_hash: invalid hash value for %s " "payload", payload_first(msg, ISAKMP_PAYLOAD_DELETE) ? "DELETE" : "NOTIFY"); message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 1); free(comp_hash); return -1; } free(comp_hash); /* Mark the HASH as handled. */ hashp->flags |= PL_MARK; /* Mark message as authenticated. */ msg->flags |= MSG_AUTHENTICATED; return 0; } /* Validate the identification payload P in message MSG. */ static int message_validate_id(struct message *msg, struct payload *p) { struct exchange *exchange = msg->exchange; size_t len = GET_ISAKMP_GEN_LENGTH(p->p); if (!exchange) { /* We should have an exchange at this point. */ log_print("message_validate_id: payload out of sequence"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } if (exchange->doi && exchange->doi->validate_id_information(GET_ISAKMP_ID_TYPE(p->p), p->p + ISAKMP_ID_DOI_DATA_OFF, p->p + ISAKMP_ID_DATA_OFF, len - ISAKMP_ID_DATA_OFF, exchange)) { message_drop(msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION, 0, 1, 1); return -1; } return 0; } /* Validate the key exchange payload P in message MSG. */ static int message_validate_key_exch(struct message *msg, struct payload *p) { struct exchange *exchange = msg->exchange; size_t len = GET_ISAKMP_GEN_LENGTH(p->p); if (!exchange) { /* We should have an exchange at this point. */ log_print("message_validate_key_exch: " "payload out of sequence"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } if (exchange->doi && exchange->doi->validate_key_information(p->p + ISAKMP_KE_DATA_OFF, len - ISAKMP_KE_DATA_OFF)) { message_drop(msg, ISAKMP_NOTIFY_INVALID_KEY_INFORMATION, 0, 1, 1); return -1; } return 0; } /* Validate the NAT-D payload P in message MSG. */ static int message_validate_nat_d(struct message *msg, struct payload *p) { struct exchange *exchange = msg->exchange; if (!exchange) { /* We should have an exchange at this point. */ log_print("message_validate_nat_d: payload out of sequence"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } if (exchange->phase != 1) { log_print("message_validate_nat_d: " "NAT-D payload must be in phase 1"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } /* Mark as handled. */ p->flags |= PL_MARK; return 0; } /* Validate the NAT-OA payload P in message MSG. */ static int message_validate_nat_oa(struct message *msg, struct payload *p) { struct exchange *exchange = msg->exchange; if (!exchange) { /* We should have an exchange at this point. */ log_print("message_validate_nat_d: payload out of sequence"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } #ifdef notyet /* XXX Probably never, due to patent issues. */ /* Mark as handled. */ p->flags |= PL_MARK; #endif return 0; } /* Validate the nonce payload P in message MSG. */ static int message_validate_nonce(struct message *msg, struct payload *p) { if (!msg->exchange) { /* We should have an exchange at this point. */ log_print("message_validate_nonce: payload out of sequence"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } /* Nonces require no specific validation. */ return 0; } /* * Validate the notify payload P in message MSG. As a side-effect, create * an exchange if we do not have one already. */ static int message_validate_notify(struct message *msg, struct payload *p) { u_int8_t proto = GET_ISAKMP_NOTIFY_PROTO(p->p); u_int16_t type = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p); struct doi *doi; doi = doi_lookup(GET_ISAKMP_NOTIFY_DOI(p->p)); if (!doi) { log_print("message_validate_notify: DOI not supported"); message_free(msg); return -1; } /* If we don't have an exchange yet, create one. */ if (!msg->exchange) { if (zero_test((u_int8_t *) msg->iov[0].iov_base + ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN)) msg->exchange = exchange_setup_p1(msg, doi->id); else msg->exchange = exchange_setup_p2(msg, doi->id); if (!msg->exchange) { log_print("message_validate_notify: can not create " "exchange"); message_free(msg); return -1; } } if (proto != ISAKMP_PROTO_ISAKMP && doi->validate_proto(proto)) { log_print("message_validate_notify: protocol not supported"); message_free(msg); return -1; } /* Validate the SPI. XXX Just ISAKMP for now. */ if (proto == ISAKMP_PROTO_ISAKMP && GET_ISAKMP_NOTIFY_SPI_SZ(p->p) == ISAKMP_HDR_COOKIES_LEN && msg->isakmp_sa && memcmp(p->p + ISAKMP_NOTIFY_SPI_OFF, msg->isakmp_sa->cookies, ISAKMP_HDR_COOKIES_LEN) != 0) { log_print("message_validate_notify: bad cookies"); message_drop(msg, ISAKMP_NOTIFY_INVALID_SPI, 0, 1, 0); return -1; } if (type < ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE || (type >= ISAKMP_NOTIFY_RESERVED_MIN && type < ISAKMP_NOTIFY_PRIVATE_MIN) || (type >= ISAKMP_NOTIFY_STATUS_RESERVED1_MIN && type <= ISAKMP_NOTIFY_STATUS_RESERVED1_MAX) || (type >= ISAKMP_NOTIFY_STATUS_DOI_MIN && type <= ISAKMP_NOTIFY_STATUS_DOI_MAX && doi->validate_notification(type)) || type >= ISAKMP_NOTIFY_STATUS_RESERVED2_MIN) { log_print("message_validate_notify: " "message type not supported"); message_free(msg); return -1; } return 0; } /* Validate the proposal payload P in message MSG. */ static int message_validate_proposal(struct message *msg, struct payload *p) { u_int8_t proto = GET_ISAKMP_PROP_PROTO(p->p); u_int8_t *sa = p->context->p; if (!msg->exchange) { /* We should have an exchange at this point. */ log_print("message_validate_proposal: " "payload out of sequence"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } if (proto != ISAKMP_PROTO_ISAKMP && msg->exchange->doi->validate_proto(proto)) { message_drop(msg, ISAKMP_NOTIFY_INVALID_PROTOCOL_ID, 0, 1, 1); return -1; } /* Check that we get monotonically increasing proposal IDs per SA. */ if (sa != last_sa) last_sa = sa; else if (GET_ISAKMP_PROP_NO(p->p) < last_prop_no) { message_drop(msg, ISAKMP_NOTIFY_BAD_PROPOSAL_SYNTAX, 0, 1, 1); return -1; } last_prop_no = GET_ISAKMP_PROP_NO(p->p); /* XXX Validate the SPI, and other syntactic things. */ return 0; } /* * Validate the SA payload P in message MSG. * Aside from normal validation, note what DOI is in use for other * validation routines to look at. Also index the proposal payloads * on the fly. * XXX This assumes PAYLOAD_SA is always the first payload * to be validated, which is true for IKE, except for quick mode where * a PAYLOAD_HASH comes first, but in that specific case it does not matter. * XXX Make sure the above comment is relevant, isn't SA always checked * first due to the IANA assigned payload number? */ static int message_validate_sa(struct message *msg, struct payload *p) { set payload_set; size_t len; u_int32_t doi_id; struct exchange *exchange = msg->exchange; u_int8_t *pkt = msg->iov[0].iov_base; doi_id = GET_ISAKMP_SA_DOI(p->p); if (!doi_lookup(doi_id)) { log_print("message_validate_sa: DOI not supported"); message_drop(msg, ISAKMP_NOTIFY_DOI_NOT_SUPPORTED, 0, 1, 1); return -1; } /* * It's time to figure out what SA this message is about. If it is * already set, then we are creating a new phase 1 SA. Otherwise, * lookup the SA using the cookies and the message ID. If we cannot * find it, and the phase 1 SA is ready, setup a phase 2 SA. */ if (!exchange) { if (zero_test(pkt + ISAKMP_HDR_RCOOKIE_OFF, ISAKMP_HDR_RCOOKIE_LEN)) exchange = exchange_setup_p1(msg, doi_id); else if (msg->isakmp_sa->flags & SA_FLAG_READY) exchange = exchange_setup_p2(msg, doi_id); else { /* XXX What to do here? */ message_free(msg); return -1; } if (!exchange) { /* XXX Log? */ message_free(msg); return -1; } } msg->exchange = exchange; /* * Create a struct sa for each SA payload handed to us unless we are * the initiator where we only will count them. */ if (exchange->initiator) { /* XXX Count SA payloads. */ } else if (sa_create(exchange, msg->transport)) { /* XXX Remove exchange if we just created it? */ message_free(msg); return -1; } if (exchange->phase == 1) { msg->isakmp_sa = TAILQ_FIRST(&exchange->sa_list); if (msg->isakmp_sa) sa_reference(msg->isakmp_sa); } /* * Let the DOI validate the situation, at the same time it tells us * what the length of the situation field is. */ if (exchange->doi->validate_situation(p->p + ISAKMP_SA_SIT_OFF, &len, GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_SA_SIT_OFF)) { log_print("message_validate_sa: situation not supported"); message_drop(msg, ISAKMP_NOTIFY_SITUATION_NOT_SUPPORTED, 0, 1, 1); return -1; } /* * Reset the fields we base our proposal & transform number checks * on. */ last_sa = last_prop = 0; last_prop_no = last_xf_no = 0; /* Go through the PROPOSAL payloads. */ ZERO(&payload_set); SET(payload_revmap[ISAKMP_PAYLOAD_PROPOSAL], &payload_set); if (message_parse_payloads(msg, p, ISAKMP_PAYLOAD_PROPOSAL, p->p + ISAKMP_SA_SIT_OFF + len, &payload_set, message_parse_proposal) == -1) return -1; return 0; } /* Validate the signature payload P in message MSG. */ static int message_validate_sig(struct message *msg, struct payload *p) { if (!msg->exchange) { /* We should have an exchange at this point. */ log_print("message_validate_sig: payload out of sequence"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } /* XXX Not implemented yet. */ return 0; } /* Validate the transform payload P in message MSG. */ static int message_validate_transform(struct message *msg, struct payload *p) { u_int8_t proto = GET_ISAKMP_PROP_PROTO(p->context->p); u_int8_t *prop = p->context->p; if (!msg->exchange) { /* We should have an exchange at this point. */ log_print("message_validate_transform: " "payload out of sequence"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } if (msg->exchange->doi ->validate_transform_id(proto, GET_ISAKMP_TRANSFORM_ID(p->p))) { message_drop(msg, ISAKMP_NOTIFY_INVALID_TRANSFORM_ID, 0, 1, 1); return -1; } /* Check that the reserved field is zero. */ if (!zero_test(p->p + ISAKMP_TRANSFORM_RESERVED_OFF, ISAKMP_TRANSFORM_RESERVED_LEN)) { message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } /* * Check that we get monotonically increasing transform numbers per * proposal. */ if (prop != last_prop) last_prop = prop; else if (GET_ISAKMP_TRANSFORM_NO(p->p) <= last_xf_no) { message_drop(msg, ISAKMP_NOTIFY_BAD_PROPOSAL_SYNTAX, 0, 1, 1); return -1; } last_xf_no = GET_ISAKMP_TRANSFORM_NO(p->p); /* Validate the attributes. */ if (attribute_map(p->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF, GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, msg->exchange->doi->validate_attribute, msg)) { message_drop(msg, ISAKMP_NOTIFY_ATTRIBUTES_NOT_SUPPORTED, 0, 1, 1); return -1; } return 0; } /* Validate the vendor payload P in message MSG. */ static int message_validate_vendor(struct message *msg, struct payload *p) { if (!msg->exchange) { /* We should have an exchange at this point. */ log_print("message_validate_vendor: payload out of sequence"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); return -1; } /* Vendor IDs are only allowed in phase 1. */ if (msg->exchange->phase != 1) { message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 1, 1); return -1; } #if defined (USE_DPD) dpd_check_vendor_payload(msg, p); #endif #if defined (USE_NAT_TRAVERSAL) nat_t_check_vendor_payload(msg, p); #endif if (!(p->flags & PL_MARK)) LOG_DBG((LOG_MESSAGE, 40, "message_validate_vendor: " "vendor ID seen")); return 0; } /* * Add an index-record pointing to the payload at BUF in message MSG * to the PAYLOAD bucket of payloads. This allows us to quickly reference * payloads by type. Also stash the parent payload P link into the new * node so we can go from transforms -> payloads -> SAs. */ static int message_index_payload(struct message *msg, struct payload *p, u_int8_t payload, u_int8_t *buf) { struct payload *payload_node; /* Put the payload pointer into the right bucket. */ payload_node = malloc(sizeof *payload_node); if (!payload_node) return -1; payload_node->p = buf; payload_node->context = p; payload_node->flags = 0; TAILQ_INSERT_TAIL(&msg->payload[payload_map[payload]], payload_node, link); return 0; } /* * Group each payload found in MSG by type for easy reference later. * While doing this, validate the generic parts of the message structure too. * NEXT is the 1st payload's type. This routine will also register the * computed message length (i.e. without padding) in msg->iov[0].iov_len. */ static int message_sort_payloads(struct message *msg, u_int8_t next) { set payload_set; int i, sz; ZERO(&payload_set); for (i = ISAKMP_PAYLOAD_SA; i < payload_index_max; i++) if (i != ISAKMP_PAYLOAD_PROPOSAL && i != ISAKMP_PAYLOAD_TRANSFORM) SET(payload_revmap[i], &payload_set); sz = message_parse_payloads(msg, 0, next, (u_int8_t *)msg->iov[0].iov_base + ISAKMP_HDR_SZ, &payload_set, message_index_payload); if (sz == -1) return -1; msg->iov[0].iov_len = ISAKMP_HDR_SZ + sz; SET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base, ISAKMP_HDR_SZ + sz); return 0; } /* Run all the generic payload tests that the drafts specify. */ static int message_validate_payloads(struct message *msg) { int i; struct payload *p; for (i = ISAKMP_PAYLOAD_SA; i < payload_index_max; i++) for (p = payload_first(msg, i); p; p = TAILQ_NEXT(p, link)) { LOG_DBG((LOG_MESSAGE, 60, "message_validate_payloads: " "payload %s at %p of message %p", constant_name(isakmp_payload_cst, i), p->p, msg)); field_dump_payload(fields[i - ISAKMP_PAYLOAD_SA], p->p); if (message_validate_payload[i - ISAKMP_PAYLOAD_SA] (msg, p)) return -1; } return 0; } /* * All incoming messages go through here. We do generic validity checks * and try to find or establish SAs. Last but not least we try to find * the exchange this message, MSG, is part of, and feed it there. */ int message_recv(struct message *msg) { u_int8_t *buf = msg->iov[0].iov_base; size_t sz = msg->iov[0].iov_len; u_int8_t exch_type; int setup_isakmp_sa, msgid_is_zero; u_int8_t flags; struct keystate *ks = 0; struct proto tmp_proto; struct sa tmp_sa; /* Messages shorter than an ISAKMP header are bad. */ if (sz < ISAKMP_HDR_SZ || sz != GET_ISAKMP_HDR_LENGTH(buf)) { log_print("message_recv: bad message length"); message_drop(msg, ISAKMP_NOTIFY_UNEQUAL_PAYLOAD_LENGTHS, 0, 1, 1); return -1; } #ifdef USE_DEBUG /* Possibly dump a raw hex image of the message to the log channel. */ message_dump_raw("message_recv", msg, LOG_MESSAGE); #endif /* * If the responder cookie is zero, this is a request to setup an * ISAKMP SA. Otherwise the cookies should refer to an existing * ISAKMP SA. * * XXX This is getting ugly, please reread later to see if it can be * made nicer. */ setup_isakmp_sa = zero_test(buf + ISAKMP_HDR_RCOOKIE_OFF, ISAKMP_HDR_RCOOKIE_LEN); if (setup_isakmp_sa) { /* * This might be a retransmission of a former ISAKMP SA setup * message. If so, just drop it. * XXX Must we really look in both the SA and exchange pools? */ if (exchange_lookup_from_icookie(buf + ISAKMP_HDR_ICOOKIE_OFF) || sa_lookup_from_icookie(buf + ISAKMP_HDR_ICOOKIE_OFF)) { /* * XXX Later we should differentiate between * retransmissions and potential replay attacks. */ LOG_DBG((LOG_MESSAGE, 90, "message_recv: dropping setup for existing SA")); message_free(msg); return -1; } } else { msg->isakmp_sa = sa_lookup_by_header(buf, 0); if (msg->isakmp_sa) sa_reference(msg->isakmp_sa); /* * If we cannot find an ISAKMP SA out of the cookies, this is * either a responder's first reply, and we need to upgrade * our exchange, or it's just plain invalid cookies. */ if (!msg->isakmp_sa) { msg->exchange = exchange_lookup_from_icookie(buf + ISAKMP_HDR_ICOOKIE_OFF); if (msg->exchange && msg->exchange->phase == 1 && zero_test(msg->exchange->cookies + ISAKMP_HDR_RCOOKIE_OFF, ISAKMP_HDR_RCOOKIE_LEN)) exchange_upgrade_p1(msg); else { log_print("message_recv: invalid cookie(s) " "%08x%08x %08x%08x", decode_32(buf + ISAKMP_HDR_ICOOKIE_OFF), decode_32(buf + ISAKMP_HDR_ICOOKIE_OFF + 4), decode_32(buf + ISAKMP_HDR_RCOOKIE_OFF), decode_32(buf + ISAKMP_HDR_RCOOKIE_OFF + 4)); tmp_proto.sa = &tmp_sa; tmp_sa.doi = doi_lookup(ISAKMP_DOI_ISAKMP); tmp_proto.proto = ISAKMP_PROTO_ISAKMP; tmp_proto.spi_sz[1] = ISAKMP_HDR_COOKIES_LEN; tmp_proto.spi[1] = buf + ISAKMP_HDR_COOKIES_OFF; message_drop(msg, ISAKMP_NOTIFY_INVALID_COOKIE, &tmp_proto, 1, 1); return -1; } #if 0 msg->isakmp_sa = sa_lookup_from_icookie(buf + ISAKMP_HDR_ICOOKIE_OFF); if (msg->isakmp_sa) sa_isakmp_upgrade(msg); #endif } msg->exchange = exchange_lookup(buf, 1); } if (message_check_duplicate(msg)) return -1; if (GET_ISAKMP_HDR_NEXT_PAYLOAD(buf) >= ISAKMP_PAYLOAD_RESERVED_MIN) { log_print("message_recv: invalid payload type %d in ISAKMP " "header (check passphrases, if applicable and in Phase 1)", GET_ISAKMP_HDR_NEXT_PAYLOAD(buf)); message_drop(msg, ISAKMP_NOTIFY_INVALID_PAYLOAD_TYPE, 0, 1, 1); return -1; } /* Validate that the message is of version 1.0. */ if (ISAKMP_VERSION_MAJOR(GET_ISAKMP_HDR_VERSION(buf)) != 1) { log_print("message_recv: invalid version major %d", ISAKMP_VERSION_MAJOR(GET_ISAKMP_HDR_VERSION(buf))); message_drop(msg, ISAKMP_NOTIFY_INVALID_MAJOR_VERSION, 0, 1, 1); return -1; } if (ISAKMP_VERSION_MINOR(GET_ISAKMP_HDR_VERSION(buf)) != 0) { log_print("message_recv: invalid version minor %d", ISAKMP_VERSION_MINOR(GET_ISAKMP_HDR_VERSION(buf))); message_drop(msg, ISAKMP_NOTIFY_INVALID_MINOR_VERSION, 0, 1, 1); return -1; } /* * Validate the exchange type. If it's a DOI-specified exchange wait * until after all payloads have been seen for the validation as the * SA payload might not yet have been parsed, thus the DOI might be * unknown. */ exch_type = GET_ISAKMP_HDR_EXCH_TYPE(buf); if (exch_type == ISAKMP_EXCH_NONE || (exch_type >= ISAKMP_EXCH_FUTURE_MIN && exch_type <= ISAKMP_EXCH_FUTURE_MAX) || (setup_isakmp_sa && exch_type >= ISAKMP_EXCH_DOI_MIN)) { log_print("message_recv: invalid exchange type %s", constant_name(isakmp_exch_cst, exch_type)); message_drop(msg, ISAKMP_NOTIFY_INVALID_EXCHANGE_TYPE, 0, 1, 1); return -1; } /* * Check for unrecognized flags, or the encryption flag when we don't * have an ISAKMP SA to decrypt with. */ flags = GET_ISAKMP_HDR_FLAGS(buf); if (flags & ~(ISAKMP_FLAGS_ENC | ISAKMP_FLAGS_COMMIT | ISAKMP_FLAGS_AUTH_ONLY)) { log_print("message_recv: invalid flags 0x%x", GET_ISAKMP_HDR_FLAGS(buf)); message_drop(msg, ISAKMP_NOTIFY_INVALID_FLAGS, 0, 1, 1); return -1; } /* * If we are about to setup an ISAKMP SA, the message ID must be * zero. */ msgid_is_zero = zero_test(buf + ISAKMP_HDR_MESSAGE_ID_OFF, ISAKMP_HDR_MESSAGE_ID_LEN); if (setup_isakmp_sa && !msgid_is_zero) { log_print("message_recv: invalid message id"); message_drop(msg, ISAKMP_NOTIFY_INVALID_MESSAGE_ID, 0, 1, 1); return -1; } if (!setup_isakmp_sa && msgid_is_zero) { /* * XXX Very likely redundant, look at the else clause of the * if (setup_isakmp_sa) statement above. */ msg->exchange = exchange_lookup(buf, 0); if (!msg->exchange) { log_print("message_recv: phase 1 message after " "ISAKMP SA is ready"); message_free(msg); return -1; } else if (msg->exchange->last_sent) { LOG_DBG((LOG_MESSAGE, 80, "message_recv: resending " "last message from phase 1")); message_send(msg->exchange->last_sent); } } if (flags & ISAKMP_FLAGS_ENC) { if (!msg->isakmp_sa) { LOG_DBG((LOG_MISC, 10, "message_recv: no isakmp_sa " "for encrypted message")); message_free(msg); return -1; } /* Decrypt rest of message using a DOI-specified IV. */ ks = msg->isakmp_sa->doi->get_keystate(msg); if (!ks) { message_free(msg); return -1; } msg->orig = malloc(sz); if (!msg->orig) { message_free(msg); free(ks); return -1; } memcpy(msg->orig, buf, sz); crypto_decrypt(ks, buf + ISAKMP_HDR_SZ, sz - ISAKMP_HDR_SZ); } else msg->orig = buf; msg->orig_sz = sz; /* IKE packet capture */ message_packet_log(msg); /* * Check the overall payload structure at the same time as indexing * them by type. */ if (GET_ISAKMP_HDR_NEXT_PAYLOAD(buf) != ISAKMP_PAYLOAD_NONE && message_sort_payloads(msg, GET_ISAKMP_HDR_NEXT_PAYLOAD(buf))) { if (ks) free(ks); return -1; } /* * Run generic payload tests now. If anything fails these checks, the * message needs either to be retained for later duplicate checks or * freed entirely. * XXX Should SAs and even transports be cleaned up then too? */ if (message_validate_payloads(msg)) { if (ks) free(ks); return -1; } /* * If we have not found an exchange by now something is definitely * wrong. */ if (!msg->exchange) { log_print("message_recv: no exchange"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 1); if (ks) free(ks); return -1; } /* * Now we can validate DOI-specific exchange types. If we have no SA * DOI-specific exchange types are definitely wrong. */ if (exch_type >= ISAKMP_EXCH_DOI_MIN && exch_type <= ISAKMP_EXCH_DOI_MAX && msg->exchange->doi->validate_exchange(exch_type)) { log_print("message_recv: invalid DOI exchange type %d", exch_type); message_drop(msg, ISAKMP_NOTIFY_INVALID_EXCHANGE_TYPE, 0, 1, 1); if (ks) free(ks); return -1; } /* Make sure the IV we used gets saved in the proper SA. */ if (ks) { if (!msg->exchange->keystate) { msg->exchange->keystate = ks; msg->exchange->crypto = ks->xf; } else free(ks); } /* Handle the flags. */ if (flags & ISAKMP_FLAGS_ENC) msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT; if ((msg->exchange->flags & EXCHANGE_FLAG_COMMITTED) == 0 && (flags & ISAKMP_FLAGS_COMMIT)) msg->exchange->flags |= EXCHANGE_FLAG_HE_COMMITTED; /* * Except for the 3rd Aggressive Mode message, require encryption * as soon as we have the keystate for it. */ if ((flags & ISAKMP_FLAGS_ENC) == 0 && (msg->exchange->phase == 2 || (msg->exchange->keystate && msg->exchange->type != ISAKMP_EXCH_AGGRESSIVE))) { log_print("message_recv: cleartext phase %d message", msg->exchange->phase); message_drop(msg, ISAKMP_NOTIFY_INVALID_FLAGS, 0, 1, 1); return -1; } /* OK let the exchange logic do the rest. */ exchange_run(msg); return 0; } void message_send_expire(struct message *msg) { msg->retrans = 0; message_send(msg); } /* Queue up message MSG for transmittal. */ void message_send(struct message *msg) { struct exchange *exchange = msg->exchange; struct message *m; struct msg_head *q; /* Remove retransmissions on this message */ if (msg->retrans) { timer_remove_event(msg->retrans); msg->retrans = 0; } /* IKE packet capture */ message_packet_log(msg); /* * If the ISAKMP SA has set up encryption, encrypt the message. * However, in a retransmit, it is already encrypted. */ if ((msg->flags & MSG_ENCRYPTED) == 0 && exchange->flags & EXCHANGE_FLAG_ENCRYPT) { if (!exchange->keystate) { exchange->keystate = exchange->doi->get_keystate(msg); if (!exchange->keystate) return; exchange->crypto = exchange->keystate->xf; exchange->flags |= EXCHANGE_FLAG_ENCRYPT; } if (message_encrypt(msg)) { /* XXX Log. */ return; } } /* Keep the COMMIT bit on. */ if (exchange->flags & EXCHANGE_FLAG_COMMITTED) SET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base, GET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base) | ISAKMP_FLAGS_COMMIT); #ifdef USE_DEBUG message_dump_raw("message_send", msg, LOG_MESSAGE); #endif msg->flags |= MSG_IN_TRANSIT; exchange->in_transit = msg; /* * If we get a retransmission of a message before our response * has left the queue, don't queue it again, as it will result * in a circular list. */ q = msg->transport->vtbl->get_queue(msg); for (m = TAILQ_FIRST(q); m; m = TAILQ_NEXT(m, link)) if (m == msg) { LOG_DBG((LOG_MESSAGE, 60, "message_send: msg %p already on sendq %p", m, q)); return; } TAILQ_INSERT_TAIL(q, msg, link); } /* * Setup the ISAKMP message header for message MSG. EXCHANGE is the exchange * type, FLAGS are the ISAKMP header flags and MSG_ID is message ID * identifying the exchange. */ void message_setup_header(struct message *msg, u_int8_t exchange, u_int8_t flags, u_int8_t *msg_id) { u_int8_t *buf = msg->iov[0].iov_base; SET_ISAKMP_HDR_ICOOKIE(buf, msg->exchange->cookies); SET_ISAKMP_HDR_RCOOKIE(buf, msg->exchange->cookies + ISAKMP_HDR_ICOOKIE_LEN); SET_ISAKMP_HDR_NEXT_PAYLOAD(buf, ISAKMP_PAYLOAD_NONE); SET_ISAKMP_HDR_VERSION(buf, ISAKMP_VERSION_MAKE(1, 0)); SET_ISAKMP_HDR_EXCH_TYPE(buf, exchange); SET_ISAKMP_HDR_FLAGS(buf, flags); SET_ISAKMP_HDR_MESSAGE_ID(buf, msg_id); SET_ISAKMP_HDR_LENGTH(buf, msg->iov[0].iov_len); } /* * Add the payload of type PAYLOAD in BUF sized SZ to the MSG message. * The caller thereby is released from the responsibility of freeing BUF, * unless we return a failure of course. If LINK is set the former * payload's "next payload" field to PAYLOAD. * * XXX We might want to resize the iov array several slots at a time. */ int message_add_payload(struct message *msg, u_int8_t payload, u_int8_t *buf, size_t sz, int link) { struct iovec *new_iov; struct payload *payload_node; payload_node = calloc(1, sizeof *payload_node); if (!payload_node) { log_error("message_add_payload: calloc (1, %lu) failed", (unsigned long)sizeof *payload_node); return -1; } new_iov = (struct iovec *) realloc(msg->iov, (msg->iovlen + 1) * sizeof *msg->iov); if (!new_iov) { log_error("message_add_payload: realloc (%p, %lu) failed", msg->iov, (msg->iovlen + 1) * (unsigned long)sizeof *msg->iov); free(payload_node); return -1; } msg->iov = new_iov; new_iov[msg->iovlen].iov_base = buf; new_iov[msg->iovlen].iov_len = sz; msg->iovlen++; if (link) *msg->nextp = payload; msg->nextp = buf + ISAKMP_GEN_NEXT_PAYLOAD_OFF; *msg->nextp = ISAKMP_PAYLOAD_NONE; SET_ISAKMP_GEN_RESERVED(buf, 0); SET_ISAKMP_GEN_LENGTH(buf, sz); SET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base, GET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base) + sz); /* * For the sake of exchange_validate we index the payloads even in * outgoing messages, however context and flags are uninteresting in * this situation. */ payload_node->p = buf; TAILQ_INSERT_TAIL(&msg->payload[payload_map[payload]], payload_node, link); return 0; } /* XXX Move up when ready. */ struct info_args { char discr; u_int32_t doi; u_int8_t proto; u_int16_t spi_sz; union { struct { u_int16_t msg_type; u_int8_t *spi; } n; struct { u_int16_t nspis; u_int8_t *spis; } d; #if defined (USE_DPD) struct { u_int16_t msg_type; u_int8_t *spi; u_int32_t seq; } dpd; #endif } u; }; /* * As a reaction to the incoming message MSG create an informational exchange * protected by ISAKMP_SA and send a notify payload of type NOTIFY, with * fields initialized from SA. INCOMING is true if the SPI field should be * filled with the incoming SPI and false if it is to be filled with the * outgoing one. * * XXX Should we handle sending multiple notify payloads? The draft allows * it, but do we need it? Furthermore, should we not return a success * status value? */ void message_send_notification(struct message *msg, struct sa *isakmp_sa, u_int16_t notify, struct proto *proto, int incoming) { struct info_args args; struct sa *doi_sa = proto ? proto->sa : isakmp_sa; args.discr = 'N'; args.doi = doi_sa ? doi_sa->doi->id : ISAKMP_DOI_ISAKMP; args.proto = proto ? proto->proto : ISAKMP_PROTO_ISAKMP; args.spi_sz = proto ? proto->spi_sz[incoming] : 0; args.u.n.msg_type = notify; args.u.n.spi = proto ? proto->spi[incoming] : 0; if (isakmp_sa && (isakmp_sa->flags & SA_FLAG_READY)) exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args, 0, 0); else exchange_establish_p1(msg->transport, ISAKMP_EXCH_INFO, msg->exchange ? msg->exchange->doi->id : ISAKMP_DOI_ISAKMP, 0, &args, 0, 0); } /* Send a DELETE inside an informational exchange for each protocol in SA. */ void message_send_delete(struct sa *sa) { struct info_args args; struct proto *proto; struct sa *isakmp_sa; struct sockaddr *dst; sa->transport->vtbl->get_dst(sa->transport, &dst); isakmp_sa = sa_isakmp_lookup_by_peer(dst, sysdep_sa_len(dst)); if (!isakmp_sa) { /* * XXX We ought to setup an ISAKMP SA with our peer here and * send the DELETE over that one. */ return; } args.discr = 'D'; args.doi = sa->doi->id; args.u.d.nspis = 1; for (proto = TAILQ_FIRST(&sa->protos); proto; proto = TAILQ_NEXT(proto, link)) { args.proto = proto->proto; args.spi_sz = proto->spi_sz[1]; args.u.d.spis = proto->spi[1]; exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args, 0, 0); } } #if defined (USE_DPD) void message_send_dpd_notify(struct sa* isakmp_sa, u_int16_t notify, u_int32_t seq) { struct info_args args; args.discr = 'P'; args.doi = IPSEC_DOI_IPSEC; args.proto = ISAKMP_PROTO_ISAKMP; args.spi_sz = ISAKMP_HDR_COOKIES_LEN; args.u.dpd.msg_type = notify; args.u.dpd.spi = isakmp_sa->cookies; args.u.dpd.seq = htonl(seq); exchange_establish_p2(isakmp_sa, ISAKMP_EXCH_INFO, 0, &args, 0, 0); } #endif /* Build the informational message into MSG. */ int message_send_info(struct message *msg) { u_int8_t *buf; size_t sz = 0; struct info_args *args = msg->extra; u_int8_t payload; /* Let the DOI get the first hand on the message. */ if (msg->exchange->doi->informational_pre_hook) if (msg->exchange->doi->informational_pre_hook(msg)) return -1; switch (args->discr) { #if defined (USE_DPD) case 'P': sz = sizeof args->u.dpd.seq; /* FALLTHROUGH */ #endif case 'N': sz += ISAKMP_NOTIFY_SPI_OFF + args->spi_sz; break; case 'D': default: /* Silence gcc */ sz = ISAKMP_DELETE_SPI_OFF + args->u.d.nspis * args->spi_sz; break; } buf = calloc(1, sz); if (!buf) { log_error("message_send_info: calloc (1, %lu) failed", (unsigned long)sz); message_free(msg); return -1; } switch (args->discr) { #if defined (USE_DPD) case 'P': memcpy(buf + ISAKMP_NOTIFY_SPI_OFF + args->spi_sz, &args->u.dpd.seq, sizeof args->u.dpd.seq); /* FALLTHROUGH */ #endif case 'N': /* Build the NOTIFY payload. */ payload = ISAKMP_PAYLOAD_NOTIFY; SET_ISAKMP_NOTIFY_DOI(buf, args->doi); SET_ISAKMP_NOTIFY_PROTO(buf, args->proto); SET_ISAKMP_NOTIFY_SPI_SZ(buf, args->spi_sz); SET_ISAKMP_NOTIFY_MSG_TYPE(buf, args->u.n.msg_type); memcpy(buf + ISAKMP_NOTIFY_SPI_OFF, args->u.n.spi, args->spi_sz); break; case 'D': default: /* Silence GCC. */ /* Build the DELETE payload. */ payload = ISAKMP_PAYLOAD_DELETE; SET_ISAKMP_DELETE_DOI(buf, args->doi); SET_ISAKMP_DELETE_PROTO(buf, args->proto); SET_ISAKMP_DELETE_SPI_SZ(buf, args->spi_sz); SET_ISAKMP_DELETE_NSPIS(buf, args->u.d.nspis); memcpy(buf + ISAKMP_DELETE_SPI_OFF, args->u.d.spis, args->u.d.nspis * args->spi_sz); msg->flags |= MSG_PRIORITIZED; break; } if (message_add_payload(msg, payload, buf, sz, 1)) { free(buf); message_free(msg); return -1; } /* Let the DOI get the last hand on the message. */ if (msg->exchange->doi->informational_post_hook) if (msg->exchange->doi->informational_post_hook(msg)) { message_free(msg); return -1; } return 0; } /* * Drop the MSG message due to reason given in NOTIFY. If NOTIFY is set * send out a notification to the originator. Fill this notification with * values from PROTO. INCOMING decides which SPI to include. If CLEAN is * set, free the message when ready with it. */ void message_drop(struct message *msg, int notify, struct proto *proto, int incoming, int clean) { struct transport *t = msg->transport; struct sockaddr *dst; char *address; short port = 0; t->vtbl->get_dst(t, &dst); if (sockaddr2text(dst, &address, 0)) { log_error("message_drop: sockaddr2text () failed"); address = 0; } switch (dst->sa_family) { case AF_INET: port = ((struct sockaddr_in *)dst)->sin_port; break; case AF_INET6: port = ((struct sockaddr_in6 *)dst)->sin6_port; break; default: log_print("message_drop: unknown protocol family %d", dst->sa_family); } log_print("dropped message from %s port %d due to notification type " "%s", address ? address : "", htons(port), constant_name(isakmp_notify_cst, notify)); if (address) free(address); /* If specified, return a notification. */ if (notify) message_send_notification(msg, msg->isakmp_sa, notify, proto, incoming); if (clean) message_free(msg); } /* * If the user demands debug printouts, printout MSG with as much detail * as we can without resorting to per-payload handling. */ void message_dump_raw(char *header, struct message *msg, int class) { u_int32_t i, j, k = 0; char buf[80], *p = buf; LOG_DBG((class, 70, "%s: message %p", header, msg)); field_dump_payload(isakmp_hdr_fld, msg->iov[0].iov_base); for (i = 0; i < msg->iovlen; i++) for (j = 0; j < msg->iov[i].iov_len; j++) { snprintf(p, sizeof buf - (int) (p - buf), "%02x", ((u_int8_t *) msg->iov[i].iov_base)[j]); p += 2; if (++k % 32 == 0) { *p = '\0'; LOG_DBG((class, 70, "%s: %s", header, buf)); p = buf; } else if (k % 4 == 0) *p++ = ' '; } *p = '\0'; if (p != buf) LOG_DBG((class, 70, "%s: %s", header, buf)); } static void message_packet_log(struct message *msg) { #if defined (USE_DEBUG) struct sockaddr *src, *dst; struct transport *t = msg->transport; /* Don't log retransmissions. Redundant for incoming packets... */ if (msg->xmits > 0) return; #if defined (USE_NAT_TRAVERSAL) if (msg->exchange && msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) t = ((struct virtual_transport *)msg->transport)->encap; #endif /* Figure out direction. */ if (msg->exchange && msg->exchange->initiator ^ (msg->exchange->step % 2)) { t->vtbl->get_src(t, &src); t->vtbl->get_dst(t, &dst); } else { t->vtbl->get_src(t, &dst); t->vtbl->get_dst(t, &src); } log_packet_iov(src, dst, msg->iov, msg->iovlen); #endif /* USE_DEBUG */ } /* * Encrypt an outgoing message MSG. As outgoing messages are represented * with an iovec with one segment per payload, we need to coalesce them * into just une buffer containing all payloads and some padding before * we encrypt. */ static int message_encrypt(struct message *msg) { struct exchange *exchange = msg->exchange; size_t i, sz = 0; u_int8_t *buf; /* If no payloads, nothing to do. */ if (msg->iovlen == 1) return 0; /* * For encryption we need to put all payloads together in a single * buffer. This buffer should be padded to the current crypto * transform's blocksize. */ for (i = 1; i < msg->iovlen; i++) sz += msg->iov[i].iov_len; sz = ((sz + exchange->crypto->blocksize - 1) / exchange->crypto->blocksize) * exchange->crypto->blocksize; buf = realloc(msg->iov[1].iov_base, sz); if (!buf) { log_error("message_encrypt: realloc (%p, %lu) failed", msg->iov[1].iov_base, (unsigned long) sz); return -1; } msg->iov[1].iov_base = buf; for (i = 2; i < msg->iovlen; i++) { memcpy(buf + msg->iov[1].iov_len, msg->iov[i].iov_base, msg->iov[i].iov_len); msg->iov[1].iov_len += msg->iov[i].iov_len; free(msg->iov[i].iov_base); } /* Pad with zeroes. */ memset(buf + msg->iov[1].iov_len, '\0', sz - msg->iov[1].iov_len); msg->iov[1].iov_len = sz; msg->iovlen = 2; SET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base, GET_ISAKMP_HDR_FLAGS(msg->iov[0].iov_base) | ISAKMP_FLAGS_ENC); SET_ISAKMP_HDR_LENGTH(msg->iov[0].iov_base, ISAKMP_HDR_SZ + sz); crypto_encrypt(exchange->keystate, buf, msg->iov[1].iov_len); msg->flags |= MSG_ENCRYPTED; /* Update the IV so we can decrypt the next incoming message. */ crypto_update_iv(exchange->keystate); return 0; } /* * Check whether the message MSG is a duplicate of the last one negotiating * this specific SA. */ static int message_check_duplicate(struct message *msg) { struct exchange *exchange = msg->exchange; size_t sz = msg->iov[0].iov_len; u_int8_t *pkt = msg->iov[0].iov_base; /* If no SA has been found, we cannot test, thus it's good. */ if (!exchange) return 0; LOG_DBG((LOG_MESSAGE, 90, "message_check_duplicate: last_received %p", exchange->last_received)); if (exchange->last_received) { LOG_DBG_BUF((LOG_MESSAGE, 95, "message_check_duplicate: last_received", exchange->last_received->orig, exchange->last_received->orig_sz)); /* Is it a duplicate, lose the new one. */ if (sz == exchange->last_received->orig_sz && memcmp(pkt, exchange->last_received->orig, sz) == 0) { LOG_DBG((LOG_MESSAGE, 80, "message_check_duplicate: dropping dup")); /* * Retransmit if the previos sent message was the last * of an exchange, otherwise just wait for the * ordinary retransmission. */ if (exchange->last_sent && (exchange->last_sent->flags & MSG_LAST)) message_send(exchange->last_sent); message_free(msg); return -1; } } /* * As this new message is an indication that state is moving forward * at the peer, remove the retransmit timer on our last message. */ if (exchange->last_sent) { if (exchange->last_sent == exchange->in_transit) { struct message *m = exchange->in_transit; TAILQ_REMOVE(m->transport->vtbl->get_queue(m), m, link); exchange->in_transit = 0; } message_free(exchange->last_sent); exchange->last_sent = 0; } return 0; } /* Helper to message_negotiate_sa. */ static INLINE struct payload * step_transform(struct payload *tp, struct payload **propp, struct payload **sap) { tp = TAILQ_NEXT(tp, link); if (tp) { *propp = tp->context; *sap = (*propp)->context; } return tp; } /* * Pick out the first transforms out of MSG (which should contain at least one * SA payload) we accept as a full protection suite. */ int message_negotiate_sa(struct message *msg, int (*validate)(struct exchange *, struct sa *, struct sa *)) { struct payload *tp, *propp, *sap, *next_tp = 0, *next_propp, *next_sap; struct payload *saved_tp = 0, *saved_propp = 0, *saved_sap = 0; struct sa *sa; struct proto *proto; int suite_ok_so_far = 0; struct exchange *exchange = msg->exchange; /* * This algorithm is a weird bottom-up thing... mostly due to the * payload links pointing upwards. * * The algorithm goes something like this: * Foreach transform * If transform is compatible * Remember that this protocol can work * Skip to last transform of this protocol * If next transform belongs to a new protocol inside the same suite * If no transform was found for the current protocol * Forget all earlier transforms for protocols in this suite * Skip to last transform of this suite * If next transform belongs to a new suite * If the current protocol had an OK transform * Skip to the last transform of this SA * If the next transform belongs to a new SA * If no transforms have been chosen * Issue a NO_PROPOSAL_CHOSEN notification */ sa = TAILQ_FIRST(&exchange->sa_list); for (tp = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM); tp; tp = next_tp) { propp = tp->context; sap = propp->context; sap->flags |= PL_MARK; next_tp = step_transform(tp, &next_propp, &next_sap); /* For each transform, see if it is compatible. */ if (!attribute_map(tp->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF, GET_ISAKMP_GEN_LENGTH(tp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, exchange->doi->is_attribute_incompatible, msg)) { LOG_DBG((LOG_NEGOTIATION, 30, "message_negotiate_sa: " "transform %d proto %d proposal %d ok", GET_ISAKMP_TRANSFORM_NO(tp->p), GET_ISAKMP_PROP_PROTO(propp->p), GET_ISAKMP_PROP_NO(propp->p))); if (sa_add_transform(sa, tp, exchange->initiator, &proto)) goto cleanup; suite_ok_so_far = 1; saved_tp = next_tp; saved_propp = next_propp; saved_sap = next_sap; /* Skip to last transform of this protocol proposal. */ while ((next_tp = step_transform(tp, &next_propp, &next_sap)) && next_propp == propp) tp = next_tp; } retry_transform: /* * Figure out if we will be looking at a new protocol proposal * inside the current protection suite. */ if (next_tp && propp != next_propp && sap == next_sap && (GET_ISAKMP_PROP_NO(propp->p) == GET_ISAKMP_PROP_NO(next_propp->p))) { if (!suite_ok_so_far) { LOG_DBG((LOG_NEGOTIATION, 30, "message_negotiate_sa: proto %d proposal " "%d failed", GET_ISAKMP_PROP_PROTO(propp->p), GET_ISAKMP_PROP_NO(propp->p))); /* * Remove potentially succeeded choices from * the SA. */ while (TAILQ_FIRST(&sa->protos)) TAILQ_REMOVE(&sa->protos, TAILQ_FIRST(&sa->protos), link); /* * Skip to the last transform of this * protection suite. */ while ((next_tp = step_transform(tp, &next_propp, &next_sap)) && (GET_ISAKMP_PROP_NO(next_propp->p) == GET_ISAKMP_PROP_NO(propp->p)) && next_sap == sap) tp = next_tp; } suite_ok_so_far = 0; } /* * Figure out if we will be looking at a new protection * suite. */ if (!next_tp || (propp != next_propp && (GET_ISAKMP_PROP_NO(propp->p) != GET_ISAKMP_PROP_NO(next_propp->p))) || sap != next_sap) { /* * Check if the suite we just considered was OK, if so * we check it against the accepted ones. */ if (suite_ok_so_far) { if (!validate || validate(exchange, sa, msg->isakmp_sa)) { LOG_DBG((LOG_NEGOTIATION, 30, "message_negotiate_sa: proposal " "%d succeeded", GET_ISAKMP_PROP_NO(propp->p))); /* * Skip to the last transform of this * SA. */ while ((next_tp = step_transform(tp, &next_propp, &next_sap)) && next_sap == sap) tp = next_tp; } else { /* Backtrack. */ LOG_DBG((LOG_NEGOTIATION, 30, "message_negotiate_sa: proposal " "%d failed", GET_ISAKMP_PROP_NO(propp->p))); next_tp = saved_tp; next_propp = saved_propp; next_sap = saved_sap; suite_ok_so_far = 0; /* * Remove potentially succeeded * choices from the SA. */ while (TAILQ_FIRST(&sa->protos)) TAILQ_REMOVE(&sa->protos, TAILQ_FIRST(&sa->protos), link); goto retry_transform; } } } /* Have we walked all the proposals of an SA? */ if (!next_tp || sap != next_sap) { if (!suite_ok_so_far) { /* * XXX We cannot possibly call this a drop... * seeing we just turn down one of the offers, * can we? I suggest renaming message_drop to * something else. */ log_print("message_negotiate_sa: no " "compatible proposal found"); message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); } sa = TAILQ_NEXT(sa, next); } } return 0; cleanup: /* * Remove potentially succeeded choices from the SA. * XXX Do we leak struct protos and related data here? */ while (TAILQ_FIRST(&sa->protos)) TAILQ_REMOVE(&sa->protos, TAILQ_FIRST(&sa->protos), link); return -1; } /* * Add SA, proposal and transform payload(s) to MSG out of information * found in the exchange MSG is part of.. */ int message_add_sa_payload(struct message *msg) { struct exchange *exchange = msg->exchange; u_int8_t *sa_buf, *saved_nextp_sa, *saved_nextp_prop; size_t sa_len, extra_sa_len; int i, nprotos = 0; struct proto *proto; u_int8_t **transforms = 0, **proposals = 0; size_t *transform_lens = 0, *proposal_lens = 0; struct sa *sa; struct doi *doi = exchange->doi; u_int8_t *spi = 0; size_t spi_sz; /* * Generate SA payloads. */ for (sa = TAILQ_FIRST(&exchange->sa_list); sa; sa = TAILQ_NEXT(sa, next)) { /* Setup a SA payload. */ sa_len = ISAKMP_SA_SIT_OFF + doi->situation_size(); extra_sa_len = 0; sa_buf = malloc(sa_len); if (!sa_buf) { log_error("message_add_sa_payload: " "malloc (%lu) failed", (unsigned long)sa_len); goto cleanup; } SET_ISAKMP_SA_DOI(sa_buf, doi->id); doi->setup_situation(sa_buf); /* Count transforms. */ nprotos = 0; for (proto = TAILQ_FIRST(&sa->protos); proto; proto = TAILQ_NEXT(proto, link)) nprotos++; /* * Allocate transient transform and proposal payload/size * vectors. */ transforms = calloc(nprotos, sizeof *transforms); if (!transforms) { log_error("message_add_sa_payload: calloc (%d, %lu) " "failed", nprotos, (unsigned long)sizeof *transforms); goto cleanup; } transform_lens = calloc(nprotos, sizeof *transform_lens); if (!transform_lens) { log_error("message_add_sa_payload: calloc (%d, %lu) " "failed", nprotos, (unsigned long) sizeof *transform_lens); goto cleanup; } proposals = calloc(nprotos, sizeof *proposals); if (!proposals) { log_error("message_add_sa_payload: calloc (%d, %lu) " "failed", nprotos, (unsigned long)sizeof *proposals); goto cleanup; } proposal_lens = calloc(nprotos, sizeof *proposal_lens); if (!proposal_lens) { log_error("message_add_sa_payload: calloc (%d, %lu) " "failed", nprotos, (unsigned long)sizeof *proposal_lens); goto cleanup; } /* Pick out the chosen transforms. */ for (proto = TAILQ_FIRST(&sa->protos), i = 0; proto; proto = TAILQ_NEXT(proto, link), i++) { transform_lens[i] = GET_ISAKMP_GEN_LENGTH(proto->chosen->p); transforms[i] = malloc(transform_lens[i]); if (!transforms[i]) { log_error("message_add_sa_payload: malloc " "(%lu) failed", (unsigned long)transform_lens[i]); goto cleanup; } /* Get incoming SPI from application. */ if (doi->get_spi) { spi = doi->get_spi(&spi_sz, GET_ISAKMP_PROP_PROTO(proto->chosen->context->p), msg); if (spi_sz && !spi) goto cleanup; proto->spi[1] = spi; proto->spi_sz[1] = spi_sz; } else spi_sz = 0; proposal_lens[i] = ISAKMP_PROP_SPI_OFF + spi_sz; proposals[i] = malloc(proposal_lens[i]); if (!proposals[i]) { log_error("message_add_sa_payload: malloc " "(%lu) failed", (unsigned long)proposal_lens[i]); goto cleanup; } memcpy(transforms[i], proto->chosen->p, transform_lens[i]); memcpy(proposals[i], proto->chosen->context->p, ISAKMP_PROP_SPI_OFF); SET_ISAKMP_PROP_NTRANSFORMS(proposals[i], 1); SET_ISAKMP_PROP_SPI_SZ(proposals[i], spi_sz); if (spi_sz) memcpy(proposals[i] + ISAKMP_PROP_SPI_OFF, spi, spi_sz); extra_sa_len += proposal_lens[i] + transform_lens[i]; } /* * Add the payloads. As this is a SA, we need to recompute the * lengths of the payloads containing others. We also need to * reset these payload's "next payload type" field. */ if (message_add_payload(msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1)) goto cleanup; SET_ISAKMP_GEN_LENGTH(sa_buf, sa_len + extra_sa_len); sa_buf = 0; saved_nextp_sa = msg->nextp; for (proto = TAILQ_FIRST(&sa->protos), i = 0; proto; proto = TAILQ_NEXT(proto, link), i++) { if (message_add_payload(msg, ISAKMP_PAYLOAD_PROPOSAL, proposals[i], proposal_lens[i], i > 1)) goto cleanup; SET_ISAKMP_GEN_LENGTH(proposals[i], proposal_lens[i] + transform_lens[i]); proposals[i] = 0; saved_nextp_prop = msg->nextp; if (message_add_payload(msg, ISAKMP_PAYLOAD_TRANSFORM, transforms[i], transform_lens[i], 0)) goto cleanup; msg->nextp = saved_nextp_prop; transforms[i] = 0; } msg->nextp = saved_nextp_sa; /* Free the temporary allocations made above. */ free(transforms); free(transform_lens); free(proposals); free(proposal_lens); } return 0; cleanup: if (sa_buf) free(sa_buf); for (i = 0; i < nprotos; i++) { if (transforms[i]) free(transforms[i]); if (proposals[i]) free(proposals[i]); } if (transforms) free(transforms); if (transform_lens) free(transform_lens); if (proposals) free(proposals); if (proposal_lens) free(proposal_lens); return -1; } /* * Return a copy of MSG's constants starting from OFFSET and stash the size * in SZP. It is the callers responsibility to free this up. */ u_int8_t * message_copy(struct message *msg, size_t offset, size_t *szp) { int skip = 0; size_t i, sz = 0; ssize_t start = -1; u_int8_t *buf, *p; /* Calculate size of message and where we want to start to copy. */ for (i = 1; i < msg->iovlen; i++) { sz += msg->iov[i].iov_len; if (sz <= offset) skip = i; else if (start < 0) start = offset - (sz - msg->iov[i].iov_len); } /* Allocate and copy. */ *szp = sz - offset; buf = malloc(*szp); if (!buf) return 0; p = buf; for (i = skip + 1; i < msg->iovlen; i++) { memcpy(p, (u_int8_t *) msg->iov[i].iov_base + start, msg->iov[i].iov_len - start); p += msg->iov[i].iov_len - start; start = 0; } return buf; } /* Register a post-send function POST_SEND with message MSG. */ int message_register_post_send(struct message *msg, void (*post_send)(struct message *)) { struct post_send *node; node = malloc(sizeof *node); if (!node) return -1; node->func = post_send; TAILQ_INSERT_TAIL(&msg->post_send, node, link); return 0; } /* Run the post-send functions of message MSG. */ void message_post_send(struct message *msg) { struct post_send *node; while ((node = TAILQ_FIRST(&msg->post_send)) != 0) { TAILQ_REMOVE(&msg->post_send, node, link); node->func(msg); free(node); } } /* Initialize and populate payload_map[]. */ void message_init(void) { u_int8_t i; memset(&payload_map, 0, sizeof payload_map); payload_index_max = sizeof payload_revmap / sizeof payload_revmap[0]; for (i = 0; i < payload_index_max; i++) { payload_map[payload_revmap[i]] = i; LOG_DBG((LOG_MESSAGE, 95, "message_init: payload_map[%d] = %d", payload_revmap[i], i)); } } struct payload * payload_first(struct message *msg, u_int8_t payload) { if (payload_map[payload]) return TAILQ_FIRST(&msg->payload[payload_map[payload]]); else return 0; } struct payload * payload_last(struct message *msg, u_int8_t payload) { if (payload_map[payload]) return TAILQ_LAST(&msg->payload[payload_map[payload]], payload_head); else return 0; } isakmpd-20041012.orig/ike_main_mode.c0000644000175000017500000000713310133045740017505 0ustar jdivejdive00000000000000/* $OpenBSD: ike_main_mode.c,v 1.15 2004/06/14 09:55:41 ho Exp $ */ /* $EOM: ike_main_mode.c,v 1.77 1999/04/25 22:12:34 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include "sysdep.h" #include "attribute.h" #include "conf.h" #include "constants.h" #include "crypto.h" #include "dh.h" #include "doi.h" #include "exchange.h" #include "hash.h" #include "ike_auth.h" #include "ike_main_mode.h" #include "ike_phase_1.h" #include "ipsec.h" #include "ipsec_doi.h" #include "isakmp.h" #include "log.h" #include "math_group.h" #include "message.h" #include "prf.h" #include "sa.h" #include "transport.h" #include "util.h" static int initiator_send_ID_AUTH(struct message *); static int responder_send_ID_AUTH(struct message *); static int responder_send_KE_NONCE(struct message *); int (*ike_main_mode_initiator[]) (struct message *) = { ike_phase_1_initiator_send_SA, ike_phase_1_initiator_recv_SA, ike_phase_1_initiator_send_KE_NONCE, ike_phase_1_initiator_recv_KE_NONCE, initiator_send_ID_AUTH, ike_phase_1_recv_ID_AUTH }; int (*ike_main_mode_responder[]) (struct message *) = { ike_phase_1_responder_recv_SA, ike_phase_1_responder_send_SA, ike_phase_1_recv_KE_NONCE, responder_send_KE_NONCE, ike_phase_1_recv_ID_AUTH, responder_send_ID_AUTH }; static int initiator_send_ID_AUTH(struct message *msg) { msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT; if (ike_phase_1_send_ID(msg)) return -1; if (ike_phase_1_send_AUTH(msg)) return -1; return ipsec_initial_contact(msg); } /* Send our public DH value and a nonce to the initiator. */ int responder_send_KE_NONCE(struct message *msg) { /* XXX Should we really just use the initiator's nonce size? */ if (ike_phase_1_send_KE_NONCE(msg, msg->exchange->nonce_i_len)) return -1; /* * Calculate DH values & key material in parallel with the message * going on a roundtrip over the wire. */ message_register_post_send(msg, (void (*)(struct message *))ike_phase_1_post_exchange_KE_NONCE); return 0; } static int responder_send_ID_AUTH(struct message *msg) { msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT; if (ike_phase_1_responder_send_ID_AUTH(msg)) return -1; return ipsec_initial_contact(msg); } isakmpd-20041012.orig/monitor.c0000644000175000017500000005664410133045740016427 0ustar jdivejdive00000000000000/* $OpenBSD: monitor.c,v 1.29 2004/08/12 11:21:07 hshoexer Exp $ */ /* * Copyright (c) 2003 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. * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined (USE_POLICY) #include #include #endif #include "sysdep.h" #include "conf.h" #include "log.h" #include "monitor.h" #include "policy.h" #include "ui.h" #include "util.h" #include "pf_key_v2.h" struct monitor_state { pid_t pid; int s; char root[MAXPATHLEN]; } m_state; volatile sig_atomic_t sigchlded = 0; extern volatile sig_atomic_t sigtermed; static volatile sig_atomic_t cur_state = STATE_INIT; /* Private functions. */ int m_write_int32(int, int32_t); int m_write_raw(int, char *, size_t); int m_read_int32(int, int32_t *); int m_read_raw(int, char *, size_t); void m_flush(int); static void m_priv_getfd(int); static void m_priv_getsocket(int); static void m_priv_setsockopt(int); static void m_priv_bind(int); static int m_priv_local_sanitize_path(char *, size_t, int); static int m_priv_check_sockopt(int, int); static int m_priv_check_bind(const struct sockaddr *, socklen_t); static void m_priv_increase_state(int); static void m_priv_test_state(int); static void m_priv_ui_init(int); static void m_priv_pfkey_open(int); /* * Public functions, unprivileged. */ /* Setup monitor context, fork, drop child privs. */ pid_t monitor_init(int debug) { struct passwd *pw; int p[2]; memset(&m_state, 0, sizeof m_state); if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, p) != 0) log_fatal("monitor_init: socketpair() failed"); pw = getpwnam(ISAKMPD_PRIVSEP_USER); if (pw == NULL) log_fatal("monitor_init: getpwnam(\"%s\") failed", ISAKMPD_PRIVSEP_USER); m_state.pid = fork(); m_state.s = p[m_state.pid ? 1 : 0]; strlcpy(m_state.root, pw->pw_dir, sizeof m_state.root); LOG_DBG((LOG_SYSDEP, 30, "monitor_init: pid %d my fd %d", m_state.pid, m_state.s)); /* The child process should drop privileges now. */ if (!m_state.pid) { if (chroot(pw->pw_dir) != 0 || chdir("/") != 0) log_fatal("monitor_init: chroot failed"); if (setgid(pw->pw_gid) != 0) log_fatal("monitor_init: setgid(%d) failed", pw->pw_gid); if (setuid(pw->pw_uid) != 0) log_fatal("monitor_init: setuid(%d) failed", pw->pw_uid); LOG_DBG((LOG_MISC, 10, "monitor_init: privileges dropped for child process")); } else { setproctitle("monitor [priv]"); } /* With "-dd", stop and wait here. For gdb "attach" etc. */ if (debug > 1) { log_print("monitor_init: stopped %s PID %d fd %d%s", m_state.pid ? "priv" : "child", getpid(), m_state.s, m_state.pid ? ", waiting for SIGCONT" : ""); kill(getpid(), SIGSTOP); /* Wait here for SIGCONT. */ if (m_state.pid) kill(m_state.pid, SIGCONT); /* Continue child. */ } return m_state.pid; } void monitor_exit(int code) { if (m_state.pid != 0) kill(m_state.pid, SIGKILL); exit(code); } void monitor_ui_init(void) { int32_t err; if (m_write_int32(m_state.s, MONITOR_UI_INIT)) goto errout; if (m_read_int32(m_state.s, &err)) goto errout; if (err != 0) { log_fatal("monitor_ui_init: parent could not create FIFO " "\"%s\"", ui_fifo); exit(1); } ui_socket = mm_receive_fd(m_state.s); if (ui_socket < 0) log_fatal("monitor_ui_init: parent could not create FIFO " "\"%s\"", ui_fifo); return; errout: log_error("monitor_ui_init: problem talking to privileged process"); return; } int monitor_pf_key_v2_open(void) { int32_t err; if (m_write_int32(m_state.s, MONITOR_PFKEY_OPEN)) goto errout; if (m_read_int32(m_state.s, &err)) goto errout; if (err < 0) { log_error("monitor_pf_key_v2_open: parent could not create " "PF_KEY socket"); return -1; } pf_key_v2_socket = mm_receive_fd(m_state.s); if (pf_key_v2_socket < 0) { log_error("monitor_pf_key_v2_open: mm_receive_fd() failed: %s", strerror(errno)); return -1; } return pf_key_v2_socket; errout: log_error("monitor_pf_key_v2_open: problem talking to privileged " "process"); return -1; } int monitor_open(const char *path, int flags, mode_t mode) { int fd, mode32 = (int32_t) mode; int32_t err; char realpath[MAXPATHLEN]; if (path[0] == '/') strlcpy(realpath, path, sizeof realpath); else snprintf(realpath, sizeof realpath, "%s/%s", m_state.root, path); /* Write data to priv process. */ if (m_write_int32(m_state.s, MONITOR_GET_FD)) goto errout; if (m_write_raw(m_state.s, realpath, strlen(realpath) + 1)) goto errout; if (m_write_int32(m_state.s, flags)) goto errout; if (m_write_int32(m_state.s, mode32)) goto errout; if (m_read_int32(m_state.s, &err)) goto errout; if (err != 0) { errno = (int) err; return -1; } /* Wait for response. */ fd = mm_receive_fd(m_state.s); if (fd < 0) { log_error("monitor_open: mm_receive_fd () failed: %s", strerror(errno)); return -1; } return fd; errout: log_error("monitor_open: problem talking to privileged process"); return -1; } FILE * monitor_fopen(const char *path, const char *mode) { FILE *fp; int fd, flags = 0, saved_errno; mode_t mask, cur_umask; /* Only the child process is supposed to run this. */ if (m_state.pid) log_fatal("[priv] bad call to monitor_fopen"); switch (mode[0]) { case 'r': flags = (mode[1] == '+' ? O_RDWR : O_RDONLY); break; case 'w': flags = (mode[1] == '+' ? O_RDWR : O_WRONLY) | O_CREAT | O_TRUNC; break; case 'a': flags = (mode[1] == '+' ? O_RDWR : O_WRONLY) | O_CREAT | O_APPEND; break; default: log_fatal("monitor_fopen: bad call"); } cur_umask = umask(0); (void)umask(cur_umask); mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; mask &= ~cur_umask; fd = monitor_open(path, flags, mask); if (fd < 0) return NULL; /* Got the fd, attach a FILE * to it. */ fp = fdopen(fd, mode); if (!fp) { log_error("monitor_fopen: fdopen() failed"); saved_errno = errno; close(fd); errno = saved_errno; return NULL; } return fp; } int monitor_stat(const char *path, struct stat *sb) { int fd, r, saved_errno; /* O_NONBLOCK is needed for stat'ing fifos. */ fd = monitor_open(path, O_RDONLY | O_NONBLOCK, 0); if (fd < 0) return -1; r = fstat(fd, sb); saved_errno = errno; close(fd); errno = saved_errno; return r; } int monitor_socket(int domain, int type, int protocol) { int s; int32_t err; if (m_write_int32(m_state.s, MONITOR_GET_SOCKET)) goto errout; if (m_write_int32(m_state.s, (int32_t)domain)) goto errout; if (m_write_int32(m_state.s, (int32_t)type)) goto errout; if (m_write_int32(m_state.s, (int32_t)protocol)) goto errout; if (m_read_int32(m_state.s, &err)) goto errout; if (err != 0) { errno = (int)err; return -1; } /* Read result. */ s = mm_receive_fd(m_state.s); if (s < 0) { log_error("monitor_socket: mm_receive_fd () failed: %s", strerror(errno)); return -1; } return s; errout: log_error("monitor_socket: problem talking to privileged process"); return -1; } int monitor_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) { int32_t ret, err; if (m_write_int32(m_state.s, MONITOR_SETSOCKOPT)) goto errout; if (mm_send_fd(m_state.s, s)) goto errout; if (m_write_int32(m_state.s, (int32_t)level)) goto errout; if (m_write_int32(m_state.s, (int32_t)optname)) goto errout; if (m_write_int32(m_state.s, (int32_t)optlen)) goto errout; if (m_write_raw(m_state.s, (char *)optval, (size_t)optlen)) goto errout; if (m_read_int32(m_state.s, &err)) goto errout; if (err != 0) errno = (int)err; if (m_read_int32(m_state.s, &ret)) goto errout; return (int)ret; errout: log_print("monitor_setsockopt: read/write error"); return -1; } int monitor_bind(int s, const struct sockaddr *name, socklen_t namelen) { int32_t ret, err; if (m_write_int32(m_state.s, MONITOR_BIND)) goto errout; if (mm_send_fd(m_state.s, s)) goto errout; if (m_write_int32(m_state.s, (int32_t)namelen)) goto errout; if (m_write_raw(m_state.s, (char *)name, (size_t)namelen)) goto errout; if (m_read_int32(m_state.s, &err)) goto errout; if (err != 0) errno = (int)err; if (m_read_int32(m_state.s, &ret)) goto errout; return (int)ret; errout: log_print("monitor_bind: read/write error"); return -1; } struct monitor_dirents * monitor_opendir(const char *path) { char *buf, *cp; size_t bufsize; int fd, nbytes, entries; long base; struct stat sb; struct dirent *dp; struct monitor_dirents *direntries; fd = monitor_open(path, 0, O_RDONLY); if (fd < 0) { log_error("monitor_opendir: opendir(\"%s\") failed", path); return NULL; } /* Now build a list with all dirents from fd. */ if (fstat(fd, &sb) < 0) { (void)close(fd); return NULL; } if (!S_ISDIR(sb.st_mode)) { (void)close(fd); errno = EACCES; return NULL; } bufsize = sb.st_size; if (bufsize < sb.st_blksize) bufsize = sb.st_blksize; buf = calloc(bufsize, sizeof(char)); if (buf == NULL) { (void)close(fd); errno = EACCES; return NULL; } nbytes = getdirentries(fd, buf, bufsize, &base); if (nbytes <= 0) { (void)close(fd); free(buf); errno = EACCES; return NULL; } (void)close(fd); for (entries = 0, cp = buf; cp < buf + nbytes;) { dp = (struct dirent *)cp; cp += dp->d_reclen; entries++; } direntries = calloc(1, sizeof(struct monitor_dirents)); if (direntries == NULL) { free(buf); errno = EACCES; return NULL; } direntries->dirents = calloc(entries + 1, sizeof(struct dirent *)); if (direntries->dirents == NULL) { free(buf); free(direntries); errno = EACCES; return NULL; } direntries->current = 0; for (entries = 0, cp = buf; cp < buf + nbytes;) { dp = (struct dirent *)cp; direntries->dirents[entries++] = dp; cp += dp->d_reclen; } direntries->dirents[entries] = NULL; return direntries; } struct dirent * monitor_readdir(struct monitor_dirents *direntries) { if (direntries->dirents[direntries->current] != NULL) return direntries->dirents[direntries->current++]; return NULL; } int monitor_closedir(struct monitor_dirents *direntries) { free(direntries->dirents); free(direntries); return 0; } void monitor_init_done(void) { if (m_write_int32(m_state.s, MONITOR_INIT_DONE)) log_print("monitor_init_done: read/write error"); return; } /* * Start of code running with privileges (the monitor process). */ /* Help functions for monitor_loop(). */ static void monitor_got_sigchld(int sig) { sigchlded = 1; } static void sig_pass_to_chld(int sig) { int oerrno = errno; if (m_state.pid != -1) kill(m_state.pid, sig); errno = oerrno; } /* This function is where the privileged process waits(loops) indefinitely. */ void monitor_loop(int debug) { pid_t pid; fd_set *fds; size_t fdsn; int status, n, maxfd; if (!debug) log_to(0); maxfd = m_state.s + 1; fdsn = howmany(maxfd, NFDBITS) * sizeof(fd_mask); fds = (fd_set *)malloc(fdsn); if (!fds) { kill(m_state.pid, SIGTERM); log_fatal("monitor_loop: malloc (%lu) failed", (unsigned long)fdsn); return; } /* If the child dies, we should shutdown also. */ signal(SIGCHLD, monitor_got_sigchld); /* SIGHUP, SIGUSR1 and SIGUSR2 will be forwarded to child. */ signal(SIGHUP, sig_pass_to_chld); signal(SIGUSR1, sig_pass_to_chld); signal(SIGUSR2, sig_pass_to_chld); while (cur_state < STATE_QUIT) { /* * Currently, there is no need for us to hang around if the * child is in the process of shutting down. */ if (sigtermed) { m_priv_increase_state(STATE_QUIT); kill(m_state.pid, SIGTERM); break; } if (sigchlded) { do { pid = waitpid(m_state.pid, &status, WNOHANG); } while (pid == -1 && errno == EINTR); if (pid == m_state.pid && (WIFEXITED(status) || WIFSIGNALED(status))) { m_priv_increase_state(STATE_QUIT); break; } } memset(fds, 0, fdsn); FD_SET(m_state.s, fds); n = select(maxfd, fds, NULL, NULL, NULL); if (n == -1) { if (errno != EINTR) { log_error("select"); sleep(1); } } else if (n) if (FD_ISSET(m_state.s, fds)) { int32_t msgcode; if (m_read_int32(m_state.s, &msgcode)) m_flush(m_state.s); else switch (msgcode) { case MONITOR_GET_FD: m_priv_getfd(m_state.s); break; case MONITOR_UI_INIT: LOG_DBG((LOG_MISC, 80, "%s: MONITOR_UI_INIT", __func__)); m_priv_test_state(STATE_INIT); m_priv_ui_init(m_state.s); break; case MONITOR_PFKEY_OPEN: LOG_DBG((LOG_MISC, 80, "%s: MONITOR_PFKEY_OPEN", __func__)); m_priv_test_state(STATE_INIT); m_priv_pfkey_open(m_state.s); break; case MONITOR_GET_SOCKET: LOG_DBG((LOG_MISC, 80, "%s: MONITOR_GET_SOCKET", __func__)); m_priv_test_state(STATE_INIT); m_priv_getsocket(m_state.s); break; case MONITOR_SETSOCKOPT: LOG_DBG((LOG_MISC, 80, "%s: MONITOR_SETSOCKOPT", __func__)); m_priv_test_state(STATE_INIT); m_priv_setsockopt(m_state.s); break; case MONITOR_BIND: LOG_DBG((LOG_MISC, 80, "%s: MONITOR_BIND", __func__)); m_priv_test_state(STATE_INIT); m_priv_bind(m_state.s); break; case MONITOR_INIT_DONE: LOG_DBG((LOG_MISC, 80, "%s: MONITOR_INIT_DONE", __func__)); m_priv_test_state(STATE_INIT); m_priv_increase_state( STATE_RUNNING); break; case MONITOR_SHUTDOWN: LOG_DBG((LOG_MISC, 80, "%s: MONITOR_SHUTDOWN", __func__)); m_priv_increase_state( STATE_QUIT); break; default: log_print("monitor_loop: " "got unknown code %d", msgcode); } } } free(fds); exit(0); } /* Privileged: called by monitor_loop. */ static void m_priv_ui_init(int s) { int32_t err; ui_init(); if (ui_socket >= 0) err = 0; else err = -1; if (m_write_int32(s, err)) goto errout; if (ui_socket >= 0 && mm_send_fd(s, ui_socket)) { close(ui_socket); goto errout; } /* In case of stdin, we do not close the socket. */ if (ui_socket > 0) close(ui_socket); return; errout: log_error("m_priv_ui_init: read/write operation failed"); return; } /* Privileged: called by monitor_loop. */ static void m_priv_pfkey_open(int s) { int fd; int32_t err; fd = pf_key_v2_open(); if (fd < 0) err = -1; else err = 0; if (m_write_int32(s, err)) goto errout; if (fd > 0 && mm_send_fd(s, fd)) { close(fd); goto errout; } close(fd); return; errout: log_error("m_priv_pfkey_open: read/write operation failed"); return; } /* Privileged: called by monitor_loop. */ static void m_priv_getfd(int s) { char path[MAXPATHLEN]; int32_t v, err; int flags; mode_t mode; /* * We expect the following data on the socket: * u_int32_t pathlen * path * u_int32_t flags * u_int32_t mode */ if (m_read_raw(s, path, MAXPATHLEN)) goto errout; if (m_read_int32(s, &v)) goto errout; flags = (int)v; if (m_read_int32(s, &v)) goto errout; mode = (mode_t) v; if (m_priv_local_sanitize_path(path, sizeof path, flags) != 0) { err = EACCES; v = -1; } else { err = 0; v = (int32_t)open(path, flags, mode); if (v < 0) err = (int32_t)errno; } if (m_write_int32(s, err)) goto errout; if (v > 0 && mm_send_fd(s, v)) { close(v); goto errout; } close(v); return; errout: log_error("m_priv_getfd: read/write operation failed"); return; } /* Privileged: called by monitor_loop. */ static void m_priv_getsocket(int s) { int domain, type, protocol; int32_t v, err; if (m_read_int32(s, &v)) goto errout; domain = (int)v; if (m_read_int32(s, &v)) goto errout; type = (int)v; if (m_read_int32(s, &v)) goto errout; protocol = (int)v; err = 0; v = (int32_t)socket(domain, type, protocol); if (v < 0) err = (int32_t)errno; if (m_write_int32(s, err)) goto errout; if (v > 0 && mm_send_fd(s, v)) { close(v); goto errout; } close(v); return; errout: log_error("m_priv_getsocket: read/write operation failed"); return; } /* Privileged: called by monitor_loop. */ static void m_priv_setsockopt(int s) { int sock, level, optname; char *optval = 0; socklen_t optlen; int32_t v, err; sock = mm_receive_fd(s); if (sock < 0) goto errout; if (m_read_int32(s, &level)) goto errout; if (m_read_int32(s, &optname)) goto errout; if (m_read_int32(s, &optlen)) goto errout; optval = (char *)malloc(optlen); if (!optval) goto errout; if (m_read_raw(s, optval, optlen)) goto errout; if (m_priv_check_sockopt(level, optname) != 0) { err = EACCES; v = -1; } else { err = 0; v = (int32_t)setsockopt(sock, level, optname, optval, optlen); if (v < 0) err = (int32_t)errno; } close(sock); sock = -1; if (m_write_int32(s, err)) goto errout; if (m_write_int32(s, v)) goto errout; free(optval); return; errout: log_print("m_priv_setsockopt: read/write error"); if (optval) free(optval); if (sock >= 0) close(sock); return; } /* Privileged: called by monitor_loop. */ static void m_priv_bind(int s) { int sock; struct sockaddr *name = 0; socklen_t namelen; int32_t v, err; sock = mm_receive_fd(s); if (sock < 0) goto errout; if (m_read_int32(s, &v)) goto errout; namelen = (socklen_t) v; name = (struct sockaddr *)malloc(namelen); if (!name) goto errout; if (m_read_raw(s, (char *)name, (size_t)namelen)) goto errout; if (m_priv_check_bind(name, namelen) != 0) { err = EACCES; v = -1; } else { err = 0; v = (int32_t)bind(sock, name, namelen); if (v < 0) { log_error("m_priv_bind: bind(%d,%p,%d) returned %d", sock, name, namelen, v); err = (int32_t)errno; } } close(sock); sock = -1; if (m_write_int32(s, err)) goto errout; if (m_write_int32(s, v)) goto errout; free(name); return; errout: log_print("m_priv_bind: read/write error"); if (name) free(name); if (sock >= 0) close(sock); return; } /* * Help functions, used by both privileged and unprivileged code */ /* Write a 32-bit value to a socket. */ int m_write_int32(int s, int32_t value) { u_int32_t v; memcpy(&v, &value, sizeof v); return (write(s, &v, sizeof v) == -1); } /* Write a number of bytes of data to a socket. */ int m_write_raw(int s, char *data, size_t dlen) { if (m_write_int32(s, (int32_t) dlen)) return 1; return (write(s, data, dlen) == -1); } int m_read_int32(int s, int32_t *value) { u_int32_t v; if (read(s, &v, sizeof v) != sizeof v) return 1; memcpy(value, &v, sizeof v); return 0; } int m_read_raw(int s, char *data, size_t maxlen) { u_int32_t v; int r; if (m_read_int32(s, &v)) return 1; if (v > maxlen) return 1; r = read(s, data, v); return (r == -1); } /* Drain all available input on a socket. */ void m_flush(int s) { u_int8_t tmp; int one = 1; ioctl(s, FIONBIO, &one);/* Non-blocking */ while (read(s, &tmp, 1) > 0); ioctl(s, FIONBIO, 0); /* Blocking */ } /* Check that path/mode is permitted. */ static int m_priv_local_sanitize_path(char *path, size_t pmax, int flags) { char *p; /* * We only permit paths starting with * /etc/isakmpd/ (read only) * /var/run/ (rw) */ if (strlen(path) < strlen("/var/run/")) goto bad_path; /* Any path containing '..' is invalid. */ for (p = path; *p && (p - path) < (int)pmax; p++) if (*p == '.' && *(p + 1) == '.') goto bad_path; /* For any write-mode, only a few paths are permitted. */ if ((flags & O_ACCMODE) != O_RDONLY) { if (strncmp("/var/run/", path, strlen("/var/run/")) == 0) return 0; goto bad_path; } /* Any other path is read-only. */ if (strncmp(ISAKMPD_ROOT, path, strlen(ISAKMPD_ROOT)) == 0 || strncmp("/var/run/", path, strlen("/var/run/")) == 0) return 0; bad_path: log_print("m_priv_local_sanitize_path: illegal path \"%.1023s\", " "replaced with \"/dev/null\"", path); strlcpy(path, "/dev/null", pmax); return 1; } /* Check setsockopt */ static int m_priv_check_sockopt(int level, int name) { switch (level) { /* These are allowed */ case SOL_SOCKET: case IPPROTO_IP: case IPPROTO_IPV6: break; default: log_print("m_priv_check_sockopt: Illegal level %d", level); return 1; } switch (name) { /* These are allowed */ case SO_REUSEPORT: case SO_REUSEADDR: case IP_AUTH_LEVEL: case IP_ESP_TRANS_LEVEL: case IP_ESP_NETWORK_LEVEL: case IP_IPCOMP_LEVEL: case IPV6_AUTH_LEVEL: case IPV6_ESP_TRANS_LEVEL: case IPV6_ESP_NETWORK_LEVEL: case IPV6_IPCOMP_LEVEL: break; default: log_print("m_priv_check_sockopt: Illegal option name %d", name); return 1; } return 0; } /* Check bind */ static int m_priv_check_bind(const struct sockaddr *sa, socklen_t salen) { in_port_t port; if (sa == NULL) { log_print("NULL address"); return 1; } if (sysdep_sa_len((struct sockaddr *)sa) != salen) { log_print("Length mismatch: %d %d", (int)sysdep_sa_len((struct sockaddr *)sa), (int)salen); return 1; } switch (sa->sa_family) { case AF_INET: if (salen != sizeof(struct sockaddr_in)) { log_print("Invalid inet address length"); return 1; } port = ((const struct sockaddr_in *)sa)->sin_port; break; case AF_INET6: if (salen != sizeof(struct sockaddr_in6)) { log_print("Invalid inet6 address length"); return 1; } port = ((const struct sockaddr_in6 *)sa)->sin6_port; break; default: log_print("Unknown address family"); return 1; } port = ntohs(port); if (port != ISAKMP_PORT_DEFAULT && port < 1024) { log_print("Disallowed port %u", port); return 1; } return 0; } /* Increase state into less permissive mode */ static void m_priv_increase_state(int state) { if (state <= cur_state) log_print("m_priv_increase_state: attempt to decrase state " "or match current state"); if (state < STATE_INIT || state > STATE_QUIT) log_print("m_priv_increase_state: attempt to switch to " "invalid state"); cur_state = state; } static void m_priv_test_state(int state) { if (cur_state != state) log_print("m_priv_test_state: Illegal state: %d != %d", (int)cur_state, state); return; } isakmpd-20041012.orig/isakmp_cfg.h0000644000175000017500000000371110133045740017033 0ustar jdivejdive00000000000000/* $OpenBSD: isakmp_cfg.h,v 1.5 2004/05/23 18:17:56 hshoexer Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Gatespace * (http://www.gatespace.com/). */ #ifndef _ISAKMP_CFG_H_ #define _ISAKMP_CFG_H_ #include struct isakmp_cfg_attr { LIST_ENTRY(isakmp_cfg_attr) link; u_int16_t type; u_int8_t attr_used; /* 8 bits just to be well-aligned. */ u_int8_t ignore; size_t length; void *value; }; struct message; extern int (*isakmp_cfg_initiator[])(struct message *); extern int (*isakmp_cfg_responder[])(struct message *); extern int16_t script_transaction[]; #endif /* _ISAKMP_CFG_H_ */ isakmpd-20041012.orig/ike_aggressive.c0000644000175000017500000001251210133045740017711 0ustar jdivejdive00000000000000/* $OpenBSD: ike_aggressive.c,v 1.8 2004/07/29 08:54:08 ho Exp $ */ /* $EOM: ike_aggressive.c,v 1.4 2000/01/31 22:33:45 niklas Exp $ */ /* * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999 Angelos D. Keromytis. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include "sysdep.h" #include "attribute.h" #include "conf.h" #include "constants.h" #include "crypto.h" #include "dh.h" #include "doi.h" #include "exchange.h" #include "hash.h" #include "ike_auth.h" #include "ike_aggressive.h" #include "ike_phase_1.h" #include "ipsec.h" #include "ipsec_doi.h" #include "isakmp.h" #include "log.h" #include "math_group.h" #include "message.h" #if defined (USE_NAT_TRAVERSAL) #include "nat_traversal.h" #endif #include "prf.h" #include "sa.h" #include "transport.h" #include "util.h" static int initiator_recv_SA_KE_NONCE_ID_AUTH(struct message *); static int initiator_send_SA_KE_NONCE_ID(struct message *); static int initiator_send_AUTH(struct message *); static int responder_recv_SA_KE_NONCE_ID(struct message *); static int responder_send_SA_KE_NONCE_ID_AUTH(struct message *); static int responder_recv_AUTH(struct message *); int (*ike_aggressive_initiator[])(struct message *) = { initiator_send_SA_KE_NONCE_ID, initiator_recv_SA_KE_NONCE_ID_AUTH, initiator_send_AUTH }; int (*ike_aggressive_responder[])(struct message *) = { responder_recv_SA_KE_NONCE_ID, responder_send_SA_KE_NONCE_ID_AUTH, responder_recv_AUTH }; /* Offer a set of transforms to the responder in the MSG message. */ static int initiator_send_SA_KE_NONCE_ID(struct message *msg) { if (ike_phase_1_initiator_send_SA(msg)) return -1; if (ike_phase_1_initiator_send_KE_NONCE(msg)) return -1; return ike_phase_1_send_ID(msg); } /* Figure out what transform the responder chose. */ static int initiator_recv_SA_KE_NONCE_ID_AUTH(struct message *msg) { if (ike_phase_1_initiator_recv_SA(msg)) return -1; if (ike_phase_1_initiator_recv_KE_NONCE(msg)) return -1; return ike_phase_1_recv_ID_AUTH(msg); } static int initiator_send_AUTH(struct message *msg) { msg->exchange->flags |= EXCHANGE_FLAG_ENCRYPT; if (ike_phase_1_send_AUTH(msg)) return -1; /* * RFC 2407 4.6.3 says that, among others, INITIAL-CONTACT MUST NOT * be sent in Aggressive Mode. This leaves us with the choice of * doing it in an informational exchange of its own with no delivery * guarantee or in the first Quick Mode, or not at all. * draft-jenkins-ipsec-rekeying-01.txt has some text that requires * INITIAL-CONTACT in phase 1, thus contradicting what we learned * above. I will bring this up in the IPsec list. For now we don't * do INITIAL-CONTACT at all when using aggressive mode. */ return 0; } /* * Accept a set of transforms offered by the initiator and chose one we can * handle. Also accept initiator's public DH value, nonce and ID. */ static int responder_recv_SA_KE_NONCE_ID(struct message *msg) { if (ike_phase_1_responder_recv_SA(msg)) return -1; if (ike_phase_1_recv_ID(msg)) return -1; return ike_phase_1_recv_KE_NONCE(msg); } /* * Reply with the transform we chose. Send our public DH value and a nonce * to the initiator. */ static int responder_send_SA_KE_NONCE_ID_AUTH(struct message *msg) { /* Add the SA payload with the transform that was chosen. */ if (ike_phase_1_responder_send_SA(msg)) return -1; /* XXX Should we really just use the initiator's nonce size? */ if (ike_phase_1_send_KE_NONCE(msg, msg->exchange->nonce_i_len)) return -1; if (ike_phase_1_post_exchange_KE_NONCE(msg)) return -1; return ike_phase_1_responder_send_ID_AUTH(msg); } /* * Reply with the transform we chose. Send our public DH value and a nonce * to the initiator. */ static int responder_recv_AUTH(struct message *msg) { if (ike_phase_1_recv_AUTH(msg)) return -1; #if defined (USE_NAT_TRAVERSAL) /* Aggressive: Check for NAT-D payloads and contents. */ if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER) (void)nat_t_exchange_check_nat_d(msg); #endif return 0; } isakmpd-20041012.orig/ui.h0000644000175000017500000000341110133045740015342 0ustar jdivejdive00000000000000/* $OpenBSD: ui.h,v 1.7 2004/05/13 06:56:34 ho Exp $ */ /* $EOM: ui.h,v 1.5 1998/12/01 10:20:12 niklas Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _UI_H_ #define _UI_H_ #define FIFO "/var/run/isakmpd.fifo" #define RESULT_FILE "/var/run/isakmpd.result" extern char *ui_fifo; extern int ui_socket; extern void ui_handler(void); extern void ui_init(void); extern void ui_report(char *); #endif /* _UI_H_ */ isakmpd-20041012.orig/monitor.h0000644000175000017500000000646110133045740016424 0ustar jdivejdive00000000000000/* $OpenBSD: monitor.h,v 1.11 2004/06/26 06:07:03 hshoexer Exp $ */ /* * Copyright (c) 2003 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. * * 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. */ #ifndef _MONITOR_H_ #define _MONITOR_H_ #if defined (USE_PRIVSEP) #include #include #include #include #define ISAKMPD_PRIVSEP_USER "_isakmpd" #define ISAKMP_PORT_DEFAULT 500 enum monitor_reqtypes { MONITOR_UI_INIT, MONITOR_PFKEY_OPEN, MONITOR_GET_FD, MONITOR_GET_SOCKET, MONITOR_SETSOCKOPT, MONITOR_BIND, MONITOR_MKFIFO, MONITOR_INIT_DONE, MONITOR_SHUTDOWN }; enum priv_state { STATE_INIT, /* just started */ STATE_RUNNING, /* running */ STATE_QUIT /* shutting down */ }; struct monitor_dirents { int current; struct dirent **dirents; }; pid_t monitor_init(int); void monitor_loop(int); int mm_send_fd(int, int); int mm_receive_fd(int); FILE *monitor_fopen(const char *, const char *); int monitor_open(const char *, int, mode_t); int monitor_stat(const char *, struct stat *); int monitor_socket(int, int, int); int monitor_setsockopt(int, int, int, const void *, socklen_t); int monitor_bind(int, const struct sockaddr *, socklen_t); int monitor_mkfifo(const char *, mode_t); struct monitor_dirents *monitor_opendir(const char *); struct dirent *monitor_readdir(struct monitor_dirents *); int monitor_closedir(struct monitor_dirents *); void monitor_init_done(void); void monitor_ui_init(void); int monitor_pf_key_v2_open(void); void monitor_exit(int); #else /* !USE_PRIVSEP */ #define monitor_fopen fopen #define monitor_open open #define monitor_stat stat #define monitor_socket socket #define monitor_setsockopt setsockopt #define monitor_bind bind #define monitor_mkfifo mkfifo #define monitor_opendir opendir #define monitor_readdir readdir #define monitor_closedir closedir #define monitor_ui_init ui_init #define monitor_exit exit #define monitor_pf_key_v2_open pf_key_v2_open #endif /* USE_PRIVSEP */ #endif /* _MONITOR_H_ */ isakmpd-20041012.orig/ipsec_fld.fld0000644000175000017500000000454710133045740017206 0ustar jdivejdive00000000000000# $OpenBSD: ipsec_fld.fld,v 1.5 2003/06/03 14:28:16 ho Exp $ # $EOM: ipsec_fld.fld,v 1.1 1998/08/02 20:12:02 niklas Exp $ # # Copyright (c) 1998 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # XXX There are num-declared fields below that really are csts. # IPsec's situation field's subdivision. IPSEC_SIT SIT mask 4 ipsec_sit_cst LABELED_DOMAIN_ID num 4 SECRECY_LENGTH num 2 RESERVED_1 ign 2 # The following fields' offsets need the secrecy length added + 32bit # alignment. SECRECY_CAT_LENGTH num 2 RESERVED_2 ign 2 # The following fields' offsets need the secrecy cat length added + 32bit # alignment on top of the aforementioned offset. INTEGRITY_LENGTH num 2 RESERVED_3 ign 2 # The following fields' offsets need the integrity length added + 32bit # alignment on top of the aforementioned offset. INTEGRITY_CAT_LENGTH num 2 RESERVED_4 ign 2 # The IPSEC_SIT record's length need the integrity cat length added + 32bit # alignment on top of the aforementioned offset. . # IPsec's layout of the identification payload's DOI data field. IPSEC_ID PROTO num 1 PORT num 2 . isakmpd-20041012.orig/ipsec.h0000644000175000017500000001247510133045740016042 0ustar jdivejdive00000000000000/* $OpenBSD: ipsec.h,v 1.24 2004/05/23 18:17:56 hshoexer Exp $ */ /* $EOM: ipsec.h,v 1.42 2000/12/03 07:58:20 angelos Exp $ */ /* * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2001 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _IPSEC_H_ #define _IPSEC_H_ #include #include #include #include "ipsec_doi.h" #ifdef USE_ISAKMP_CFG #include "isakmp_cfg.h" #endif struct group; struct hash; struct ike_auth; struct message; struct proto; struct sa; /* * IPsec-specific data to be linked into the exchange struct. * XXX Should probably be several different structs, one for each kind * of exchange, i.e. phase 1, phase 2 and ISAKMP configuration parameters * separated. */ struct ipsec_exch { u_int flags; struct hash *hash; struct ike_auth *ike_auth; struct group *group; u_int16_t prf_type; /* 0 if no KEY_EXCH was proposed, 1 otherwise */ u_int8_t pfs; /* * A copy of the initiator SA payload body for later computation of * hashes. Phase 1 only. */ size_t sa_i_b_len; u_int8_t *sa_i_b; /* Diffie-Hellman values. */ size_t g_x_len; u_int8_t *g_xi; u_int8_t *g_xr; u_int8_t *g_xy; /* SKEYIDs. XXX Phase 1 only? */ size_t skeyid_len; u_int8_t *skeyid; u_int8_t *skeyid_d; u_int8_t *skeyid_a; u_int8_t *skeyid_e; /* HASH_I & HASH_R. XXX Do these need to be saved here? */ u_int8_t *hash_i; u_int8_t *hash_r; /* KEYMAT */ size_t keymat_len; /* Phase 2. */ u_int8_t *id_ci; size_t id_ci_sz; u_int8_t *id_cr; size_t id_cr_sz; #ifdef USE_ISAKMP_CFG /* ISAKMP configuration mode parameters */ u_int16_t cfg_id; u_int16_t cfg_type; LIST_HEAD(isakmp_cfg_attr_head, isakmp_cfg_attr) attrs; #endif }; #define IPSEC_EXCH_FLAG_NO_ID 1 struct ipsec_sa { /* Phase 1. */ u_int8_t hash; size_t skeyid_len; u_int8_t *skeyid_d; u_int8_t *skeyid_a; u_int16_t prf_type; /* Phase 2. */ u_int16_t group_desc; /* Tunnel parameters. These are in network byte order. */ struct sockaddr *src_net; struct sockaddr *src_mask; struct sockaddr *dst_net; struct sockaddr *dst_mask; u_int8_t tproto; u_int16_t sport; u_int16_t dport; }; struct ipsec_proto { /* Phase 2. */ u_int16_t encap_mode; u_int16_t auth; u_int16_t keylen; u_int16_t keyrounds; /* This is not negotiated, but rather configured. */ int32_t replay_window; /* KEYMAT */ u_int8_t *keymat[2]; }; extern u_int8_t *ipsec_add_hash_payload(struct message *, size_t); extern int ipsec_ah_keylength(struct proto *); extern u_int8_t *ipsec_build_id(char *, size_t *); extern int ipsec_decode_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); extern void ipsec_decode_transform(struct message *, struct sa *, struct proto *, u_int8_t *); extern int ipsec_esp_authkeylength(struct proto *); extern int ipsec_esp_enckeylength(struct proto *); extern int ipsec_fill_in_hash(struct message *); extern int ipsec_gen_g_x(struct message *); extern int ipsec_get_id(char *, int *, struct sockaddr **, struct sockaddr **, u_int8_t *, u_int16_t *); extern ssize_t ipsec_id_size(char *, u_int8_t *); extern char *ipsec_id_string(u_int8_t *, size_t); extern void ipsec_init(void); extern int ipsec_initial_contact(struct message *); extern int ipsec_is_attribute_incompatible(u_int16_t, u_int8_t *, u_int16_t, void *); extern int ipsec_keymat_length(struct proto *); extern int ipsec_save_g_x(struct message *); extern struct sa *ipsec_sa_lookup(struct sockaddr *, u_int32_t, u_int8_t); extern char *ipsec_decode_ids(char *, u_int8_t *, size_t, u_int8_t *, size_t, int); extern int ipsec_clone_id(u_int8_t **, size_t *, u_int8_t *, size_t); #endif /* _IPSEC_H_ */ isakmpd-20041012.orig/math_mp.h0000644000175000017500000000353510133045740016361 0ustar jdivejdive00000000000000/* $OpenBSD: math_mp.h,v 1.6 2004/04/15 18:39:26 deraadt Exp $ */ /* $EOM: math_mp.h,v 1.4 2000/09/16 09:41:43 ho Exp $ */ /* * Copyright (c) 1999, 2000 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _MATH_MP_H_ #define _MATH_MP_H_ #define MP_FLAVOUR_GMP 1 #define MP_FLAVOUR_OPENSSL 2 #if MP_FLAVOUR == MP_FLAVOUR_GMP #include #define math_mp_t mpz_t #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL #include typedef BIGNUM *math_mp_t; #else #error "No multiprecision math library chosen." #endif #endif /* _MATH_MP_H_ */ isakmpd-20041012.orig/genfields.sh0000644000175000017500000001031310133045740017047 0ustar jdivejdive00000000000000# $OpenBSD: genfields.sh,v 1.9 2004/04/15 18:39:25 deraadt Exp $ # $EOM: genfields.sh,v 1.5 1999/04/02 01:15:55 niklas Exp $ # # Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # base=`basename $1` upcased_name=`echo $base |tr a-z A-Z` awk=${AWK:-awk} locase_function='function locase (str) { cmd = "echo " str " |tr A-Z a-z" cmd | getline retval; close (cmd); return retval; }' $awk " $locase_function "' BEGIN { print "/* DO NOT EDIT-- this file is automatically generated. */\n" print "#ifndef _'$upcased_name'_H_" print "#define _'$upcased_name'_H_\n" print "#include \"sysdep.h\"\n" print "#include \"field.h\"\n" print "struct constant_map;\n" } /^#/ { next } /^\./ { printf ("#define %s_SZ %d\n", prefix, off) size[prefix] = off next } /^[^ ]/ { prefix = $1 printf ("extern struct field %s_fld[];\n\n", locase(prefix)); if ($3) { off = size[$3] } else { off = 0 } i = 0 next } /^[ ]/ && $1 { printf ("#define %s_%s_OFF %d\n", prefix, $1, off) if ($3) { printf ("#define %s_%s_LEN %d\n", prefix, $1, $3) } if ($4) { printf ("extern struct constant_map *%s_%s_maps[];\n", locase(prefix), locase($1)) } if ($2 == "raw") { printf ("#define GET_%s_%s(buf, val) ", prefix, $1) printf ("field_get_raw (%s_fld + %d, buf, val)\n", locase(prefix), i) printf ("#define SET_%s_%s(buf, val) ", prefix, $1) printf ("field_set_raw (%s_fld + %d, buf, val)\n", locase(prefix), i) } else { printf ("#define GET_%s_%s(buf) field_get_num (%s_fld + %d, buf)\n", prefix, $1, locase(prefix), i) printf ("#define SET_%s_%s(buf, val) ", prefix, $1) printf ("field_set_num (%s_fld + %d, buf, val)\n", locase(prefix), i) } off += $3 i++ next } { print } END { printf ("\n") print "#endif /* _'$upcased_name'_H_ */" } ' <$1.fld >$base.h $awk " $locase_function "' BEGIN { print "/* DO NOT EDIT-- this file is automatically generated. */\n" print "#include \"sysdep.h\"\n" print "#include \"constants.h\"" print "#include \"field.h\"" print "#include \"'$base'.h\"" print "#include \"isakmp_num.h\"" print "#include \"ipsec_num.h\"\n" } /^#/ { next } /^\./ { print " { 0, 0, 0, 0, 0 }\n};\n" size[prefix] = off for (map in maps) { printf ("struct constant_map *%s_%s_maps[] = {\n", locase(prefix), locase(map)) printf (" %s, 0\n};\n", maps[map]) } next } /^[^ ]/ { prefix = $1 printf ("struct field %s_fld[] = {\n", locase(prefix)) if ($3) { off = size[$3] } else { off = 0 } delete maps next } /^[ ]/ && $1 { if ($4) { maps_name = locase(prefix)"_"locase($1)"_maps" maps[$1] = $4 } else { maps_name = "0" } printf (" { \"%s\", %d, %d, %s, %s },\n", $1, off, $3, $2, maps_name) off += $3 next } { print } ' <$1.fld >$base.c isakmpd-20041012.orig/math_2n.c0000644000175000017500000004764210133045740016266 0ustar jdivejdive00000000000000/* $OpenBSD: math_2n.c,v 1.16 2004/06/14 09:55:41 ho Exp $ */ /* $EOM: math_2n.c,v 1.15 1999/04/20 09:23:30 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * B2N is a module for doing arithmetic on the Field GF(2**n) which is * isomorph to ring of polynomials GF(2)[x]/p(x) where p(x) is an * irreduciable polynomial over GF(2)[x] with grade n. * * First we need functions which operate on GF(2)[x], operation * on GF(2)[x]/p(x) can be done as for Z_p then. */ #include #include #include #include "sysdep.h" #include "math_2n.h" #include "util.h" static u_int8_t hex2int(char); static char int2hex[] = "0123456789abcdef"; CHUNK_TYPE b2n_mask[CHUNK_BITS] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, #if CHUNK_BITS > 8 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, #if CHUNK_BITS > 16 0x00010000, 0x00020000, 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, #endif #endif }; /* Convert a hex character to its integer value. */ static u_int8_t hex2int(char c) { if (c <= '9') return c - '0'; if (c <= 'f') return 10 + c - 'a'; return 0; } int b2n_random(b2n_ptr n, u_int32_t bits) { if (b2n_resize(n, (CHUNK_MASK + bits) >> CHUNK_SHIFTS)) return -1; getrandom((u_int8_t *) n->limp, CHUNK_BYTES * n->chunks); /* Get the number of significant bits right */ if (bits & CHUNK_MASK) { CHUNK_TYPE m = (((1 << ((bits & CHUNK_MASK) - 1)) - 1) << 1) | 1; n->limp[n->chunks - 1] &= m; } n->dirty = 1; return 0; } /* b2n management functions */ void b2n_init(b2n_ptr n) { n->chunks = 0; n->limp = 0; } void b2n_clear(b2n_ptr n) { if (n->limp) free(n->limp); } int b2n_resize(b2n_ptr n, unsigned int chunks) { size_t old = n->chunks; size_t size; CHUNK_TYPE *new; if (chunks == 0) chunks = 1; if (chunks == old) return 0; size = CHUNK_BYTES * chunks; new = realloc(n->limp, size); if (!new) return -1; n->limp = new; n->chunks = chunks; n->bits = chunks << CHUNK_SHIFTS; n->dirty = 1; if (chunks > old) memset(n->limp + old, 0, size - CHUNK_BYTES * old); return 0; } /* Simple assignment functions. */ int b2n_set(b2n_ptr d, b2n_ptr s) { if (d == s) return 0; b2n_sigbit(s); if (b2n_resize(d, (CHUNK_MASK + s->bits) >> CHUNK_SHIFTS)) return -1; memcpy(d->limp, s->limp, CHUNK_BYTES * d->chunks); d->bits = s->bits; d->dirty = s->dirty; return 0; } int b2n_set_null(b2n_ptr n) { if (b2n_resize(n, 1)) return -1; n->limp[0] = n->bits = n->dirty = 0; return 0; } int b2n_set_ui(b2n_ptr n, unsigned int val) { #if CHUNK_BITS < 32 int i, chunks; chunks = (CHUNK_BYTES - 1 + sizeof(val)) / CHUNK_BYTES; if (b2n_resize(n, chunks)) return -1; for (i = 0; i < chunks; i++) { n->limp[i] = val & CHUNK_BMASK; val >>= CHUNK_BITS; } #else if (b2n_resize(n, 1)) return -1; n->limp[0] = val; #endif n->dirty = 1; return 0; } /* XXX This one only takes hex at the moment. */ int b2n_set_str(b2n_ptr n, char *str) { int i, j, w, len, chunks; CHUNK_TYPE tmp; if (strncasecmp(str, "0x", 2)) return -1; /* Make the hex string even lengthed */ len = strlen(str) - 2; if (len & 1) { len++; str++; } else str += 2; len /= 2; chunks = (CHUNK_BYTES - 1 + len) / CHUNK_BYTES; if (b2n_resize(n, chunks)) return -1; memset(n->limp, 0, CHUNK_BYTES * n->chunks); for (w = 0, i = 0; i < chunks; i++) { tmp = 0; for (j = (i == 0 ? ((len - 1) % CHUNK_BYTES) + 1 : CHUNK_BYTES); j > 0; j--) { tmp <<= 8; tmp |= (hex2int(str[w]) << 4) | hex2int(str[w + 1]); w += 2; } n->limp[chunks - 1 - i] = tmp; } n->dirty = 1; return 0; } /* Output function, mainly for debugging purposes. */ void b2n_print(b2n_ptr n) { int i, j, w, flag = 0; int left; char buffer[2 * CHUNK_BYTES]; CHUNK_TYPE tmp; left = ((((7 + b2n_sigbit(n)) >> 3) - 1) % CHUNK_BYTES) + 1; printf("0x"); for (i = 0; i < n->chunks; i++) { tmp = n->limp[n->chunks - 1 - i]; memset(buffer, '0', sizeof(buffer)); for (w = 0, j = (i == 0 ? left : CHUNK_BYTES); j > 0; j--) { buffer[w++] = int2hex[(tmp >> 4) & 0xf]; buffer[w++] = int2hex[tmp & 0xf]; tmp >>= 8; } for (j = (i == 0 ? left - 1 : CHUNK_BYTES - 1); j >= 0; j--) if (flag || (i == n->chunks - 1 && j == 0) || buffer[2 * j] != '0' || buffer[2 * j + 1] != '0') { putchar(buffer[2 * j]); putchar(buffer[2 * j + 1]); flag = 1; } } printf("\n"); } int b2n_snprint(char *buf, size_t sz, b2n_ptr n) { int i, j, w, flag = 0; size_t k; int left; char buffer[2 * CHUNK_BYTES]; CHUNK_TYPE tmp; left = ((((7 + b2n_sigbit(n)) >> 3) - 1) % CHUNK_BYTES) + 1; k = strlcpy(buf, "0x", sz); for (i = 0; i < n->chunks && k < sz - 1; i++) { tmp = n->limp[n->chunks - 1 - i]; memset(buffer, '0', sizeof(buffer)); for (w = 0, j = (i == 0 ? left : CHUNK_BYTES); j > 0; j--) { buffer[w++] = int2hex[(tmp >> 4) & 0xf]; buffer[w++] = int2hex[tmp & 0xf]; tmp >>= 8; } for (j = (i == 0 ? left - 1 : CHUNK_BYTES - 1); j >= 0 && k < sz - 3; j--) if (flag || (i == n->chunks - 1 && j == 0) || buffer[2 * j] != '0' || buffer[2 * j + 1] != '0') { buf[k++] = buffer[2 * j]; buf[k++] = buffer[2 * j + 1]; flag = 1; } } buf[k++] = 0; return k; } /* Arithmetic functions. */ u_int32_t b2n_sigbit(b2n_ptr n) { int i, j; if (!n->dirty) return n->bits; for (i = n->chunks - 1; i > 0; i--) if (n->limp[i]) break; if (!n->limp[i]) return 0; for (j = CHUNK_MASK; j > 0; j--) if (n->limp[i] & b2n_mask[j]) break; n->bits = (i << CHUNK_SHIFTS) + j + 1; n->dirty = 0; return n->bits; } /* Addition on GF(2)[x] is nice, its just an XOR. */ int b2n_add(b2n_ptr d, b2n_ptr a, b2n_ptr b) { int i; b2n_ptr bmin, bmax; if (!b2n_cmp_null(a)) return b2n_set(d, b); if (!b2n_cmp_null(b)) return b2n_set(d, a); bmin = B2N_MIN(a, b); bmax = B2N_MAX(a, b); if (b2n_resize(d, bmax->chunks)) return -1; for (i = 0; i < bmin->chunks; i++) d->limp[i] = bmax->limp[i] ^ bmin->limp[i]; /* * If d is not bmax, we have to copy the rest of the bytes, and also * need to adjust to number of relevant bits. */ if (d != bmax) { for (; i < bmax->chunks; i++) d->limp[i] = bmax->limp[i]; d->bits = bmax->bits; } /* * Help to converse memory. When the result of the addition is zero * truncate the used amount of memory. */ if (d != bmax && !b2n_cmp_null(d)) return b2n_set_null(d); else d->dirty = 1; return 0; } /* Compare two polynomials. */ int b2n_cmp(b2n_ptr n, b2n_ptr m) { int sn, sm; int i; sn = b2n_sigbit(n); sm = b2n_sigbit(m); if (sn > sm) return 1; if (sn < sm) return -1; for (i = n->chunks - 1; i >= 0; i--) if (n->limp[i] > m->limp[i]) return 1; else if (n->limp[i] < m->limp[i]) return -1; return 0; } int b2n_cmp_null(b2n_ptr a) { int i = 0; do { if (a->limp[i]) return 1; } while (++i < a->chunks); return 0; } /* Left shift, needed for polynomial multiplication. */ int b2n_lshift(b2n_ptr d, b2n_ptr n, unsigned int s) { int i, maj, min, chunks; u_int16_t bits = b2n_sigbit(n), add; CHUNK_TYPE *p, *op; if (!s) return b2n_set(d, n); maj = s >> CHUNK_SHIFTS; min = s & CHUNK_MASK; add = (!(bits & CHUNK_MASK) || ((bits & CHUNK_MASK) + min) > CHUNK_MASK) ? 1 : 0; chunks = n->chunks; if (b2n_resize(d, chunks + maj + add)) return -1; memmove(d->limp + maj, n->limp, CHUNK_BYTES * chunks); if (maj) memset(d->limp, 0, CHUNK_BYTES * maj); if (add) d->limp[d->chunks - 1] = 0; /* If !min there are no bit shifts, we are done */ if (!min) return 0; op = p = &d->limp[d->chunks - 1]; for (i = d->chunks - 2; i >= maj; i--) { op--; *p = (*p << min) | (*op >> (CHUNK_BITS - min)); p--; } *p <<= min; d->dirty = 0; d->bits = bits + (maj << CHUNK_SHIFTS) + min; return 0; } /* Right shift, needed for polynomial division. */ int b2n_rshift(b2n_ptr d, b2n_ptr n, unsigned int s) { int maj, min, size = n->chunks, newsize; b2n_ptr tmp; if (!s) return b2n_set(d, n); maj = s >> CHUNK_SHIFTS; newsize = size - maj; if (size < maj) return b2n_set_null(d); min = (CHUNK_BITS - (s & CHUNK_MASK)) & CHUNK_MASK; if (min) { if ((b2n_sigbit(n) & CHUNK_MASK) > (u_int32_t) min) newsize++; if (b2n_lshift(d, n, min)) return -1; tmp = d; } else tmp = n; memmove(d->limp, tmp->limp + maj + (min ? 1 : 0), CHUNK_BYTES * newsize); if (b2n_resize(d, newsize)) return -1; d->bits = tmp->bits - ((maj + (min ? 1 : 0)) << CHUNK_SHIFTS); return 0; } /* Normal polynomial multiplication. */ int b2n_mul(b2n_ptr d, b2n_ptr n, b2n_ptr m) { int i, j; b2n_t tmp, tmp2; if (!b2n_cmp_null(m) || !b2n_cmp_null(n)) return b2n_set_null(d); if (b2n_sigbit(m) == 1) return b2n_set(d, n); if (b2n_sigbit(n) == 1) return b2n_set(d, m); b2n_init(tmp); b2n_init(tmp2); if (b2n_set(tmp, B2N_MAX(n, m))) goto fail; if (b2n_set(tmp2, B2N_MIN(n, m))) goto fail; if (b2n_set_null(d)) goto fail; for (i = 0; i < tmp2->chunks; i++) if (tmp2->limp[i]) for (j = 0; j < CHUNK_BITS; j++) { if (tmp2->limp[i] & b2n_mask[j]) if (b2n_add(d, d, tmp)) goto fail; if (b2n_lshift(tmp, tmp, 1)) goto fail; } else if (b2n_lshift(tmp, tmp, CHUNK_BITS)) goto fail; b2n_clear(tmp); b2n_clear(tmp2); return 0; fail: b2n_clear(tmp); b2n_clear(tmp2); return -1; } /* * Squaring in this polynomial ring is more efficient than normal * multiplication. */ int b2n_square(b2n_ptr d, b2n_ptr n) { int i, j, maj, min, bits, chunk; b2n_t t; maj = b2n_sigbit(n); min = maj & CHUNK_MASK; maj = (maj + CHUNK_MASK) >> CHUNK_SHIFTS; b2n_init(t); if (b2n_resize(t, 2 * maj + ((CHUNK_MASK + 2 * min) >> CHUNK_SHIFTS))) { b2n_clear(t); return -1; } chunk = 0; bits = 0; for (i = 0; i < maj; i++) if (n->limp[i]) for (j = 0; j < CHUNK_BITS; j++) { if (n->limp[i] & b2n_mask[j]) t->limp[chunk] ^= b2n_mask[bits]; bits += 2; if (bits >= CHUNK_BITS) { chunk++; bits &= CHUNK_MASK; } } else chunk += 2; t->dirty = 1; B2N_SWAP(d, t); b2n_clear(t); return 0; } /* * Normal polynomial division. * These functions are far from optimal in speed. */ int b2n_div_q(b2n_ptr d, b2n_ptr n, b2n_ptr m) { b2n_t r; int rv; b2n_init(r); rv = b2n_div(d, r, n, m); b2n_clear(r); return rv; } int b2n_div_r(b2n_ptr r, b2n_ptr n, b2n_ptr m) { b2n_t q; int rv; b2n_init(q); rv = b2n_div(q, r, n, m); b2n_clear(q); return rv; } int b2n_div(b2n_ptr q, b2n_ptr r, b2n_ptr n, b2n_ptr m) { int i, j, len, bits; u_int32_t sm, sn; b2n_t nenn, div, shift, mask; /* If Teiler > Zaehler, the result is 0 */ if ((sm = b2n_sigbit(m)) > (sn = b2n_sigbit(n))) { if (b2n_set_null(q)) return -1; return b2n_set(r, n); } if (sm == 0) /* Division by Zero */ return -1; else if (sm == 1) { /* Division by the One-Element */ if (b2n_set(q, n)) return -1; return b2n_set_null(r); } b2n_init(nenn); b2n_init(div); b2n_init(shift); b2n_init(mask); if (b2n_set(nenn, n)) goto fail; if (b2n_set(div, m)) goto fail; if (b2n_set(shift, m)) goto fail; if (b2n_set_ui(mask, 1)) goto fail; if (b2n_resize(q, (sn - sm + CHUNK_MASK) >> CHUNK_SHIFTS)) goto fail; memset(q->limp, 0, CHUNK_BYTES * q->chunks); if (b2n_lshift(shift, shift, sn - sm)) goto fail; if (b2n_lshift(mask, mask, sn - sm)) goto fail; /* Number of significant octets */ len = (sn - 1) >> CHUNK_SHIFTS; /* The first iteration is done over the relevant bits */ bits = (CHUNK_MASK + sn) & CHUNK_MASK; for (i = len; i >= 0 && b2n_sigbit(nenn) >= sm; i--) for (j = (i == len ? bits : CHUNK_MASK); j >= 0 && b2n_sigbit(nenn) >= sm; j--) { if (nenn->limp[i] & b2n_mask[j]) { if (b2n_sub(nenn, nenn, shift)) goto fail; if (b2n_add(q, q, mask)) goto fail; } if (b2n_rshift(shift, shift, 1)) goto fail; if (b2n_rshift(mask, mask, 1)) goto fail; } B2N_SWAP(r, nenn); b2n_clear(nenn); b2n_clear(div); b2n_clear(shift); b2n_clear(mask); return 0; fail: b2n_clear(nenn); b2n_clear(div); b2n_clear(shift); b2n_clear(mask); return -1; } /* Functions for Operation on GF(2**n) ~= GF(2)[x]/p(x). */ int b2n_mod(b2n_ptr m, b2n_ptr n, b2n_ptr p) { int bits, size; if (b2n_div_r(m, n, p)) return -1; bits = b2n_sigbit(m); size = ((CHUNK_MASK + bits) >> CHUNK_SHIFTS); if (size == 0) size = 1; if (m->chunks > size) if (b2n_resize(m, size)) return -1; m->bits = bits; m->dirty = 0; return 0; } int b2n_gcd(b2n_ptr e, b2n_ptr go, b2n_ptr ho) { b2n_t g, h; b2n_init(g); b2n_init(h); if (b2n_set(g, go)) goto fail; if (b2n_set(h, ho)) goto fail; while (b2n_cmp_null(h)) { if (b2n_mod(g, g, h)) goto fail; B2N_SWAP(g, h); } B2N_SWAP(e, g); b2n_clear(g); b2n_clear(h); return 0; fail: b2n_clear(g); b2n_clear(h); return -1; } int b2n_mul_inv(b2n_ptr ga, b2n_ptr be, b2n_ptr p) { b2n_t a; b2n_init(a); if (b2n_set_ui(a, 1)) goto fail; if (b2n_div_mod(ga, a, be, p)) goto fail; b2n_clear(a); return 0; fail: b2n_clear(a); return -1; } int b2n_div_mod(b2n_ptr ga, b2n_ptr a, b2n_ptr be, b2n_ptr p) { b2n_t s0, s1, s2, q, r0, r1; /* There is no multiplicative inverse to Null. */ if (!b2n_cmp_null(be)) return b2n_set_null(ga); b2n_init(s0); b2n_init(s1); b2n_init(s2); b2n_init(r0); b2n_init(r1); b2n_init(q); if (b2n_set(r0, p)) goto fail; if (b2n_set(r1, be)) goto fail; if (b2n_set_null(s0)) goto fail; if (b2n_set(s1, a)) goto fail; while (b2n_cmp_null(r1)) { if (b2n_div(q, r0, r0, r1)) goto fail; B2N_SWAP(r0, r1); if (b2n_mul(s2, q, s1)) goto fail; if (b2n_mod(s2, s2, p)) goto fail; if (b2n_sub(s2, s0, s2)) goto fail; B2N_SWAP(s0, s1); B2N_SWAP(s1, s2); } B2N_SWAP(ga, s0); b2n_clear(s0); b2n_clear(s1); b2n_clear(s2); b2n_clear(r0); b2n_clear(r1); b2n_clear(q); return 0; fail: b2n_clear(s0); b2n_clear(s1); b2n_clear(s2); b2n_clear(r0); b2n_clear(r1); b2n_clear(q); return -1; } /* * The trace tells us if there do exist any square roots * for 'a' in GF(2)[x]/p(x). The number of square roots is * 2 - 2*Trace. * If z is a square root, z + 1 is the other. */ int b2n_trace(b2n_ptr ho, b2n_ptr a, b2n_ptr p) { int i, m = b2n_sigbit(p) - 1; b2n_t h; b2n_init(h); if (b2n_set(h, a)) goto fail; for (i = 0; i < m - 1; i++) { if (b2n_square(h, h)) goto fail; if (b2n_mod(h, h, p)) goto fail; if (b2n_add(h, h, a)) goto fail; } B2N_SWAP(ho, h); b2n_clear(h); return 0; fail: b2n_clear(h); return -1; } /* * The halftrace yields the square root if the degree of the * irreduceable polynomial is odd. */ int b2n_halftrace(b2n_ptr ho, b2n_ptr a, b2n_ptr p) { int i, m = b2n_sigbit(p) - 1; b2n_t h; b2n_init(h); if (b2n_set(h, a)) goto fail; for (i = 0; i < (m - 1) / 2; i++) { if (b2n_square(h, h)) goto fail; if (b2n_mod(h, h, p)) goto fail; if (b2n_square(h, h)) goto fail; if (b2n_mod(h, h, p)) goto fail; if (b2n_add(h, h, a)) goto fail; } B2N_SWAP(ho, h); b2n_clear(h); return 0; fail: b2n_clear(h); return -1; } /* * Solving the equation: y**2 + y = b in GF(2**m) where ip is the * irreduceable polynomial. If m is odd, use the half trace. */ int b2n_sqrt(b2n_ptr zo, b2n_ptr b, b2n_ptr ip) { int i, m = b2n_sigbit(ip) - 1; b2n_t w, p, temp, z; if (!b2n_cmp_null(b)) return b2n_set_null(z); if (m & 1) return b2n_halftrace(zo, b, ip); b2n_init(z); b2n_init(w); b2n_init(p); b2n_init(temp); do { if (b2n_random(p, m)) goto fail; if (b2n_set_null(z)) goto fail; if (b2n_set(w, p)) goto fail; for (i = 1; i < m; i++) { if (b2n_square(z, z)) /* z**2 */ goto fail; if (b2n_mod(z, z, ip)) goto fail; if (b2n_square(w, w)) /* w**2 */ goto fail; if (b2n_mod(w, w, ip)) goto fail; if (b2n_mul(temp, w, b)) /* w**2 * b */ goto fail; if (b2n_mod(temp, temp, ip)) goto fail; if (b2n_add(z, z, temp)) /* z**2 + w**2 + b */ goto fail; if (b2n_add(w, w, p)) /* w**2 + p */ goto fail; } } while (!b2n_cmp_null(w)); B2N_SWAP(zo, z); b2n_clear(w); b2n_clear(p); b2n_clear(temp); b2n_clear(z); return 0; fail: b2n_clear(w); b2n_clear(p); b2n_clear(temp); b2n_clear(z); return -1; } /* Exponentiation modulo a polynomial. */ int b2n_exp_mod(b2n_ptr d, b2n_ptr b0, u_int32_t e, b2n_ptr p) { b2n_t u, b; b2n_init(u); b2n_init(b); if (b2n_set_ui(u, 1)) goto fail; if (b2n_mod(b, b0, p)) goto fail; while (e) { if (e & 1) { if (b2n_mul(u, u, b)) goto fail; if (b2n_mod(u, u, p)) goto fail; } if (b2n_square(b, b)) goto fail; if (b2n_mod(b, b, p)) goto fail; e >>= 1; } B2N_SWAP(d, u); b2n_clear(u); b2n_clear(b); return 0; fail: b2n_clear(u); b2n_clear(b); return -1; } /* * Low-level function to speed up scalar multiplication with * elliptic curves. * Multiplies a normal number by 3. */ /* Normal addition behaves as Z_{2**n} and not F_{2**n}. */ int b2n_nadd(b2n_ptr d0, b2n_ptr a0, b2n_ptr b0) { int i, carry; b2n_ptr a, b; b2n_t d; if (!b2n_cmp_null(a0)) return b2n_set(d0, b0); if (!b2n_cmp_null(b0)) return b2n_set(d0, a0); b2n_init(d); a = B2N_MAX(a0, b0); b = B2N_MIN(a0, b0); if (b2n_resize(d, a->chunks + 1)) { b2n_clear(d); return -1; } for (carry = i = 0; i < b->chunks; i++) { d->limp[i] = a->limp[i] + b->limp[i] + carry; carry = (d->limp[i] < a->limp[i] ? 1 : 0); } for (; i < a->chunks && carry; i++) { d->limp[i] = a->limp[i] + carry; carry = (d->limp[i] < a->limp[i] ? 1 : 0); } if (i < a->chunks) memcpy(d->limp + i, a->limp + i, CHUNK_BYTES * (a->chunks - i)); d->dirty = 1; B2N_SWAP(d0, d); b2n_clear(d); return 0; } /* Very special sub, a > b. */ int b2n_nsub(b2n_ptr d0, b2n_ptr a, b2n_ptr b) { int i, carry; b2n_t d; if (b2n_cmp(a, b) <= 0) return b2n_set_null(d0); b2n_init(d); if (b2n_resize(d, a->chunks)) { b2n_clear(d); return -1; } for (carry = i = 0; i < b->chunks; i++) { d->limp[i] = a->limp[i] - b->limp[i] - carry; carry = (d->limp[i] > a->limp[i] ? 1 : 0); } for (; i < a->chunks && carry; i++) { d->limp[i] = a->limp[i] - carry; carry = (d->limp[i] > a->limp[i] ? 1 : 0); } if (i < a->chunks) memcpy(d->limp + i, a->limp + i, CHUNK_BYTES * (a->chunks - i)); d->dirty = 1; B2N_SWAP(d0, d); b2n_clear(d); return 0; } int b2n_3mul(b2n_ptr d0, b2n_ptr e) { b2n_t d; b2n_init(d); if (b2n_lshift(d, e, 1)) goto fail; if (b2n_nadd(d0, d, e)) goto fail; b2n_clear(d); return 0; fail: b2n_clear(d); return -1; } isakmpd-20041012.orig/features/0000755000175000017500000000000010133045740016373 5ustar jdivejdive00000000000000isakmpd-20041012.orig/features/policy0000644000175000017500000000302010133045740017610 0ustar jdivejdive00000000000000# $OpenBSD: policy,v 1.6 2003/06/03 14:29:41 ho Exp $ # $EOM: policy,v 1.4 2000/02/20 16:38:15 niklas Exp $ # # Copyright (c) 2000 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Wireless Networks Inc. # # NOTE: KeyNote policy support requires the keynote library POLICY= policy.c isakmpd-20041012.orig/features/ec0000644000175000017500000000271310133045740016710 0ustar jdivejdive00000000000000# $OpenBSD: ec,v 1.4 2003/06/03 14:29:41 ho Exp $ # $EOM: ec,v 1.3 2000/02/20 16:38:15 niklas Exp $ # # Copyright (c) 2000 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Wireless Networks Inc. # EC= math_ec2n.c isakmpd-20041012.orig/features/aggressive0000644000175000017500000000275010133045740020461 0ustar jdivejdive00000000000000# $OpenBSD: aggressive,v 1.4 2003/06/03 14:29:41 ho Exp $ # $EOM: aggressive,v 1.3 2000/02/20 16:38:15 niklas Exp $ # # Copyright (c) 2000 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Wireless Networks Inc. # AGGRESSIVE= ike_aggressive.c isakmpd-20041012.orig/features/isakmp_cfg0000644000175000017500000000267210133045740020430 0ustar jdivejdive00000000000000# $OpenBSD: isakmp_cfg,v 1.2 2003/06/03 14:29:41 ho Exp $ # # Copyright (c) 2001 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Gatespace (http://www.gatespace.com/). # ISAKMP_CFG= isakmp_cfg.c isakmpd-20041012.orig/features/nat_traversal0000644000175000017500000000257210133045740021171 0ustar jdivejdive00000000000000# $OpenBSD: nat_traversal,v 1.2 2004/06/21 17:02:53 markus Exp $ # # Copyright (c) 2004 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. # # 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. # NAT_TRAVERSAL= nat_traversal.c udp_encap.c isakmpd-20041012.orig/features/dnssec0000644000175000017500000000265010133045740017600 0ustar jdivejdive00000000000000# $OpenBSD: dnssec,v 1.3 2003/06/03 14:29:41 ho Exp $ # # Copyright (c) 2001 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. # # 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. # DNSSEC= dnssec.c #LWRESLIB= /usr/local/lib/liblwres.a #DNSSEC_CFLAGS= -I/usr/local/include -DLWRES isakmpd-20041012.orig/features/privsep0000644000175000017500000000255110133045740020011 0ustar jdivejdive00000000000000# $OpenBSD: privsep,v 1.2 2003/06/03 14:29:41 ho Exp $ # # Copyright (c) 2003 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. # # 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. # PRIVSEP= monitor.c monitor_fdpass.c isakmpd-20041012.orig/features/CVS/0000755000175000017500000000000010133045751017030 5ustar jdivejdive00000000000000isakmpd-20041012.orig/features/dpd0000644000175000017500000000251410133045740017067 0ustar jdivejdive00000000000000# $OpenBSD: dpd,v 1.1 2004/06/20 15:20:07 ho Exp $ # # Copyright (c) 2004 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. # # 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. # DPD= dpd.c isakmpd-20041012.orig/features/x5090000644000175000017500000000271410133045740017027 0ustar jdivejdive00000000000000# $OpenBSD: x509,v 1.5 2003/06/03 14:29:41 ho Exp $ # $EOM: x509,v 1.4 2000/02/20 16:38:15 niklas Exp $ # # Copyright (c) 2000 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Wireless Networks Inc. # X509= x509.c isakmpd-20041012.orig/if.c0000644000175000017500000000774110133045740015330 0ustar jdivejdive00000000000000/* $OpenBSD: if.c,v 1.22 2004/06/14 09:55:41 ho Exp $ */ /* $EOM: if.c,v 1.12 1999/10/01 13:45:20 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #ifdef HAVE_GETIFADDRS #include #endif #include "sysdep.h" #include "log.h" #include "monitor.h" #include "if.h" #ifndef HAVE_GETIFADDRS /* XXX Unsafe if either x or y has side-effects. */ #ifndef MAX #define MAX(x, y) ((x) > (y) ? (x) : (y)) #endif /* Most boxes has less than 16 interfaces, so this might be a good guess. */ #define INITIAL_IFREQ_COUNT 16 /* * Get all network interface configurations. * Return 0 if successful, -1 otherwise. */ int siocgifconf(struct ifconf *ifcp) { caddr_t buf, new_buf; int s, len; /* Get a socket to ask for the network interface configurations. */ s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) { log_error("siocgifconf: " "socket (AF_INET, SOCK_DGRAM, 0) failed"); return -1; } len = sizeof(struct ifreq) * INITIAL_IFREQ_COUNT; buf = 0; while (1) { /* * Allocate a larger buffer each time around the loop and get * the network interfaces configurations into it. */ new_buf = realloc(buf, len); if (!new_buf) { log_error("siocgifconf: realloc (%p, %d) failed", buf, len); goto err; } ifcp->ifc_len = len; ifcp->ifc_buf = buf = new_buf; if (ioctl(s, SIOCGIFCONF, ifcp) == -1) { log_error("siocgifconf: ioctl (%d, SIOCGIFCONF, ...) " "failed", s); goto err; } /* * If there is place for another ifreq we can be sure that the * buffer was big enough, otherwise double the size and try * again. */ if (len - ifcp->ifc_len >= sizeof(struct ifreq)) break; len *= 2; } close(s); return 0; err: if (buf) free(buf); ifcp->ifc_len = 0; ifcp->ifc_buf = 0; close(s); return -1; } #endif int if_map(int (*func)(char *, struct sockaddr *, void *), void *arg) { int err = 0; #ifdef HAVE_GETIFADDRS struct ifaddrs *ifap, *ifa; if (getifaddrs(&ifap) < 0) return -1; for (ifa = ifap; ifa; ifa = ifa->ifa_next) if ((*func)(ifa->ifa_name, ifa->ifa_addr, arg) == -1) err = -1; freeifaddrs(ifap); #else struct ifconf ifc; struct ifreq *ifrp; caddr_t limit, p; size_t len; if (siocgifconf(&ifc)) return -1; limit = ifc.ifc_buf + ifc.ifc_len; for (p = ifc.ifc_buf; p < limit; p += len) { ifrp = (struct ifreq *)p; if ((*func)(ifrp->ifr_name, &ifrp->ifr_addr, arg) == -1) err = -1; len = sizeof ifrp->ifr_name + MAX(sysdep_sa_len(&ifrp->ifr_addr), sizeof ifrp->ifr_addr); } free(ifc.ifc_buf); #endif return err; } isakmpd-20041012.orig/isakmp_cfg.c0000644000175000017500000006540510133045740017036 0ustar jdivejdive00000000000000/* $OpenBSD: isakmp_cfg.c,v 1.34 2004/08/08 19:11:06 deraadt Exp $ */ /* * Copyright (c) 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2002 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. * * 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. */ /* * This code was written under funding by Gatespace * (http://www.gatespace.com/). */ #include #include #include #include #include #include #include "sysdep.h" #include "attribute.h" #include "conf.h" #include "exchange.h" #include "hash.h" #include "ipsec.h" #include "isakmp_fld.h" #include "isakmp_num.h" #include "log.h" #include "message.h" #include "prf.h" #include "sa.h" #include "transport.h" #include "util.h" /* * Validation script used to test messages for correct content of * payloads depending on the exchange type. */ int16_t script_transaction[] = { ISAKMP_PAYLOAD_ATTRIBUTE, /* Initiator -> responder. */ EXCHANGE_SCRIPT_SWITCH, ISAKMP_PAYLOAD_ATTRIBUTE, /* Responder -> initiator. */ EXCHANGE_SCRIPT_END }; static int cfg_decode_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); static int cfg_encode_attributes(struct isakmp_cfg_attr_head *, u_int32_t, u_int32_t, char *, u_int8_t **, u_int16_t *); static int cfg_initiator_send_ATTR(struct message *); static int cfg_initiator_recv_ATTR(struct message *); static int cfg_responder_recv_ATTR(struct message *); static int cfg_responder_send_ATTR(struct message *); u_int8_t *cfg_add_hash(struct message *); int cfg_finalize_hash(struct message *, u_int8_t *, u_int8_t *, u_int16_t); int cfg_verify_hash(struct message *); /* Server: SET/ACK Client; REQ/REPLY */ int (*isakmp_cfg_initiator[]) (struct message *) = { cfg_initiator_send_ATTR, cfg_initiator_recv_ATTR }; /* Server: REQ/REPLY Client: SET/ACK */ int (*isakmp_cfg_responder[]) (struct message *) = { cfg_responder_recv_ATTR, cfg_responder_send_ATTR }; /* * When we are "the server", this starts SET/ACK mode * When we are "the client", this starts REQ/REPLY mode */ static int cfg_initiator_send_ATTR(struct message *msg) { struct sa *isakmp_sa = msg->isakmp_sa; struct ipsec_exch *ie = msg->exchange->data; u_int8_t *hashp = 0, *attrp, *attr; size_t attrlen, off; char *id_string, *cfg_mode, *field; struct sockaddr *sa; #define CFG_ATTR_BIT_MAX ISAKMP_CFG_ATTR_FUTURE_MIN /* XXX */ bitstr_t bit_decl(attrbits, CFG_ATTR_BIT_MAX); u_int16_t bit, length; u_int32_t life; if (msg->exchange->phase == 2) { hashp = cfg_add_hash(msg); if (!hashp) return -1; } /* We initiated this exchange, check isakmp_sa for other side. */ if (isakmp_sa->initiator) id_string = ipsec_id_string(isakmp_sa->id_r, isakmp_sa->id_r_len); else id_string = ipsec_id_string(isakmp_sa->id_i, isakmp_sa->id_i_len); if (!id_string) { log_print("cfg_initiator_send_ATTR: cannot parse ID"); goto fail; } /* Check for attribute list to send to the other side */ attrlen = 0; bit_nclear(attrbits, 0, CFG_ATTR_BIT_MAX - 1); cfg_mode = conf_get_str(id_string, "Mode"); if (!cfg_mode || strcmp(cfg_mode, "SET") == 0) { /* SET/ACK mode */ ie->cfg_type = ISAKMP_CFG_SET; LOG_DBG((LOG_NEGOTIATION, 10, "cfg_initiator_send_ATTR: SET/ACK mode")); #define ATTRFIND(STR,ATTR4,LEN4,ATTR6,LEN6) do \ { \ if ((sa = conf_get_address (id_string, STR)) != NULL) \ switch (sa->sa_family) { \ case AF_INET: \ bit_set (attrbits, ATTR4); \ attrlen += ISAKMP_ATTR_SZ + LEN4; \ break; \ case AF_INET6: \ bit_set (attrbits, ATTR6); \ attrlen += ISAKMP_ATTR_SZ + LEN6; \ break; \ default: \ break; \ } \ free (sa); \ } while (0) /* * XXX We don't simultaneously support IPv4 and IPv6 * addresses. */ ATTRFIND("Address", ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS, 4, ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS, 16); ATTRFIND("Netmask", ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK, 4, ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK, 16); ATTRFIND("Nameserver", ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS, 4, ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS, 16); ATTRFIND("WINS-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS, 4, ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS, 16); ATTRFIND("DHCP-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP, 4, ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP, 16); #ifdef notyet ATTRFIND("Network", ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET, 8, ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET, 17); #endif #undef ATTRFIND if (conf_get_str(id_string, "Lifetime")) { bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY); attrlen += ISAKMP_ATTR_SZ + 4; } } else { struct conf_list *alist; struct conf_list_node *anode; ie->cfg_type = ISAKMP_CFG_REQUEST; LOG_DBG((LOG_NEGOTIATION, 10, "cfg_initiator_send_ATTR: REQ/REPLY mode")); alist = conf_get_list(id_string, "Attributes"); if (alist) { for (anode = TAILQ_FIRST(&alist->fields); anode; anode = TAILQ_NEXT(anode, link)) { if (strcasecmp(anode->field, "Address") == 0) { bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS); bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS); attrlen += ISAKMP_ATTR_SZ * 2; } else if (strcasecmp(anode->field, "Netmask") == 0) { bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK); bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK); attrlen += ISAKMP_ATTR_SZ * 2; } else if (strcasecmp(anode->field, "Nameserver") == 0) { bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS); bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS); attrlen += ISAKMP_ATTR_SZ * 2; } else if (strcasecmp(anode->field, "WINS-server") == 0) { bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS); bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS); attrlen += ISAKMP_ATTR_SZ * 2; } else if (strcasecmp(anode->field, "DHCP-server") == 0) { bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP); bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP); attrlen += ISAKMP_ATTR_SZ * 2; } else if (strcasecmp(anode->field, "Lifetime") == 0) { bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY); attrlen += ISAKMP_ATTR_SZ; } else { log_print("cfg_initiator_send_ATTR: " "unknown attribute %.20s in " "section [%s]", anode->field, id_string); } } conf_free_list(alist); } } if (attrlen == 0) { /* No data found. */ log_print("cfg_initiator_send_ATTR: no IKECFG attributes " "found for [%s]", id_string); /* * We can continue, but this indicates a configuration error * that the user probably will want to correct. */ free(id_string); return 0; } attrlen += ISAKMP_ATTRIBUTE_SZ; attrp = calloc(1, attrlen); if (!attrp) { log_error("cfg_initiator_send_ATTR: calloc (1, %lu) failed", (unsigned long)attrlen); goto fail; } if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen, 1)) { free(attrp); goto fail; } SET_ISAKMP_ATTRIBUTE_TYPE(attrp, ie->cfg_type); getrandom((u_int8_t *) & ie->cfg_id, sizeof ie->cfg_id); SET_ISAKMP_ATTRIBUTE_ID(attrp, ie->cfg_id); off = ISAKMP_ATTRIBUTE_SZ; /* * Use the bitstring built previously to collect the right * parameters for attrp. */ for (bit = 0; bit < CFG_ATTR_BIT_MAX; bit++) if (bit_test(attrbits, bit)) { attr = attrp + off; SET_ISAKMP_ATTR_TYPE(attr, bit); if (ie->cfg_type == ISAKMP_CFG_REQUEST) { off += ISAKMP_ATTR_SZ; continue; } /* All the other are similar, this is the odd one. */ if (bit == ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY) { life = conf_get_num(id_string, "Lifetime", 1200); SET_ISAKMP_ATTR_LENGTH_VALUE(attr, 4); encode_32(attr + ISAKMP_ATTR_VALUE_OFF, life); off += ISAKMP_ATTR_SZ + 4; continue; } switch (bit) { case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: length = 4; break; case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: length = 16; break; default: length = 0; /* Silence gcc. */ } switch (bit) { case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: field = "Address"; break; case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: field = "Netmask"; break; case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: field = "Nameserver"; break; case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: field = "DHCP-server"; break; case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: field = "WINS-server"; break; default: field = 0; /* Silence gcc. */ } sa = conf_get_address(id_string, field); SET_ISAKMP_ATTR_LENGTH_VALUE(attr, length); memcpy(attr + ISAKMP_ATTR_VALUE_OFF, sockaddr_addrdata(sa), length); free(sa); off += ISAKMP_ATTR_SZ + length; } if (msg->exchange->phase == 2) if (cfg_finalize_hash(msg, hashp, attrp, attrlen)) goto fail; return 0; fail: if (id_string) free(id_string); return -1; } /* * As "the server", this ends SET/ACK. * As "the client", this ends REQ/REPLY. */ static int cfg_initiator_recv_ATTR(struct message *msg) { struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE); struct ipsec_exch *ie = msg->exchange->data; struct sa *isakmp_sa = msg->isakmp_sa; struct isakmp_cfg_attr *attr; struct sockaddr *sa; const char *uk_addr = ""; char *addr; if (msg->exchange->phase == 2) if (cfg_verify_hash(msg)) return -1; /* Sanity. */ if (ie->cfg_id != GET_ISAKMP_ATTRIBUTE_ID(attrp->p)) { log_print("cfg_initiator_recv_ATTR: " "cfg packet ID does not match!"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } switch (attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]) { case ISAKMP_CFG_ACK: if (ie->cfg_type != ISAKMP_CFG_SET) { log_print("cfg_initiator_recv_ATTR: " "bad packet type ACK"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } break; case ISAKMP_CFG_REPLY: if (ie->cfg_type != ISAKMP_CFG_REQUEST) { log_print("cfg_initiator_recv_ATTR: " "bad packet type REPLY"); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } break; default: log_print("cfg_initiator_recv_ATTR: unexpected configuration " "message type %d", attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]); message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF, GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, cfg_decode_attribute, ie); switch (ie->cfg_type) { case ISAKMP_CFG_ACK: { /* SET/ACK -- Server side (ACK from client) */ msg->transport->vtbl->get_src(isakmp_sa->transport, &sa); if (sockaddr2text(sa, &addr, 0) < 0) addr = (char *) uk_addr; for (attr = LIST_FIRST(&ie->attrs); attr; attr = LIST_NEXT(attr, link)) LOG_DBG((LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "client %s ACKs attribute %s", addr, constant_name(isakmp_cfg_attr_cst, attr->type))); if (addr != uk_addr) free(addr); } break; case ISAKMP_CFG_REPLY: { /* * REQ/REPLY: effect attributes we've gotten * responses on. */ msg->transport->vtbl->get_src(isakmp_sa->transport, &sa); if (sockaddr2text(sa, &addr, 0) < 0) addr = (char *) uk_addr; for (attr = LIST_FIRST(&ie->attrs); attr; attr = LIST_NEXT(attr, link)) LOG_DBG((LOG_NEGOTIATION, 50, "cfg_initiator_recv_ATTR: " "server %s replied with attribute %s", addr, constant_name(isakmp_cfg_attr_cst, attr->type))); if (addr != uk_addr) free(addr); } break; default: break; } attrp->flags |= PL_MARK; return 0; } /* * As "the server", this starts REQ/REPLY (initiated by the client). * As "the client", this starts SET/ACK (initiated by the server). */ static int cfg_responder_recv_ATTR(struct message *msg) { struct payload *attrp = payload_first(msg, ISAKMP_PAYLOAD_ATTRIBUTE); struct ipsec_exch *ie = msg->exchange->data; struct sa *isakmp_sa = msg->isakmp_sa; struct isakmp_cfg_attr *attr; struct sockaddr *sa; char *addr; if (msg->exchange->phase == 2) if (cfg_verify_hash(msg)) return -1; ie->cfg_id = GET_ISAKMP_ATTRIBUTE_ID(attrp->p); ie->cfg_type = attrp->p[ISAKMP_ATTRIBUTE_TYPE_OFF]; switch (ie->cfg_type) { case ISAKMP_CFG_REQUEST: case ISAKMP_CFG_SET: break; default: message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); log_print("cfg_responder_recv_ATTR: " "unexpected configuration message type %d", ie->cfg_type); return -1; } attribute_map(attrp->p + ISAKMP_ATTRIBUTE_ATTRS_OFF, GET_ISAKMP_GEN_LENGTH(attrp->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, cfg_decode_attribute, ie); switch (ie->cfg_type) { case ISAKMP_CFG_REQUEST: /* We're done. */ break; case ISAKMP_CFG_SET: { /* SET/ACK -- Client side (SET from server) */ const char *uk_addr = ""; msg->transport->vtbl->get_dst(isakmp_sa->transport, &sa); if (sockaddr2text(sa, &addr, 0) < 0) addr = (char *) uk_addr; for (attr = LIST_FIRST(&ie->attrs); attr; attr = LIST_NEXT(attr, link)) LOG_DBG((LOG_NEGOTIATION, 50, "cfg_responder_recv_ATTR: " "server %s asks us to SET attribute %s", addr, constant_name(isakmp_cfg_attr_cst, attr->type))); /* * XXX Here's the place to add code to walk through * XXX each attribute and send them along to dhclient * XXX or whatever. Each attribute that we act upon * XXX (such as setting a netmask), should be marked * XXX like this for us to send the proper ACK * XXX response: attr->attr_used++; */ if (addr != uk_addr) free(addr); } break; default: break; } attrp->flags |= PL_MARK; return 0; } /* * As "the server", this ends REQ/REPLY mode. * As "the client", this ends SET/ACK mode. */ static int cfg_responder_send_ATTR(struct message *msg) { struct ipsec_exch *ie = msg->exchange->data; struct sa *isakmp_sa = msg->isakmp_sa; u_int8_t *hashp = 0, *attrp; u_int16_t attrlen; char *id_string; if (msg->exchange->phase == 2) { hashp = cfg_add_hash(msg); if (!hashp) return -1; } /* We are responder, check isakmp_sa for other side. */ if (isakmp_sa->initiator ^ (ie->cfg_type == ISAKMP_CFG_REQUEST)) id_string = ipsec_id_string(isakmp_sa->id_i, isakmp_sa->id_i_len); else id_string = ipsec_id_string(isakmp_sa->id_r, isakmp_sa->id_r_len); if (!id_string) { log_print("cfg_responder_send_ATTR: cannot parse client's ID"); return -1; } if (cfg_encode_attributes(&ie->attrs, (ie->cfg_type == ISAKMP_CFG_SET ? ISAKMP_CFG_ACK : ISAKMP_CFG_REPLY), ie->cfg_id, id_string, &attrp, &attrlen)) { free(id_string); return -1; } free(id_string); if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen, 1)) { free(attrp); return -1; } if (msg->exchange->phase == 2) if (cfg_finalize_hash(msg, hashp, attrp, attrlen)) return -1; return 0; } u_int8_t * cfg_add_hash(struct message *msg) { struct ipsec_sa *isa = msg->isakmp_sa->data; struct hash *hash = hash_get(isa->hash); u_int8_t *hashp; hashp = malloc(ISAKMP_HASH_SZ + hash->hashsize); if (!hashp) { log_error("cfg_add_hash: malloc (%lu) failed", ISAKMP_HASH_SZ + (unsigned long)hash->hashsize); return 0; } if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, hashp, ISAKMP_HASH_SZ + hash->hashsize, 1)) { free(hashp); return 0; } return hashp; } int cfg_finalize_hash(struct message *msg, u_int8_t *hashp, u_int8_t *data, u_int16_t length) { struct ipsec_sa *isa = msg->isakmp_sa->data; struct prf *prf; prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, isa->skeyid_len); if (!prf) return -1; prf->Init(prf->prfctx); prf->Update(prf->prfctx, msg->exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); prf->Update(prf->prfctx, data, length); prf->Final(hashp + ISAKMP_GEN_SZ, prf->prfctx); prf_free(prf); return 0; } int cfg_verify_hash(struct message *msg) { struct payload *hashp = payload_first(msg, ISAKMP_PAYLOAD_HASH); struct ipsec_sa *isa = msg->isakmp_sa->data; struct prf *prf; u_int8_t *hash, *comp_hash; size_t hash_len; if (!hashp) { log_print("cfg_verify_hash: phase 2 message missing HASH"); message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 0); return -1; } hash = hashp->p; hash_len = GET_ISAKMP_GEN_LENGTH(hash); comp_hash = malloc(hash_len - ISAKMP_GEN_SZ); if (!comp_hash) { log_error("cfg_verify_hash: malloc (%lu) failed", (unsigned long)hash_len - ISAKMP_GEN_SZ); return -1; } /* Verify hash. */ prf = prf_alloc(isa->prf_type, isa->hash, isa->skeyid_a, isa->skeyid_len); if (!prf) { free(comp_hash); return -1; } prf->Init(prf->prfctx); prf->Update(prf->prfctx, msg->exchange->message_id, ISAKMP_HDR_MESSAGE_ID_LEN); prf->Update(prf->prfctx, hash + hash_len, msg->iov[0].iov_len - ISAKMP_HDR_SZ - hash_len); prf->Final(comp_hash, prf->prfctx); prf_free(prf); if (memcmp(hash + ISAKMP_GEN_SZ, comp_hash, hash_len - ISAKMP_GEN_SZ) != 0) { message_drop(msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 0); free(comp_hash); return -1; } free(comp_hash); /* Mark the HASH as handled. */ hashp->flags |= PL_MARK; /* Mark message authenticated. */ msg->flags |= MSG_AUTHENTICATED; return 0; } /* * Decode the attribute of type TYPE with a LEN length value pointed to by * VALUE. VIE is a pointer to the IPsec exchange context holding the * attributes indexed by type for easy retrieval. */ static int cfg_decode_attribute(u_int16_t type, u_int8_t * value, u_int16_t len, void *vie) { struct ipsec_exch *ie = vie; struct isakmp_cfg_attr *attr; if (type >= ISAKMP_CFG_ATTR_PRIVATE_MIN && type <= ISAKMP_CFG_ATTR_PRIVATE_MAX) return 0; if (type == 0 || type >= ISAKMP_CFG_ATTR_FUTURE_MIN) { LOG_DBG((LOG_NEGOTIATION, 30, "cfg_decode_attribute: invalid attr type %u", type)); return -1; } attr = calloc(1, sizeof *attr); if (!attr) { log_error("cfg_decode_attribute: calloc (1, %lu) failed", (unsigned long)sizeof *attr); return -1; } attr->type = type; attr->length = len; if (len) { attr->value = malloc(len); if (!attr->value) { log_error("cfg_decode_attribute: malloc (%d) failed", len); free(attr); /* Should we also deallocate all other values? */ return -1; } memcpy(attr->value, value, len); } LIST_INSERT_HEAD(&ie->attrs, attr, link); return 0; } /* * Encode list of attributes from ie->attrs into a attribute payload. */ static int cfg_encode_attributes(struct isakmp_cfg_attr_head *attrs, u_int32_t type, u_int32_t cfg_id, char *id_string, u_int8_t **attrp, u_int16_t *len) { struct isakmp_cfg_attr *attr; struct sockaddr *sa; sa_family_t family; u_int32_t value; u_int16_t off; char *field; /* Compute length */ *len = ISAKMP_ATTRIBUTE_SZ; for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) { /* With ACK we only include the attrs we've actually used. */ if (type == ISAKMP_CFG_ACK && attr->attr_used == 0) continue; switch (attr->type) { case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY: attr->length = 4; break; case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: attr->length = 8; break; case ISAKMP_CFG_ATTR_APPLICATION_VERSION: /* XXX So far no version identifier of isakmpd here. */ attr->length = 0; break; case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES: attr->length = 2 * 15; break; case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: attr->length = 16; break; case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: attr->length = 17; break; default: attr->ignore++; /* XXX Log! */ } *len += ISAKMP_ATTR_SZ + attr->length; } /* Allocate enough space for the payload */ *attrp = calloc(1, *len); if (!*attrp) { log_error("cfg_encode_attributes: calloc (1, %lu) failed", (unsigned long)*len); return -1; } SET_ISAKMP_ATTRIBUTE_TYPE(*attrp, type); SET_ISAKMP_ATTRIBUTE_ID(*attrp, cfg_id); off = ISAKMP_ATTRIBUTE_SZ; for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) { /* With ACK we only include the attrs we've actually used. */ if (type == ISAKMP_CFG_ACK && attr->attr_used == 0) continue; switch (attr->type) { case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: family = AF_INET; break; case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: family = AF_INET6; break; default: family = 0; break; } switch (attr->type) { case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: field = "Address"; break; case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET: case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET: field = "Network"; /* XXX or just "Address" */ break; case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: field = "Netmask"; break; case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: field = "DHCP-server"; break; case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: field = "Nameserver"; break; case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: field = "WINS-server"; break; default: field = 0; } switch (attr->type) { case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS: case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK: case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP: case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS: case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS: case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS: sa = conf_get_address(id_string, field); if (!sa) { LOG_DBG((LOG_NEGOTIATION, 10, "cfg_responder_send_ATTR: " "attribute not found: %s", field)); attr->length = 0; break; } if (sa->sa_family != family) { log_print("cfg_responder_send_ATTR: " "attribute %s - expected %s got %s data", field, (family == AF_INET ? "IPv4" : "IPv6"), (sa->sa_family == AF_INET ? "IPv4" : "IPv6")); free(sa); attr->length = 0; break; } /* Temporary limit length for the _SUBNET types. */ if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) attr->length = 4; else if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) attr->length = 16; memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF, sockaddr_addrdata(sa), attr->length); free(sa); /* _SUBNET types need some extra work. */ if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) { sa = conf_get_address(id_string, "Netmask"); if (!sa) { LOG_DBG((LOG_NEGOTIATION, 10, "cfg_responder_send_ATTR: " "attribute not found: Netmask")); attr->length = 0; break; } if (sa->sa_family != AF_INET) { log_print("cfg_responder_send_ATTR: " "attribute Netmask - expected " "IPv4 got IPv6 data"); free(sa); attr->length = 0; break; } memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF + attr->length, sockaddr_addrdata(sa), attr->length); attr->length = 8; free(sa); } else if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) { int prefix = conf_get_num(id_string, "Prefix", -1); if (prefix == -1) { log_print("cfg_responder_send_ATTR: " "attribute not found: Prefix"); attr->length = 0; break; } else if (prefix < -1 || prefix > 128) { log_print("cfg_responder_send_ATTR: " "attribute Prefix - invalid " "value %d", prefix); attr->length = 0; break; } *(*attrp + off + ISAKMP_ATTR_VALUE_OFF + 16) = (u_int8_t)prefix; attr->length = 17; } break; case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY: value = conf_get_num(id_string, "Lifetime", 1200); encode_32(*attrp + off + ISAKMP_ATTR_VALUE_OFF, value); break; case ISAKMP_CFG_ATTR_APPLICATION_VERSION: /* XXX So far no version identifier of isakmpd here. */ break; case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES: break; default: break; } SET_ISAKMP_ATTR_TYPE(*attrp + off, attr->type); SET_ISAKMP_ATTR_LENGTH_VALUE(*attrp + off, attr->length); off += ISAKMP_ATTR_VALUE_OFF + attr->length; } return 0; } isakmpd-20041012.orig/ike_aggressive.h0000644000175000017500000000336710133045740017726 0ustar jdivejdive00000000000000/* $OpenBSD: ike_aggressive.h,v 1.5 2004/05/23 18:17:55 hshoexer Exp $ */ /* $EOM: ike_aggressive.h,v 1.1 1999/04/16 21:24:43 niklas Exp $ */ /* * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _IKE_AGGRESSIVE_H_ #define _IKE_AGGRESSIVE_H_ struct message; extern int (*ike_aggressive_initiator[])(struct message *msg); extern int (*ike_aggressive_responder[])(struct message *msg); #endif /* _IKE_AGGRESSIVE_H_ */ isakmpd-20041012.orig/udp_encap.h0000644000175000017500000000321210133045740016662 0ustar jdivejdive00000000000000/* $OpenBSD: udp_encap.h,v 1.1 2004/06/20 15:24:05 ho Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. All rights reserved. * Copyright (c) 2004 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. * * 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. */ #ifndef _UDP_ENCAP_H_ #define _UDP_ENCAP_H_ struct transport *udp_encap_bind (const struct sockaddr *); void udp_encap_init (void); extern char *udp_encap_default_port; extern char *udp_encap_bind_port; #endif /* _UDP_H_ */ isakmpd-20041012.orig/sysdep.h0000644000175000017500000000623610133045740016244 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep.h,v 1.19 2004/08/10 15:59:10 ho Exp $ */ /* $EOM: sysdep.h,v 1.17 2000/12/04 04:46:35 angelos Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _SYSDEP_H_ #define _SYSDEP_H_ #include #if defined (USE_BOEHM_GC) #include #include #endif #include "sysdep-os.h" struct proto; struct sa; struct sockaddr; extern void sysdep_app_handler(int); extern int sysdep_app_open(void); extern int sysdep_cleartext(int, int); extern void sysdep_connection_check(char *); extern int sysdep_ipsec_delete_spi(struct sa *, struct proto *, int); extern int sysdep_ipsec_enable_sa(struct sa *, struct sa *); extern u_int8_t *sysdep_ipsec_get_spi(size_t *, u_int8_t, struct sockaddr *, struct sockaddr *, u_int32_t); extern struct sa_kinfo *sysdep_ipsec_get_kernel_sa(u_int8_t *, size_t, u_int8_t, struct sockaddr *); extern int sysdep_ipsec_group_spis(struct sa *, struct proto *, struct proto *, int); extern int sysdep_ipsec_set_spi(struct sa *, struct proto *, int, struct sa *); extern char *sysdep_progname(void); extern u_int32_t sysdep_random(void); extern u_int8_t sysdep_sa_len(struct sockaddr *); #if defined (USE_BOEHM_GC) /* * Use Boehm's garbage collector as a means to find leaks. * XXX The defines below are GCC-specific. I think it is OK to require * XXX GCC if you are debugging isakmpd in this way. */ void *GC_debug_malloc(size_t, char *, int); void *GC_debug_realloc(void *, size_t, char *, int); void GC_debug_free(void *); char *gc_strdup(const char *); #define malloc(x) GC_debug_malloc ((x), __FILE__, __LINE__) #define realloc(x,y) GC_debug_realloc ((x), (y), __FILE__, __LINE__) #define free(x) GC_debug_free (x) #define calloc(x,y) malloc((x) * (y)) #define strdup(x) gc_strdup((x)) #endif /* WITH_BOEHM_GC */ #endif /* _SYSDEP_H_ */ isakmpd-20041012.orig/gmp_util.c0000644000175000017500000000577110133045740016553 0ustar jdivejdive00000000000000/* $OpenBSD: gmp_util.c,v 1.11 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: gmp_util.c,v 1.7 2000/09/18 00:01:47 ho Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 1999, 2000 Niklas Hallqvist. 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 * 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include "sysdep.h" #include "gmp_util.h" #include "math_mp.h" /* Various utility functions for gmp, used in more than one module */ u_int32_t mpz_sizeinoctets(math_mp_t a) { #if MP_FLAVOUR == MP_FLAVOUR_GMP return (7 + mpz_sizeinbase(a, 2)) >> 3; #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL return BN_num_bytes(a); #endif } void mpz_getraw(u_int8_t *raw, math_mp_t v, u_int32_t len) { math_mp_t a; #if MP_FLAVOUR == MP_FLAVOUR_GMP math_mp_t tmp; /* XXX mpz_get_str (raw, BASE, v); ? */ mpz_init_set(a, v); mpz_init(tmp); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL /* XXX bn2bin? */ a = BN_dup(v); #endif while (len-- > 0) #if MP_FLAVOUR == MP_FLAVOUR_GMP raw[len] = mpz_fdiv_qr_ui(a, tmp, a, 256); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL raw[len] = BN_div_word(a, 256); #endif #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_clear(a); mpz_clear(tmp); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL BN_clear_free(a); #endif } void mpz_setraw(math_mp_t d, u_int8_t *s, u_int32_t l) { u_int32_t i; #if MP_FLAVOUR == MP_FLAVOUR_GMP /* XXX mpz_set_str (d, s, 0); */ mpz_set_si(d, 0); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL /* XXX bin2bn? */ BN_set_word(d, 0); #endif for (i = 0; i < l; i++) { #if MP_FLAVOUR == MP_FLAVOUR_GMP mpz_mul_ui(d, d, 256); mpz_add_ui(d, d, s[i]); #elif MP_FLAVOUR == MP_FLAVOUR_OPENSSL BN_mul_word(d, 256); BN_add_word(d, s[i]); #endif } } isakmpd-20041012.orig/math_2n.h0000644000175000017500000001114310133045740016256 0ustar jdivejdive00000000000000/* $OpenBSD: math_2n.h,v 1.7 2004/04/15 18:39:26 deraadt Exp $ */ /* $EOM: math_2n.h,v 1.9 1999/04/17 23:20:32 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _MATH_2N_H #define _MATH_2N_H_ /* * The chunk size we use is variable, this allows speed ups * for processors like the Alpha with 64bit words. * XXX - b2n_mask is only up to 32 bit at the moment. */ #define USE_32BIT /* XXX - This obviously needs fixing */ #ifdef USE_32BIT #define CHUNK_TYPE u_int32_t #define CHUNK_BITS 32 #define CHUNK_SHIFTS 5 #define CHUNK_BMASK 0xffffffff #define CHUNK_MASK (CHUNK_BITS - 1) #define CHUNK_BYTES (CHUNK_BITS >> 3) #define CHUNK_NIBBLES (CHUNK_BITS >> 2) #else #define CHUNK_TYPE u_int8_t #define CHUNK_BITS 8 #define CHUNK_SHIFTS 3 #define CHUNK_BMASK 0xff #define CHUNK_MASK (CHUNK_BITS - 1) #define CHUNK_BYTES (CHUNK_BITS >> 3) #define CHUNK_NIBBLES (CHUNK_BITS >> 2) #endif extern CHUNK_TYPE b2n_mask[CHUNK_BITS]; /* An element of GF(2**n), n = bits */ typedef struct { u_int16_t chunks; u_int16_t bits; u_int8_t dirty; /* Sig bits are dirty */ CHUNK_TYPE *limp; } _b2n; typedef _b2n *b2n_ptr; typedef _b2n b2n_t[1]; #define B2N_SET(x,y) do \ { \ (x)->chunks = (y)->chunks; \ (x)->bits = (y)->bits; \ (x)->limp = (y)->limp; \ (x)->dirty = (y)->dirty; \ } \ while (0) #define B2N_SWAP(x,y) do \ { \ b2n_t _t_; \ \ B2N_SET (_t_, (x)); \ B2N_SET ((x), (y)); \ B2N_SET ((y), _t_); \ } \ while (0) #define B2N_MIN(x,y) ((x)->chunks > (y)->chunks ? (y) : (x)) #define B2N_MAX(x,y) ((x)->chunks > (y)->chunks ? (x) : (y)) int b2n_3mul(b2n_ptr, b2n_ptr); int b2n_add(b2n_ptr, b2n_ptr, b2n_ptr); int b2n_cmp(b2n_ptr, b2n_ptr); int b2n_cmp_null(b2n_ptr); int b2n_div(b2n_ptr, b2n_ptr, b2n_ptr, b2n_ptr); int b2n_div_mod(b2n_ptr, b2n_ptr, b2n_ptr, b2n_ptr); int b2n_div_q(b2n_ptr, b2n_ptr, b2n_ptr); int b2n_div_r(b2n_ptr, b2n_ptr, b2n_ptr); int b2n_exp_mod(b2n_ptr, b2n_ptr, u_int32_t, b2n_ptr); void b2n_init(b2n_ptr); void b2n_clear(b2n_ptr); int b2n_gcd(b2n_ptr, b2n_ptr, b2n_ptr); int b2n_halftrace(b2n_ptr, b2n_ptr, b2n_ptr); int b2n_lshift(b2n_ptr, b2n_ptr, unsigned int); int b2n_mod(b2n_ptr, b2n_ptr, b2n_ptr); int b2n_mul(b2n_ptr, b2n_ptr, b2n_ptr); int b2n_mul_inv(b2n_ptr, b2n_ptr, b2n_ptr); int b2n_nadd(b2n_ptr, b2n_ptr, b2n_ptr); int b2n_nsub(b2n_ptr, b2n_ptr, b2n_ptr); void b2n_print(b2n_ptr); int b2n_random(b2n_ptr, u_int32_t); int b2n_resize(b2n_ptr, unsigned int); int b2n_rshift(b2n_ptr, b2n_ptr, unsigned int); int b2n_set(b2n_ptr, b2n_ptr); int b2n_set_null(b2n_ptr); int b2n_set_str(b2n_ptr, char *); int b2n_set_ui(b2n_ptr, unsigned int); u_int32_t b2n_sigbit(b2n_ptr); int b2n_snprint(char *, size_t, b2n_ptr); int b2n_sqrt(b2n_ptr, b2n_ptr, b2n_ptr); int b2n_square(b2n_ptr, b2n_ptr); #define b2n_sub b2n_add int b2n_trace(b2n_ptr, b2n_ptr, b2n_ptr); #endif /* _MATH_2N_H_ */ isakmpd-20041012.orig/ike_auth.c0000644000175000017500000007633510133045740016530 0ustar jdivejdive00000000000000/* $OpenBSD: ike_auth.c,v 1.95 2004/08/08 19:11:06 deraadt Exp $ */ /* $EOM: ike_auth.c,v 1.59 2000/11/21 00:21:31 angelos Exp $ */ /* * Copyright (c) 1998, 1999, 2000, 2001 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, 2001, 2003 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include #include #include #include #if defined (USE_KEYNOTE) #include #endif #include #include "sysdep.h" #include "cert.h" #include "conf.h" #include "constants.h" #if defined (USE_DNSSEC) #include "dnssec.h" #endif #include "exchange.h" #include "gmp_util.h" #include "hash.h" #include "ike_auth.h" #include "ipsec.h" #include "ipsec_doi.h" #include "libcrypto.h" #include "log.h" #include "message.h" #include "monitor.h" #include "prf.h" #include "transport.h" #include "util.h" #include "key.h" #if defined (USE_X509) #include "x509.h" #endif #ifdef notyet static u_int8_t *enc_gen_skeyid(struct exchange *, size_t *); #endif static u_int8_t *pre_shared_gen_skeyid(struct exchange *, size_t *); static int pre_shared_decode_hash(struct message *); static int pre_shared_encode_hash(struct message *); #if defined (USE_X509) || defined (USE_KEYNOTE) static u_int8_t *sig_gen_skeyid(struct exchange *, size_t *); static int rsa_sig_decode_hash(struct message *); static int rsa_sig_encode_hash(struct message *); #endif #if defined (USE_RAWKEY) static int get_raw_key_from_file(int, u_int8_t *, size_t, RSA **); #endif static int ike_auth_hash(struct exchange *, u_int8_t *); static struct ike_auth ike_auth[] = { { IKE_AUTH_PRE_SHARED, pre_shared_gen_skeyid, pre_shared_decode_hash, pre_shared_encode_hash }, #ifdef notdef { IKE_AUTH_DSS, sig_gen_skeyid, pre_shared_decode_hash, pre_shared_encode_hash }, #endif #if defined (USE_X509) || defined (USE_KEYNOTE) { IKE_AUTH_RSA_SIG, sig_gen_skeyid, rsa_sig_decode_hash, rsa_sig_encode_hash }, #endif #ifdef notdef { IKE_AUTH_RSA_ENC, enc_gen_skeyid, pre_shared_decode_hash, pre_shared_encode_hash }, { IKE_AUTH_RSA_ENC_REV, enc_gen_skeyid, pre_shared_decode_hash, pre_shared_encode_hash }, #endif }; struct ike_auth * ike_auth_get(u_int16_t id) { size_t i; for (i = 0; i < sizeof ike_auth / sizeof ike_auth[0]; i++) if (id == ike_auth[i].id) return &ike_auth[i]; return 0; } /* * Find and decode the configured key (pre-shared or public) for the * peer denoted by ID. Stash the len in KEYLEN. */ static void * ike_auth_get_key(int type, char *id, char *local_id, size_t *keylen) { char *key, *buf; #if defined (USE_X509) || defined (USE_KEYNOTE) int fd; char *keyfile; #if defined (USE_X509) FILE *keyfp; RSA *rsakey; size_t fsize; #endif #endif switch (type) { case IKE_AUTH_PRE_SHARED: /* Get the pre-shared key for our peer. */ key = conf_get_str(id, "Authentication"); if (!key && local_id) key = conf_get_str(local_id, "Authentication"); if (!key) { log_print("ike_auth_get_key: " "no key found for peer \"%s\" or local ID \"%s\"", id, local_id); return 0; } /* If the key starts with 0x it is in hex format. */ if (strncasecmp(key, "0x", 2) == 0) { *keylen = (strlen(key) - 1) / 2; buf = malloc(*keylen); if (!buf) { log_error("ike_auth_get_key: malloc (%lu) " "failed", (unsigned long)*keylen); return 0; } if (hex2raw(key + 2, (unsigned char *)buf, *keylen)) { free(buf); log_print("ike_auth_get_key: invalid hex key " "%s", key); return 0; } key = buf; } else { buf = key; key = strdup(buf); if (!key) { log_error("ike_auth_get_key: strdup() failed"); return 0; } *keylen = strlen(key); } break; case IKE_AUTH_RSA_SIG: #if defined (USE_X509) || defined (USE_KEYNOTE) #if defined (USE_KEYNOTE) if (local_id && (keyfile = conf_get_str("KeyNote", "Credential-directory")) != 0) { struct stat sb; struct keynote_deckey dc; char *privkeyfile, *buf2; int pkflen; size_t size; pkflen = strlen(keyfile) + strlen(local_id) + sizeof PRIVATE_KEY_FILE + sizeof "//" - 1; privkeyfile = calloc(pkflen, sizeof(char)); if (!privkeyfile) { log_print("ike_auth_get_key: failed to " "allocate %d bytes", pkflen); return 0; } snprintf(privkeyfile, pkflen, "%s/%s/%s", keyfile, local_id, PRIVATE_KEY_FILE); keyfile = privkeyfile; fd = monitor_open(keyfile, O_RDONLY, 0); if (fd < 0) { free(keyfile); goto ignorekeynote; } if (fstat(fd, &sb) < 0) { log_print("ike_auth_get_key: fstat failed"); free(keyfile); close(fd); return 0; } size = (size_t)sb.st_size; buf = calloc(size + 1, sizeof(char)); if (!buf) { log_print("ike_auth_get_key: failed allocating" " %lu bytes", (unsigned long)size + 1); free(keyfile); close(fd); return 0; } if (read(fd, buf, size) != (ssize_t)size) { free(buf); log_print("ike_auth_get_key: " "failed reading %lu bytes from \"%s\"", (unsigned long)size, keyfile); free(keyfile); close(fd); return 0; } close(fd); /* Parse private key string */ buf2 = kn_get_string(buf); free(buf); if (!buf2 || kn_decode_key(&dc, buf2, KEYNOTE_PRIVATE_KEY) == -1) { if (buf2) free(buf2); log_print("ike_auth_get_key: failed decoding " "key in \"%s\"", keyfile); free(keyfile); return 0; } free(buf2); if (dc.dec_algorithm != KEYNOTE_ALGORITHM_RSA) { log_print("ike_auth_get_key: wrong algorithm " "type %d in \"%s\"", dc.dec_algorithm, keyfile); free(keyfile); kn_free_key(&dc); return 0; } free(keyfile); return dc.dec_key; } ignorekeynote: #endif /* USE_KEYNOTE */ #ifdef USE_X509 /* Otherwise, try X.509 */ keyfile = conf_get_str("X509-certificates", "Private-key"); fd = monitor_open(keyfile, O_RDONLY, 0); if (fd < 0) { log_print("ike_auth_get_key: failed opening \"%s\"", keyfile); return 0; } if (check_file_secrecy_fd(fd, keyfile, &fsize) < 0) { close(fd); return 0; } if ((keyfp = fdopen(fd, "r")) == NULL) { log_print("ike_auth_get_key: fdopen failed"); close(fd); return 0; } #if SSLEAY_VERSION_NUMBER >= 0x00904100L rsakey = PEM_read_RSAPrivateKey(keyfp, NULL, NULL, NULL); #else rsakey = PEM_read_RSAPrivateKey(keyfp, NULL, NULL); #endif fclose(keyfp); if (!rsakey) { log_print("ike_auth_get_key: " "PEM_read_bio_RSAPrivateKey failed"); return 0; } return rsakey; #endif /* USE_X509 */ #endif /* USE_X509 || USE_KEYNOTE */ default: log_print("ike_auth_get_key: unknown key type %d", type); return 0; } return key; } static u_int8_t * pre_shared_gen_skeyid(struct exchange *exchange, size_t *sz) { struct prf *prf; struct ipsec_exch *ie = exchange->data; u_int8_t *skeyid, *buf = 0; unsigned char *key; size_t keylen; /* * If we're the responder and have the initiator's ID (which is the * case in Aggressive mode), try to find the preshared key in the * section of the initiator's Phase 1 ID. This allows us to do * mobile user support with preshared keys. */ if (!exchange->initiator && exchange->id_i) { switch (exchange->id_i[0]) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: util_ntoa((char **) &buf, exchange->id_i[0] == IPSEC_ID_IPV4_ADDR ? AF_INET : AF_INET6, exchange->id_i + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ); if (!buf) return 0; break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: buf = calloc(exchange->id_i_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1, sizeof(char)); if (!buf) { log_print("pre_shared_gen_skeyid: malloc (%lu" ") failed", (unsigned long)exchange->id_i_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1); return 0; } memcpy(buf, exchange->id_i + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, exchange->id_i_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); break; /* XXX Support more ID types ? */ default: break; } } /* * Get the pre-shared key for our peer. This will work even if the key * has been passed to us through a mechanism like PFKEYv2. */ key = ike_auth_get_key(IKE_AUTH_PRE_SHARED, exchange->name, (char *) buf, &keylen); if (buf) free(buf); /* Fail if no key could be found. */ if (!key) return 0; /* Store the secret key for later policy processing. */ exchange->recv_key = calloc(keylen + 1, sizeof(char)); exchange->recv_keytype = ISAKMP_KEY_PASSPHRASE; if (!exchange->recv_key) { log_error("pre_shared_gen_skeyid: malloc (%lu) failed", (unsigned long)keylen); free(key); return 0; } memcpy(exchange->recv_key, key, keylen); exchange->recv_certtype = ISAKMP_CERTENC_NONE; free(key); prf = prf_alloc(ie->prf_type, ie->hash->type, exchange->recv_key, keylen); if (!prf) return 0; *sz = prf->blocksize; skeyid = malloc(*sz); if (!skeyid) { log_error("pre_shared_gen_skeyid: malloc (%lu) failed", (unsigned long)*sz); prf_free(prf); return 0; } prf->Init(prf->prfctx); prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len); prf->Update(prf->prfctx, exchange->nonce_r, exchange->nonce_r_len); prf->Final(skeyid, prf->prfctx); prf_free(prf); return skeyid; } #if defined (USE_X509) || defined (USE_KEYNOTE) /* Both DSS & RSA signature authentication use this algorithm. */ static u_int8_t * sig_gen_skeyid(struct exchange *exchange, size_t *sz) { struct prf *prf; struct ipsec_exch *ie = exchange->data; u_int8_t *skeyid; unsigned char *key; key = malloc(exchange->nonce_i_len + exchange->nonce_r_len); if (!key) return 0; memcpy(key, exchange->nonce_i, exchange->nonce_i_len); memcpy(key + exchange->nonce_i_len, exchange->nonce_r, exchange->nonce_r_len); LOG_DBG((LOG_NEGOTIATION, 80, "sig_gen_skeyid: PRF type %d, hash %d", ie->prf_type, ie->hash->type)); LOG_DBG_BUF((LOG_NEGOTIATION, 80, "sig_gen_skeyid: SKEYID initialized with", (u_int8_t *)key, exchange->nonce_i_len + exchange->nonce_r_len)); prf = prf_alloc(ie->prf_type, ie->hash->type, key, exchange->nonce_i_len + exchange->nonce_r_len); free(key); if (!prf) return 0; *sz = prf->blocksize; skeyid = malloc(*sz); if (!skeyid) { log_error("sig_gen_skeyid: malloc (%lu) failed", (unsigned long)*sz); prf_free(prf); return 0; } LOG_DBG((LOG_NEGOTIATION, 80, "sig_gen_skeyid: g^xy length %lu", (unsigned long) ie->g_x_len)); LOG_DBG_BUF((LOG_NEGOTIATION, 80, "sig_gen_skeyid: SKEYID fed with g^xy", ie->g_xy, ie->g_x_len)); prf->Init(prf->prfctx); prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len); prf->Final(skeyid, prf->prfctx); prf_free(prf); return skeyid; } #endif /* USE_X509 || USE_KEYNOTE */ #ifdef notdef /* * Both standard and revised RSA encryption authentication use this SKEYID * computation. */ static u_int8_t * enc_gen_skeyid(struct exchange *exchange, size_t *sz) { struct prf *prf; struct ipsec_exch *ie = exchange->data; struct hash *hash = ie->hash; u_int8_t *skeyid; hash->Init(hash->ctx); hash->Update(hash->ctx, exchange->nonce_i, exchange->nonce_i_len); hash->Update(hash->ctx, exchange->nonce_r, exchange->nonce_r_len); hash->Final(hash->digest, hash->ctx); prf = prf_alloc(ie->prf_type, hash->type, hash->digest, *sz); if (!prf) return 0; *sz = prf->blocksize; skeyid = malloc(*sz); if (!skeyid) { log_error("enc_gen_skeyid: malloc (%d) failed", *sz); prf_free(prf); return 0; } prf->Init(prf->prfctx); prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN); prf->Final(skeyid, prf->prfctx); prf_free(prf); return skeyid; } #endif /* notdef */ static int pre_shared_decode_hash(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct payload *payload; size_t hashsize = ie->hash->hashsize; char header[80]; int initiator = exchange->initiator; u_int8_t **hash_p; /* Choose the right fields to fill-in. */ hash_p = initiator ? &ie->hash_r : &ie->hash_i; payload = payload_first(msg, ISAKMP_PAYLOAD_HASH); if (!payload) { log_print("pre_shared_decode_hash: no HASH payload found"); return -1; } /* Check that the hash is of the correct size. */ if (GET_ISAKMP_GEN_LENGTH(payload->p) - ISAKMP_GEN_SZ != hashsize) return -1; /* XXX Need this hash be in the SA? */ *hash_p = malloc(hashsize); if (!*hash_p) { log_error("pre_shared_decode_hash: malloc (%lu) failed", (unsigned long)hashsize); return -1; } memcpy(*hash_p, payload->p + ISAKMP_HASH_DATA_OFF, hashsize); snprintf(header, sizeof header, "pre_shared_decode_hash: HASH_%c", initiator ? 'R' : 'I'); LOG_DBG_BUF((LOG_MISC, 80, header, *hash_p, hashsize)); payload->flags |= PL_MARK; return 0; } #if defined (USE_X509) || defined (USE_KEYNOTE) /* Decrypt the HASH in SIG, we already need a parsed ID payload. */ static int rsa_sig_decode_hash(struct message *msg) { struct cert_handler *handler; struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct payload *p; void *cert = 0; u_int8_t *rawcert = 0, **hash_p, **id_cert, *id; u_int32_t rawcertlen, *id_cert_len; RSA *key = 0; size_t hashsize = ie->hash->hashsize, id_len; char header[80]; int len, initiator = exchange->initiator; int found = 0, n, i, id_found; #if defined (USE_DNSSEC) u_int8_t *rawkey = 0; u_int32_t rawkeylen; #endif /* Choose the right fields to fill-in. */ hash_p = initiator ? &ie->hash_r : &ie->hash_i; id = initiator ? exchange->id_r : exchange->id_i; id_len = initiator ? exchange->id_r_len : exchange->id_i_len; if (!id || id_len == 0) { log_print("rsa_sig_decode_hash: ID is missing"); return -1; } /* * XXX Assume we should use the same kind of certification as the * remote... moreover, just use the first CERT payload to decide what * to use. */ p = payload_first(msg, ISAKMP_PAYLOAD_CERT); if (!p) handler = cert_get(ISAKMP_CERTENC_KEYNOTE); else handler = cert_get(GET_ISAKMP_CERT_ENCODING(p->p)); if (!handler) { log_print("rsa_sig_decode_hash: cert_get (%d) failed", p ? GET_ISAKMP_CERT_ENCODING(p->p) : -1); return -1; } #if defined (USE_POLICY) || defined (USE_KEYNOTE) /* * We need the policy session initialized now, so we can add * credentials etc. */ exchange->policy_id = kn_init(); if (exchange->policy_id == -1) { log_print("rsa_sig_decode_hash: failed to initialize policy " "session"); return -1; } #endif /* USE_POLICY || USE_KEYNOTE */ /* Obtain a certificate from our certificate storage. */ if (handler->cert_obtain(id, id_len, 0, &rawcert, &rawcertlen)) { if (handler->id == ISAKMP_CERTENC_X509_SIG) { cert = handler->cert_get(rawcert, rawcertlen); if (!cert) LOG_DBG((LOG_CRYPTO, 50, "rsa_sig_decode_hash:" " certificate malformed")); else { if (!handler->cert_get_key(cert, &key)) { log_print("rsa_sig_decode_hash: " "decoding certificate failed"); handler->cert_free(cert); } else { found++; LOG_DBG((LOG_CRYPTO, 40, "rsa_sig_decode_hash: using cert " "of type %d", handler->id)); exchange->recv_cert = cert; exchange->recv_certtype = handler->id; #if defined (USE_POLICY) x509_generate_kn(exchange->policy_id, cert); #endif /* USE_POLICY */ } } } else if (handler->id == ISAKMP_CERTENC_KEYNOTE) handler->cert_insert(exchange->policy_id, rawcert); free(rawcert); } /* * Walk over potential CERT payloads in this message. * XXX I believe this is the wrong spot for this. CERTs can appear * anytime. */ for (p = payload_first(msg, ISAKMP_PAYLOAD_CERT); p; p = TAILQ_NEXT(p, link)) { p->flags |= PL_MARK; /* * When we have found a key, just walk over the rest, marking * them. */ if (found) continue; handler = cert_get(GET_ISAKMP_CERT_ENCODING(p->p)); if (!handler) { LOG_DBG((LOG_MISC, 30, "rsa_sig_decode_hash: " "no handler for %s CERT encoding", constant_name(isakmp_certenc_cst, GET_ISAKMP_CERT_ENCODING(p->p)))); continue; } cert = handler->cert_get(p->p + ISAKMP_CERT_DATA_OFF, GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_CERT_DATA_OFF); if (!cert) { log_print("rsa_sig_decode_hash: " "can not get data from CERT"); continue; } if (!handler->cert_validate(cert)) { handler->cert_free(cert); log_print("rsa_sig_decode_hash: received CERT can't " "be validated"); continue; } if (GET_ISAKMP_CERT_ENCODING(p->p) == ISAKMP_CERTENC_X509_SIG) { if (!handler->cert_get_subjects(cert, &n, &id_cert, &id_cert_len)) { handler->cert_free(cert); log_print("rsa_sig_decode_hash: can not get " "subject from CERT"); continue; } id_found = 0; for (i = 0; i < n; i++) if (id_cert_len[i] == id_len && id[0] == id_cert[i][0] && memcmp(id + 4, id_cert[i] + 4, id_len - 4) == 0) { id_found++; break; } if (!id_found) { handler->cert_free(cert); log_print("rsa_sig_decode_hash: no CERT " "subject match the ID"); free(id_cert); continue; } cert_free_subjects(n, id_cert, id_cert_len); } if (!handler->cert_get_key(cert, &key)) { handler->cert_free(cert); log_print("rsa_sig_decode_hash: decoding payload CERT " "failed"); continue; } /* We validated the cert, cache it for later use. */ handler->cert_insert(exchange->policy_id, cert); exchange->recv_cert = cert; exchange->recv_certtype = GET_ISAKMP_CERT_ENCODING(p->p); #if defined (USE_POLICY) || defined (USE_KEYNOTE) if (exchange->recv_certtype == ISAKMP_CERTENC_KEYNOTE) { struct keynote_deckey dc; char *pp; int dclen; dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; dc.dec_key = key; pp = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX, KEYNOTE_PUBLIC_KEY); if (pp == NULL) { kn_free_key(&dc); log_print("rsa_sig_decode_hash: failed to " "ASCII-encode key"); return -1; } dclen = strlen(pp) + sizeof "rsa-hex:"; exchange->keynote_key = calloc(dclen, sizeof(char)); if (!exchange->keynote_key) { free(pp); kn_free_key(&dc); log_print("rsa_sig_decode_hash: failed to " "allocate %d bytes", dclen); return -1; } snprintf(exchange->keynote_key, dclen, "rsa-hex:%s", pp); free(pp); } #endif found++; } #if defined (USE_DNSSEC) /* * If no certificate provided a key, try to find a validated DNSSEC * KEY. */ if (!found) { rawkey = dns_get_key(IKE_AUTH_RSA_SIG, msg, &rawkeylen); /* We need to convert 'void *rawkey' into 'RSA *key'. */ if (dns_RSA_dns_to_x509(rawkey, rawkeylen, &key) == 0) found++; else log_print("rsa_sig_decode_hash: KEY to RSA key " "conversion failed"); if (rawkey) free(rawkey); } #endif /* USE_DNSSEC */ #if defined (USE_RAWKEY) /* If we still have not found a key, try to read it from a file. */ if (!found) if (get_raw_key_from_file(IKE_AUTH_RSA_SIG, id, id_len, &key) != -1) found++; #endif if (!found) { log_print("rsa_sig_decode_hash: no public key found"); return -1; } p = payload_first(msg, ISAKMP_PAYLOAD_SIG); if (!p) { log_print("rsa_sig_decode_hash: missing signature payload"); RSA_free(key); return -1; } /* Check that the sig is of the correct size. */ len = GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_SIG_SZ; if (len != RSA_size(key)) { RSA_free(key); log_print("rsa_sig_decode_hash: " "SIG payload length does not match public key"); return -1; } *hash_p = malloc(len); if (!*hash_p) { RSA_free(key); log_error("rsa_sig_decode_hash: malloc (%d) failed", len); return -1; } len = RSA_public_decrypt(len, p->p + ISAKMP_SIG_DATA_OFF, *hash_p, key, RSA_PKCS1_PADDING); if (len == -1) { RSA_free(key); log_print("rsa_sig_decode_hash: RSA_public_decrypt () failed"); return -1; } /* Store key for later use */ exchange->recv_key = key; exchange->recv_keytype = ISAKMP_KEY_RSA; if (len != (int) hashsize) { free(*hash_p); *hash_p = 0; log_print("rsa_sig_decode_hash: len %lu != hashsize %lu", (unsigned long)len, (unsigned long)hashsize); return -1; } snprintf(header, sizeof header, "rsa_sig_decode_hash: HASH_%c", initiator ? 'R' : 'I'); LOG_DBG_BUF((LOG_MISC, 80, header, *hash_p, hashsize)); p->flags |= PL_MARK; return 0; } #endif /* USE_X509 || USE_KEYNOTE */ static int pre_shared_encode_hash(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; size_t hashsize = ie->hash->hashsize; char header[80]; int initiator = exchange->initiator; u_int8_t *buf; buf = ipsec_add_hash_payload(msg, hashsize); if (!buf) return -1; if (ike_auth_hash(exchange, buf + ISAKMP_HASH_DATA_OFF) == -1) return -1; snprintf(header, sizeof header, "pre_shared_encode_hash: HASH_%c", initiator ? 'I' : 'R'); LOG_DBG_BUF((LOG_MISC, 80, header, buf + ISAKMP_HASH_DATA_OFF, hashsize)); return 0; } #if defined (USE_X509) || defined (USE_KEYNOTE) /* Encrypt the HASH into a SIG type. */ static int rsa_sig_encode_hash(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; size_t hashsize = ie->hash->hashsize, id_len; struct cert_handler *handler; char header[80]; int initiator = exchange->initiator, idtype; u_int8_t *buf, *data, *buf2, *id; u_int32_t datalen; int32_t sigsize; void *sent_key; id = initiator ? exchange->id_i : exchange->id_r; id_len = initiator ? exchange->id_i_len : exchange->id_r_len; /* We may have been provided these by the kernel */ buf = (u_int8_t *) conf_get_str(exchange->name, "Credentials"); if (buf && (idtype = conf_get_num(exchange->name, "Credential_Type", -1) != -1)) { exchange->sent_certtype = idtype; handler = cert_get(idtype); if (!handler) { log_print("rsa_sig_encode_hash: cert_get (%d) failed", idtype); return -1; } exchange->sent_cert = handler->cert_from_printable((char *)buf); if (!exchange->sent_cert) { log_print("rsa_sig_encode_hash: failed to retrieve " "certificate"); return -1; } handler->cert_serialize(exchange->sent_cert, &data, &datalen); if (!data) { log_print("rsa_sig_encode_hash: cert serialization " "failed"); return -1; } goto aftercert; /* Skip all the certificate discovery */ } /* XXX This needs to be configurable. */ idtype = ISAKMP_CERTENC_KEYNOTE; /* Find a certificate with subjectAltName = id. */ handler = cert_get(idtype); if (!handler) { idtype = ISAKMP_CERTENC_X509_SIG; handler = cert_get(idtype); if (!handler) { log_print("rsa_sig_encode_hash: cert_get(%d) failed", idtype); return -1; } } if (handler->cert_obtain(id, id_len, 0, &data, &datalen) == 0) { if (idtype == ISAKMP_CERTENC_KEYNOTE) { idtype = ISAKMP_CERTENC_X509_SIG; handler = cert_get(idtype); if (!handler) { log_print("rsa_sig_encode_hash: cert_get(%d) " "failed", idtype); return -1; } if (handler->cert_obtain(id, id_len, 0, &data, &datalen) == 0) { LOG_DBG((LOG_MISC, 10, "rsa_sig_encode_hash: " "no certificate to send")); goto skipcert; } } else { LOG_DBG((LOG_MISC, 10, "rsa_sig_encode_hash: no certificate to send")); goto skipcert; } } /* Let's store the certificate we are going to use */ exchange->sent_certtype = idtype; exchange->sent_cert = handler->cert_get(data, datalen); if (!exchange->sent_cert) { free(data); log_print("rsa_sig_encode_hash: failed to get certificate " "from wire encoding"); return -1; } aftercert: buf = realloc(data, ISAKMP_CERT_SZ + datalen); if (!buf) { log_error("rsa_sig_encode_hash: realloc (%p, %d) failed", data, ISAKMP_CERT_SZ + datalen); free(data); return -1; } memmove(buf + ISAKMP_CERT_SZ, buf, datalen); SET_ISAKMP_CERT_ENCODING(buf, idtype); if (message_add_payload(msg, ISAKMP_PAYLOAD_CERT, buf, ISAKMP_CERT_SZ + datalen, 1)) { free(buf); return -1; } skipcert: /* Again, we may have these from the kernel */ buf = (u_int8_t *) conf_get_str(exchange->name, "PKAuthentication"); if (buf) { key_from_printable(ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, (char *)buf, &data, &datalen); if (!data) { log_print("rsa_sig_encode_hash: badly formatted RSA " "private key"); return 0; } sent_key = key_internalize(ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, data, datalen); if (!sent_key) { log_print("rsa_sig_encode_hash: bad RSA private key " "from dynamic SA acquisition subsystem"); return 0; } } else { /* Try through the regular means. */ switch (id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ]) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: util_ntoa((char **)&buf2, id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ] == IPSEC_ID_IPV4_ADDR ? AF_INET : AF_INET6, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ); if (!buf2) return 0; break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: buf2 = calloc(id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1, sizeof(char)); if (!buf2) { log_print("rsa_sig_encode_hash: malloc (%lu) " "failed", (unsigned long)id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1); return 0; } memcpy(buf2, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); break; /* XXX Support more ID types? */ default: buf2 = 0; return 0; } sent_key = ike_auth_get_key(IKE_AUTH_RSA_SIG, exchange->name, (char *)buf2, 0); free(buf2); /* Did we find a key? */ if (!sent_key) { log_print("rsa_sig_encode_hash: " "could not get private key"); return -1; } } /* Enable RSA blinding. */ if (RSA_blinding_on(sent_key, NULL) != 1) { log_error("rsa_sig_encode_hash: RSA_blinding_on () failed."); return -1; } /* XXX hashsize is not necessarily prf->blocksize. */ buf = malloc(hashsize); if (!buf) { log_error("rsa_sig_encode_hash: malloc (%lu) failed", (unsigned long)hashsize); return -1; } if (ike_auth_hash(exchange, buf) == -1) { free(buf); return -1; } snprintf(header, sizeof header, "rsa_sig_encode_hash: HASH_%c", initiator ? 'I' : 'R'); LOG_DBG_BUF((LOG_MISC, 80, header, buf, hashsize)); data = malloc(RSA_size(sent_key)); if (!data) { log_error("rsa_sig_encode_hash: malloc (%d) failed", RSA_size(sent_key)); return -1; } sigsize = RSA_private_encrypt(hashsize, buf, data, sent_key, RSA_PKCS1_PADDING); if (sigsize == -1) { log_print("rsa_sig_encode_hash: " "RSA_private_encrypt () failed"); if (data) free(data); free(buf); RSA_free(sent_key); return -1; } datalen = (u_int32_t) sigsize; free(buf); buf = realloc(data, ISAKMP_SIG_SZ + datalen); if (!buf) { log_error("rsa_sig_encode_hash: realloc (%p, %d) failed", data, ISAKMP_SIG_SZ + datalen); free(data); return -1; } memmove(buf + ISAKMP_SIG_SZ, buf, datalen); snprintf(header, sizeof header, "rsa_sig_encode_hash: SIG_%c", initiator ? 'I' : 'R'); LOG_DBG_BUF((LOG_MISC, 80, header, buf + ISAKMP_SIG_DATA_OFF, datalen)); if (message_add_payload(msg, ISAKMP_PAYLOAD_SIG, buf, ISAKMP_SIG_SZ + datalen, 1)) { free(buf); return -1; } return 0; } #endif /* USE_X509 || USE_KEYNOTE */ int ike_auth_hash(struct exchange *exchange, u_int8_t *buf) { struct ipsec_exch *ie = exchange->data; struct prf *prf; struct hash *hash = ie->hash; int initiator = exchange->initiator; u_int8_t *id; size_t id_len; /* Choose the right fields to fill-in. */ id = initiator ? exchange->id_i : exchange->id_r; id_len = initiator ? exchange->id_i_len : exchange->id_r_len; /* Allocate the prf and start calculating our HASH. */ prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len); if (!prf) return -1; prf->Init(prf->prfctx); prf->Update(prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len); prf->Update(prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len); prf->Update(prf->prfctx, exchange->cookies + (initiator ? ISAKMP_HDR_ICOOKIE_OFF : ISAKMP_HDR_RCOOKIE_OFF), ISAKMP_HDR_ICOOKIE_LEN); prf->Update(prf->prfctx, exchange->cookies + (initiator ? ISAKMP_HDR_RCOOKIE_OFF : ISAKMP_HDR_ICOOKIE_OFF), ISAKMP_HDR_ICOOKIE_LEN); prf->Update(prf->prfctx, ie->sa_i_b, ie->sa_i_b_len); prf->Update(prf->prfctx, id, id_len); prf->Final(buf, prf->prfctx); prf_free(prf); return 0; } #if defined (USE_RAWKEY) static int get_raw_key_from_file(int type, u_int8_t *id, size_t id_len, RSA **rsa) { char filename[FILENAME_MAX]; char *fstr; FILE *keyfp; if (type != IKE_AUTH_RSA_SIG) { /* XXX More types? */ LOG_DBG((LOG_NEGOTIATION, 20, "get_raw_key_from_file: " "invalid auth type %d\n", type)); return -1; } *rsa = 0; fstr = conf_get_str("General", "Pubkey-directory"); if (!fstr) fstr = CONF_DFLT_PUBKEY_DIR; if (snprintf(filename, sizeof filename, "%s/", fstr) > (int)sizeof filename - 1) return -1; fstr = ipsec_id_string(id, id_len); if (!fstr) { LOG_DBG((LOG_NEGOTIATION, 50, "get_raw_key_from_file: " "ipsec_id_string failed")); return -1; } strlcat(filename, fstr, sizeof filename - strlen(filename)); free(fstr); /* If the file does not exist, fail silently. */ keyfp = monitor_fopen(filename, "r"); if (keyfp) { *rsa = PEM_read_RSA_PUBKEY(keyfp, NULL, NULL, NULL); fclose(keyfp); } else if (errno != ENOENT) { log_error("get_raw_key_from_file: monitor_fopen " "(\"%s\", \"r\") failed", filename); return -1; } else LOG_DBG((LOG_NEGOTIATION, 50, "get_raw_key_from_file: file %s not found", filename)); return (*rsa ? 0 : -1); } #endif /* USE_RAWKEY */ isakmpd-20041012.orig/cookie.c0000644000175000017500000000540510133045740016176 0ustar jdivejdive00000000000000/* $OpenBSD: cookie.c,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */ /* $EOM: cookie.c,v 1.21 1999/08/05 15:00:04 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include "sysdep.h" #include "cookie.h" #include "exchange.h" #include "hash.h" #include "transport.h" #include "util.h" #define COOKIE_SECRET_SIZE 16 /* * Generate an anti-clogging token (a protection against an attacker forcing * us to keep state for a flood of connection requests) a.k.a. a cookie * at BUF, LEN bytes long. The cookie will be generated by hashing of * information found, among otherplaces, in transport T and exchange * EXCHANGE. */ void cookie_gen(struct transport *t, struct exchange *exchange, u_int8_t *buf, size_t len) { struct hash *hash = hash_get(HASH_SHA1); u_int8_t tmpsecret[COOKIE_SECRET_SIZE]; struct sockaddr *name; hash->Init(hash->ctx); (*t->vtbl->get_dst)(t, &name); hash->Update(hash->ctx, (u_int8_t *)name, sysdep_sa_len(name)); (*t->vtbl->get_src)(t, &name); hash->Update(hash->ctx, (u_int8_t *)name, sysdep_sa_len(name)); if (exchange->initiator == 0) hash->Update(hash->ctx, exchange->cookies + ISAKMP_HDR_ICOOKIE_OFF, ISAKMP_HDR_ICOOKIE_LEN); getrandom(tmpsecret, COOKIE_SECRET_SIZE); hash->Update(hash->ctx, tmpsecret, COOKIE_SECRET_SIZE); hash->Final(hash->digest, hash->ctx); memcpy(buf, hash->digest, len); } isakmpd-20041012.orig/sa.h0000644000175000017500000002205610133045740015336 0ustar jdivejdive00000000000000/* $OpenBSD: sa.h,v 1.41 2004/08/10 15:59:10 ho Exp $ */ /* $EOM: sa.h,v 1.58 2000/10/10 12:39:01 provos Exp $ */ /* * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2001 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _SA_H_ #define _SA_H_ #include #include #include #include #include "isakmp.h" /* Remove a SA if it has not been fully negotiated in this time. */ #define SA_NEGOTIATION_MAX_TIME 120 struct crypto_xf; struct doi; struct event; struct exchange; struct keystate; struct message; struct payload; struct proto_attr; struct sa; struct transport; /* A protection suite consists of a set of protocol descriptions like this. */ struct proto { /* Link to the next protocol in the suite. */ TAILQ_ENTRY(proto) link; /* The SA we belong to. */ struct sa *sa; /* The protocol number as found in the proposal payload. */ u_int8_t no; /* The protocol this SA is for. */ u_int8_t proto; /* * Security parameter index info. Element 0 - outgoing, 1 - * incoming. */ u_int8_t spi_sz[2]; u_int8_t *spi[2]; /* * The chosen transform, only valid while the incoming SA payload that * held it is available for duplicate testing. */ struct payload *chosen; /* The chosen transform's ID. */ u_int8_t id; /* DOI-specific data. */ void *data; /* Proposal transforms data, for validating the responders selection. */ TAILQ_HEAD(proto_attr_head, proto_attr) xfs; size_t xf_cnt; }; struct proto_attr { /* Link to next transform. */ TAILQ_ENTRY(proto_attr) next; /* Transform attribute data and size, suitable for attribute_map(). */ u_int8_t *attrs; size_t len; }; struct sa { /* Link to SAs with the same hash value. */ LIST_ENTRY(sa) link; /* * When several SA's are being negotiated in one message we connect * them through this link. */ TAILQ_ENTRY(sa) next; /* * A name of the major policy deciding offers and acceptable * proposals. */ char *name; /* The transport this SA got negotiated over. */ struct transport *transport; /* Both initiator and responder cookies. */ u_int8_t cookies[ISAKMP_HDR_COOKIES_LEN]; /* The message ID signifying non-ISAKMP SAs. */ u_int8_t message_id[ISAKMP_HDR_MESSAGE_ID_LEN]; /* The protection suite chosen. */ TAILQ_HEAD(proto_head, proto) protos; /* The exchange type we should use when rekeying. */ u_int8_t exch_type; /* Phase is 1 for ISAKMP SAs, and 2 for application ones. */ u_int8_t phase; /* A reference counter for this structure. */ u_int16_t refcnt; /* Various flags, look below for descriptions. */ u_int32_t flags; /* The DOI that is to handle DOI-specific issues for this SA. */ struct doi *doi; /* * Crypto info needed to encrypt/decrypt packets protected by this * SA. */ struct crypto_xf *crypto; int key_length; struct keystate *keystate; /* IDs from Phase 1 */ u_int8_t *id_i; size_t id_i_len; u_int8_t *id_r; size_t id_r_len; /* Set if we were the initiator of the SA/exchange in Phase 1 */ int initiator; /* Policy session ID, where applicable, copied over from the exchange */ int policy_id; /* * The key used to authenticate phase 1, in printable format, used * only by KeyNote. */ char *keynote_key; /* * Certificates or other information from Phase 1; these are copied * from the exchange, so look at exchange.h for an explanation of * their use. */ int recv_certtype, recv_keytype; /* Certificate received from peer, native format. */ void *recv_cert; /* Key peer used to authenticate, native format. */ void *recv_key; /* * Certificates or other information we used to authenticate to the * peer, Phase 1. */ int sent_certtype; /* Certificate (to be) sent to peer, native format. */ void *sent_cert; /* DOI-specific opaque data. */ void *data; /* Lifetime data. */ u_int64_t seconds; u_int64_t kilobytes; /* ACQUIRE sequence number */ u_int32_t seq; /* The events that will occur when an SA has timed out. */ struct event *soft_death; struct event *death; #if defined (USE_NAT_TRAVERSAL) struct event *nat_t_keepalive; #endif #if defined (USE_DPD) /* IKE DPD (RFC3706) message sequence number. */ u_int32_t dpd_seq; /* sent */ u_int32_t dpd_rseq; /* recieved */ u_int32_t dpd_failcount; /* # of subsequent failures */ struct event *dpd_event; /* time of next event */ #endif }; /* This SA is alive. */ #define SA_FLAG_READY 0x01 /* Renegotiate the SA at each expiry. */ #define SA_FLAG_STAYALIVE 0x02 /* Establish the SA when it is needed. */ #define SA_FLAG_ONDEMAND 0x04 /* This SA has been replaced by another newer one. */ #define SA_FLAG_REPLACED 0x08 /* This SA has seen a soft timeout and wants to be renegotiated on use. */ #define SA_FLAG_FADING 0x10 /* This SA should always be actively renegotiated (with us as initiator). */ #define SA_FLAG_ACTIVE_ONLY 0x20 /* This SA flag is a placeholder for a TRANSACTION exchange "SA flag". */ #define SA_FLAG_IKECFG 0x40 /* This SA flag indicates if we should do DPD with the phase 1 SA peer. */ #define SA_FLAG_DPD 0x80 /* NAT-T encapsulation state. Kept in isakmp_sa for the new p2 exchange. */ #define SA_FLAG_NAT_T_ENABLE 0x100 #define SA_FLAG_NAT_T_KEEPALIVE 0x200 extern void proto_free(struct proto * proto); extern int sa_add_transform(struct sa *, struct payload *, int, struct proto **); extern int sa_create(struct exchange *, struct transport *); extern int sa_enter(struct sa *); extern void sa_delete(struct sa *, int); extern void sa_teardown_all(void); extern struct sa *sa_find(int (*) (struct sa *, void *), void *); extern int sa_flag(char *); extern void sa_free(struct sa *); extern void sa_init(void); extern void sa_reinit(void); extern struct sa *sa_isakmp_lookup_by_peer(struct sockaddr *, socklen_t); extern void sa_isakmp_upgrade(struct message *); extern struct sa *sa_lookup(u_int8_t *, u_int8_t *); extern struct sa *sa_lookup_by_peer(struct sockaddr *, socklen_t); extern struct sa *sa_lookup_by_header(u_int8_t *, int); extern struct sa *sa_lookup_by_name(char *, int); extern struct sa *sa_lookup_from_icookie(u_int8_t *); extern struct sa *sa_lookup_isakmp_sa(struct sockaddr *, u_int8_t *); extern void sa_mark_replaced(struct sa *); extern void sa_reference(struct sa *); extern void sa_release(struct sa *); extern void sa_remove(struct sa *); extern void sa_report(void); extern void sa_dump(int, int, char *, struct sa *); extern void sa_report_all(FILE *); extern int sa_setup_expirations(struct sa *); /* * This structure contains most of the data of the in-kernel SA. * Currently only used to collect the tdb_last_used time for DPD. */ struct sa_kinfo { u_int32_t flags; /* /usr/include/netinet/ip_ipsp.h */ u_int32_t exp_allocations; u_int32_t soft_allocations; u_int32_t cur_allocations; u_int64_t exp_bytes; u_int64_t soft_bytes; u_int64_t cur_bytes; u_int64_t exp_timeout; u_int64_t soft_timeout; u_int64_t first_use; u_int64_t established; u_int64_t soft_first_use; u_int64_t exp_first_use; u_int64_t last_used; u_int64_t last_marked; struct sockaddr_storage dst; struct sockaddr_storage src; struct sockaddr_storage proxy; u_int32_t spi; u_int32_t rpl; u_int16_t udpencap_port; u_int16_t amxkeylen; u_int16_t emxkeylen; u_int16_t ivlen; u_int8_t sproto; u_int8_t wnd; u_int8_t satype; }; #endif /* _SA_H_ */ isakmpd-20041012.orig/policy.c0000644000175000017500000017011210133045740016222 0ustar jdivejdive00000000000000/* $OpenBSD: policy.c,v 1.78 2004/08/08 19:11:06 deraadt Exp $ */ /* $EOM: policy.c,v 1.49 2000/10/24 13:33:39 niklas Exp $ */ /* * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved. * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2001 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sysdep.h" #include "conf.h" #include "exchange.h" #include "ipsec.h" #include "isakmp_doi.h" #include "sa.h" #include "transport.h" #include "log.h" #include "message.h" #include "monitor.h" #include "util.h" #include "policy.h" #include "x509.h" char **policy_asserts = NULL; int ignore_policy = 0; int policy_asserts_num = 0; struct exchange *policy_exchange = 0; struct sa *policy_sa = 0; struct sa *policy_isakmp_sa = 0; static const char hextab[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /* * Adaptation of Vixie's inet_ntop4 () */ static const char * my_inet_ntop4(const in_addr_t *src, char *dst, size_t size, int normalize) { static const char fmt[] = "%03u.%03u.%03u.%03u"; char tmp[sizeof "255.255.255.255"]; in_addr_t src2; if (normalize) src2 = ntohl(*src); else src2 = *src; if (snprintf(tmp, sizeof tmp, fmt, ((u_int8_t *)&src2)[0], ((u_int8_t *)&src2)[1], ((u_int8_t *)&src2)[2], ((u_int8_t *)&src2)[3]) > (int)size) { errno = ENOSPC; return 0; } strlcpy(dst, tmp, size); return dst; } static const char * my_inet_ntop6(const unsigned char *src, char *dst, size_t size) { static const char fmt[] = "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"; char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; if (snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3], src[4], src[5], src[6], src[7], src[8], src[9], src[10], src[11], src[12], src[13], src[14], src[15]) > (int)size) { errno = ENOSPC; return 0; } strlcpy(dst, tmp, size); return dst; } char * policy_callback(char *name) { struct proto *proto; u_int8_t *attr, *value, *id, *idlocal, *idremote; size_t id_sz, idlocalsz, idremotesz; struct sockaddr *sin; struct ipsec_exch *ie; struct ipsec_sa *is; size_t i; int fmt, lifetype = 0; in_addr_t net, subnet; u_int16_t len, type; time_t tt; char *addr; static char mytimeofday[15]; /* We use all these as a cache. */ #define PMAX 32 static char *esp_present, *ah_present, *comp_present; static char *ah_hash_alg, *ah_auth_alg, *esp_auth_alg, *esp_enc_alg; static char *comp_alg, ah_life_kbytes[PMAX], ah_life_seconds[PMAX]; static char esp_life_kbytes[PMAX], esp_life_seconds[PMAX]; static char comp_life_kbytes[PMAX]; static char *ah_ecn, *esp_ecn, *comp_ecn; static char comp_life_seconds[PMAX], *ah_encapsulation; static char *esp_encapsulation, *comp_encapsulation; static char ah_key_length[PMAX], esp_key_length[PMAX]; static char ah_key_rounds[PMAX], esp_key_rounds[PMAX]; static char comp_dict_size[PMAX], comp_private_alg[PMAX]; static char *remote_filter_type, *local_filter_type; static char remote_filter_addr_upper[NI_MAXHOST]; static char remote_filter_addr_lower[NI_MAXHOST]; static char local_filter_addr_upper[NI_MAXHOST]; static char local_filter_addr_lower[NI_MAXHOST]; static char ah_group_desc[PMAX], esp_group_desc[PMAX]; static char comp_group_desc[PMAX], remote_ike_address[NI_MAXHOST]; static char local_ike_address[NI_MAXHOST]; static char *remote_id_type, remote_id_addr_upper[NI_MAXHOST]; static char *phase_1, remote_id_addr_lower[NI_MAXHOST]; static char *remote_id_proto, remote_id_port[PMAX]; static char remote_filter_port[PMAX], local_filter_port[PMAX]; static char *remote_filter_proto, *local_filter_proto, *pfs; static char *initiator, remote_filter_proto_num[3]; static char local_filter_proto_num[3], remote_id_proto_num[3]; static char phase1_group[PMAX]; /* Allocated. */ static char *remote_filter = 0, *local_filter = 0, *remote_id = 0; static int dirty = 1; /* We only need to set dirty at initialization time really. */ if (strcmp(name, KEYNOTE_CALLBACK_CLEANUP) == 0 || strcmp(name, KEYNOTE_CALLBACK_INITIALIZE) == 0) { esp_present = ah_present = comp_present = pfs = "no"; ah_hash_alg = ah_auth_alg = phase_1 = ""; esp_auth_alg = esp_enc_alg = comp_alg = ah_encapsulation = ""; ah_ecn = esp_ecn = comp_ecn = "no"; esp_encapsulation = comp_encapsulation = ""; remote_filter_type = ""; local_filter_type = remote_id_type = initiator = ""; remote_filter_proto = local_filter_proto = ""; remote_id_proto = ""; if (remote_filter != 0) { free(remote_filter); remote_filter = 0; } if (local_filter != 0) { free(local_filter); local_filter = 0; } if (remote_id != 0) { free(remote_id); remote_id = 0; } memset(remote_ike_address, 0, sizeof remote_ike_address); memset(local_ike_address, 0, sizeof local_ike_address); memset(ah_life_kbytes, 0, sizeof ah_life_kbytes); memset(ah_life_seconds, 0, sizeof ah_life_seconds); memset(esp_life_kbytes, 0, sizeof esp_life_kbytes); memset(esp_life_seconds, 0, sizeof esp_life_seconds); memset(comp_life_kbytes, 0, sizeof comp_life_kbytes); memset(comp_life_seconds, 0, sizeof comp_life_seconds); memset(ah_key_length, 0, sizeof ah_key_length); memset(ah_key_rounds, 0, sizeof ah_key_rounds); memset(esp_key_length, 0, sizeof esp_key_length); memset(esp_key_rounds, 0, sizeof esp_key_rounds); memset(comp_dict_size, 0, sizeof comp_dict_size); memset(comp_private_alg, 0, sizeof comp_private_alg); memset(remote_filter_addr_upper, 0, sizeof remote_filter_addr_upper); memset(remote_filter_addr_lower, 0, sizeof remote_filter_addr_lower); memset(local_filter_addr_upper, 0, sizeof local_filter_addr_upper); memset(local_filter_addr_lower, 0, sizeof local_filter_addr_lower); memset(remote_id_addr_upper, 0, sizeof remote_id_addr_upper); memset(remote_id_addr_lower, 0, sizeof remote_id_addr_lower); memset(ah_group_desc, 0, sizeof ah_group_desc); memset(esp_group_desc, 0, sizeof esp_group_desc); memset(remote_id_port, 0, sizeof remote_id_port); memset(remote_filter_port, 0, sizeof remote_filter_port); memset(local_filter_port, 0, sizeof local_filter_port); memset(phase1_group, 0, sizeof phase1_group); dirty = 1; return ""; } /* * If dirty is set, this is the first request for an attribute, so * populate our value cache. */ if (dirty) { ie = policy_exchange->data; if (ie->pfs) pfs = "yes"; is = policy_isakmp_sa->data; snprintf(phase1_group, sizeof phase1_group, "%u", is->group_desc); for (proto = TAILQ_FIRST(&policy_sa->protos); proto; proto = TAILQ_NEXT(proto, link)) { switch (proto->proto) { case IPSEC_PROTO_IPSEC_AH: ah_present = "yes"; switch (proto->id) { case IPSEC_AH_MD5: ah_hash_alg = "md5"; break; case IPSEC_AH_SHA: ah_hash_alg = "sha"; break; case IPSEC_AH_RIPEMD: ah_hash_alg = "ripemd"; break; case IPSEC_AH_SHA2_256: ah_auth_alg = "sha2-256"; break; case IPSEC_AH_SHA2_384: ah_auth_alg = "sha2-384"; break; case IPSEC_AH_SHA2_512: ah_auth_alg = "sha2-512"; break; case IPSEC_AH_DES: ah_hash_alg = "des"; break; } break; case IPSEC_PROTO_IPSEC_ESP: esp_present = "yes"; switch (proto->id) { case IPSEC_ESP_DES_IV64: esp_enc_alg = "des-iv64"; break; case IPSEC_ESP_DES: esp_enc_alg = "des"; break; case IPSEC_ESP_3DES: esp_enc_alg = "3des"; break; case IPSEC_ESP_AES: case IPSEC_ESP_AES_128_CTR: esp_enc_alg = "aes"; break; case IPSEC_ESP_RC5: esp_enc_alg = "rc5"; break; case IPSEC_ESP_IDEA: esp_enc_alg = "idea"; break; case IPSEC_ESP_CAST: esp_enc_alg = "cast"; break; case IPSEC_ESP_BLOWFISH: esp_enc_alg = "blowfish"; break; case IPSEC_ESP_3IDEA: esp_enc_alg = "3idea"; break; case IPSEC_ESP_DES_IV32: esp_enc_alg = "des-iv32"; break; case IPSEC_ESP_RC4: esp_enc_alg = "rc4"; break; case IPSEC_ESP_NULL: esp_enc_alg = "null"; break; } break; case IPSEC_PROTO_IPCOMP: comp_present = "yes"; switch (proto->id) { case IPSEC_IPCOMP_OUI: comp_alg = "oui"; break; case IPSEC_IPCOMP_DEFLATE: comp_alg = "deflate"; break; case IPSEC_IPCOMP_LZS: comp_alg = "lzs"; break; case IPSEC_IPCOMP_V42BIS: comp_alg = "v42bis"; break; } break; } for (attr = proto->chosen->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF; attr < proto->chosen->p + GET_ISAKMP_GEN_LENGTH(proto->chosen->p); attr = value + len) { if (attr + ISAKMP_ATTR_VALUE_OFF > (proto->chosen->p + GET_ISAKMP_GEN_LENGTH(proto->chosen->p))) return ""; type = GET_ISAKMP_ATTR_TYPE(attr); fmt = ISAKMP_ATTR_FORMAT(type); type = ISAKMP_ATTR_TYPE(type); value = attr + (fmt ? ISAKMP_ATTR_LENGTH_VALUE_OFF : ISAKMP_ATTR_VALUE_OFF); len = (fmt ? ISAKMP_ATTR_LENGTH_VALUE_LEN : GET_ISAKMP_ATTR_LENGTH_VALUE(attr)); if (value + len > proto->chosen->p + GET_ISAKMP_GEN_LENGTH(proto->chosen->p)) return ""; switch (type) { case IPSEC_ATTR_SA_LIFE_TYPE: lifetype = decode_16(value); break; case IPSEC_ATTR_SA_LIFE_DURATION: switch (proto->proto) { case IPSEC_PROTO_IPSEC_AH: if (lifetype == IPSEC_DURATION_SECONDS) { if (len == 2) snprintf(ah_life_seconds, sizeof ah_life_seconds, "%u", decode_16(value)); else snprintf(ah_life_seconds, sizeof ah_life_seconds, "%u", decode_32(value)); } else { if (len == 2) snprintf(ah_life_kbytes, sizeof ah_life_kbytes, "%u", decode_16(value)); else snprintf(ah_life_kbytes, sizeof ah_life_kbytes, "%u", decode_32(value)); } break; case IPSEC_PROTO_IPSEC_ESP: if (lifetype == IPSEC_DURATION_SECONDS) { if (len == 2) snprintf(esp_life_seconds, sizeof esp_life_seconds, "%u", decode_16(value)); else snprintf(esp_life_seconds, sizeof esp_life_seconds, "%u", decode_32(value)); } else { if (len == 2) snprintf(esp_life_kbytes, sizeof esp_life_kbytes, "%u", decode_16(value)); else snprintf(esp_life_kbytes, sizeof esp_life_kbytes, "%u", decode_32(value)); } break; case IPSEC_PROTO_IPCOMP: if (lifetype == IPSEC_DURATION_SECONDS) { if (len == 2) snprintf(comp_life_seconds, sizeof comp_life_seconds, "%u", decode_16(value)); else snprintf(comp_life_seconds, sizeof comp_life_seconds, "%u", decode_32(value)); } else { if (len == 2) snprintf(comp_life_kbytes, sizeof comp_life_kbytes, "%u", decode_16(value)); else snprintf(comp_life_kbytes, sizeof comp_life_kbytes, "%u", decode_32(value)); } break; } break; case IPSEC_ATTR_GROUP_DESCRIPTION: switch (proto->proto) { case IPSEC_PROTO_IPSEC_AH: snprintf(ah_group_desc, sizeof ah_group_desc, "%u", decode_16(value)); break; case IPSEC_PROTO_IPSEC_ESP: snprintf(esp_group_desc, sizeof esp_group_desc, "%u", decode_16(value)); break; case IPSEC_PROTO_IPCOMP: snprintf(comp_group_desc, sizeof comp_group_desc, "%u", decode_16(value)); break; } break; case IPSEC_ATTR_ECN_TUNNEL: if (decode_16(value)) switch (proto->proto) { case IPSEC_PROTO_IPSEC_AH: ah_ecn = "yes"; break; case IPSEC_PROTO_IPSEC_ESP: esp_ecn = "yes"; break; case IPSEC_PROTO_IPCOMP: comp_ecn = "yes"; break; } case IPSEC_ATTR_ENCAPSULATION_MODE: if (decode_16(value) == IPSEC_ENCAP_TUNNEL) switch (proto->proto) { case IPSEC_PROTO_IPSEC_AH: ah_encapsulation = "tunnel"; break; case IPSEC_PROTO_IPSEC_ESP: esp_encapsulation = "tunnel"; break; case IPSEC_PROTO_IPCOMP: comp_encapsulation = "tunnel"; break; } #if defined (USE_NAT_TRAVERSAL) else if (decode_16(value) == IPSEC_ENCAP_UDP_ENCAP_TUNNEL) switch (proto->proto) { case IPSEC_PROTO_IPSEC_AH: ah_encapsulation = "udp-encap-tunnel"; break; case IPSEC_PROTO_IPSEC_ESP: esp_encapsulation = "udp-encap-tunnel"; break; case IPSEC_PROTO_IPCOMP: comp_encapsulation = "udp-encap-tunnel"; break; } /* XXX IPSEC_ENCAP_UDP_ENCAP_TRANSPORT */ #endif else switch (proto->proto) { case IPSEC_PROTO_IPSEC_AH: ah_encapsulation = "transport"; break; case IPSEC_PROTO_IPSEC_ESP: esp_encapsulation = "transport"; break; case IPSEC_PROTO_IPCOMP: comp_encapsulation = "transport"; break; } break; case IPSEC_ATTR_AUTHENTICATION_ALGORITHM: switch (proto->proto) { case IPSEC_PROTO_IPSEC_AH: switch (decode_16(value)) { case IPSEC_AUTH_HMAC_MD5: ah_auth_alg = "hmac-md5"; break; case IPSEC_AUTH_HMAC_SHA: ah_auth_alg = "hmac-sha"; break; case IPSEC_AUTH_HMAC_RIPEMD: ah_auth_alg = "hmac-ripemd"; break; case IPSEC_AUTH_HMAC_SHA2_256: ah_auth_alg = "hmac-sha2-256"; break; case IPSEC_AUTH_HMAC_SHA2_384: ah_auth_alg = "hmac-sha2-384"; break; case IPSEC_AUTH_HMAC_SHA2_512: ah_auth_alg = "hmac-sha2-512"; break; case IPSEC_AUTH_DES_MAC: ah_auth_alg = "des-mac"; break; case IPSEC_AUTH_KPDK: ah_auth_alg = "kpdk"; break; } break; case IPSEC_PROTO_IPSEC_ESP: switch (decode_16(value)) { case IPSEC_AUTH_HMAC_MD5: esp_auth_alg = "hmac-md5"; break; case IPSEC_AUTH_HMAC_SHA: esp_auth_alg = "hmac-sha"; break; case IPSEC_AUTH_HMAC_RIPEMD: esp_auth_alg = "hmac-ripemd"; break; case IPSEC_AUTH_HMAC_SHA2_256: esp_auth_alg = "hmac-sha2-256"; break; case IPSEC_AUTH_HMAC_SHA2_384: esp_auth_alg = "hmac-sha2-384"; break; case IPSEC_AUTH_HMAC_SHA2_512: esp_auth_alg = "hmac-sha2-512"; break; case IPSEC_AUTH_DES_MAC: esp_auth_alg = "des-mac"; break; case IPSEC_AUTH_KPDK: esp_auth_alg = "kpdk"; break; } break; } break; case IPSEC_ATTR_KEY_LENGTH: switch (proto->proto) { case IPSEC_PROTO_IPSEC_AH: snprintf(ah_key_length, sizeof ah_key_length, "%u", decode_16(value)); break; case IPSEC_PROTO_IPSEC_ESP: snprintf(esp_key_length, sizeof esp_key_length, "%u", decode_16(value)); break; } break; case IPSEC_ATTR_KEY_ROUNDS: switch (proto->proto) { case IPSEC_PROTO_IPSEC_AH: snprintf(ah_key_rounds, sizeof ah_key_rounds, "%u", decode_16(value)); break; case IPSEC_PROTO_IPSEC_ESP: snprintf(esp_key_rounds, sizeof esp_key_rounds, "%u", decode_16(value)); break; } break; case IPSEC_ATTR_COMPRESS_DICTIONARY_SIZE: snprintf(comp_dict_size, sizeof comp_dict_size, "%u", decode_16(value)); break; case IPSEC_ATTR_COMPRESS_PRIVATE_ALGORITHM: snprintf(comp_private_alg, sizeof comp_private_alg, "%u", decode_16(value)); break; } } } policy_sa->transport->vtbl->get_src(policy_sa->transport, &sin); if (sockaddr2text(sin, &addr, 1)) { log_error("policy_callback: sockaddr2text failed"); goto bad; } strlcpy(local_ike_address, addr, sizeof local_ike_address); free(addr); policy_sa->transport->vtbl->get_dst(policy_sa->transport, &sin); if (sockaddr2text(sin, &addr, 1)) { log_error("policy_callback: sockaddr2text failed"); goto bad; } strlcpy(remote_ike_address, addr, sizeof remote_ike_address); free(addr); switch (policy_isakmp_sa->exch_type) { case ISAKMP_EXCH_AGGRESSIVE: phase_1 = "aggressive"; break; case ISAKMP_EXCH_ID_PROT: phase_1 = "main"; break; } if (policy_isakmp_sa->initiator) { id = policy_isakmp_sa->id_r; id_sz = policy_isakmp_sa->id_r_len; } else { id = policy_isakmp_sa->id_i; id_sz = policy_isakmp_sa->id_i_len; } switch (id[0]) { case IPSEC_ID_IPV4_ADDR: remote_id_type = "IPv4 address"; net = decode_32(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ); my_inet_ntop4(&net, remote_id_addr_upper, sizeof remote_id_addr_upper - 1, 1); my_inet_ntop4(&net, remote_id_addr_lower, sizeof remote_id_addr_lower - 1, 1); remote_id = strdup(remote_id_addr_upper); if (!remote_id) { log_error("policy_callback: " "strdup (\"%s\") failed", remote_id_addr_upper); goto bad; } break; case IPSEC_ID_IPV4_RANGE: remote_id_type = "IPv4 range"; net = decode_32(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ); my_inet_ntop4(&net, remote_id_addr_lower, sizeof remote_id_addr_lower - 1, 1); net = decode_32(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ + 4); my_inet_ntop4(&net, remote_id_addr_upper, sizeof remote_id_addr_upper - 1, 1); len = strlen(remote_id_addr_upper) + strlen(remote_id_addr_lower) + 2; remote_id = calloc(len, sizeof(char)); if (!remote_id) { log_error("policy_callback: " "calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(remote_id, remote_id_addr_lower, len); strlcat(remote_id, "-", len); strlcat(remote_id, remote_id_addr_upper, len); break; case IPSEC_ID_IPV4_ADDR_SUBNET: remote_id_type = "IPv4 subnet"; net = decode_32(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ); subnet = decode_32(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ + 4); net &= subnet; my_inet_ntop4(&net, remote_id_addr_lower, sizeof remote_id_addr_lower - 1, 1); net |= ~subnet; my_inet_ntop4(&net, remote_id_addr_upper, sizeof remote_id_addr_upper - 1, 1); len = strlen(remote_id_addr_upper) + strlen(remote_id_addr_lower) + 2; remote_id = calloc(len, sizeof(char)); if (!remote_id) { log_error("policy_callback: " "calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(remote_id, remote_id_addr_lower, len); strlcat(remote_id, "-", len); strlcat(remote_id, remote_id_addr_upper, len); break; case IPSEC_ID_IPV6_ADDR: remote_id_type = "IPv6 address"; my_inet_ntop6(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, remote_id_addr_upper, sizeof remote_id_addr_upper); strlcpy(remote_id_addr_lower, remote_id_addr_upper, sizeof remote_id_addr_lower); remote_id = strdup(remote_id_addr_upper); if (!remote_id) { log_error("policy_callback: " "strdup (\"%s\") failed", remote_id_addr_upper); goto bad; } break; case IPSEC_ID_IPV6_RANGE: remote_id_type = "IPv6 range"; my_inet_ntop6(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, remote_id_addr_lower, sizeof remote_id_addr_lower - 1); my_inet_ntop6(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ + 16, remote_id_addr_upper, sizeof remote_id_addr_upper - 1); len = strlen(remote_id_addr_upper) + strlen(remote_id_addr_lower) + 2; remote_id = calloc(len, sizeof(char)); if (!remote_id) { log_error("policy_callback: " "calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(remote_id, remote_id_addr_lower, len); strlcat(remote_id, "-", len); strlcat(remote_id, remote_id_addr_upper, len); break; case IPSEC_ID_IPV6_ADDR_SUBNET: { struct in6_addr net, mask; remote_id_type = "IPv6 subnet"; bcopy(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, &net, sizeof(net)); bcopy(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ + 16, &mask, sizeof(mask)); for (i = 0; i < 16; i++) net.s6_addr[i] &= mask.s6_addr[i]; my_inet_ntop6((unsigned char *)&net, remote_id_addr_lower, sizeof remote_id_addr_lower - 1); for (i = 0; i < 16; i++) net.s6_addr[i] |= ~mask.s6_addr[i]; my_inet_ntop6((unsigned char *)&net, remote_id_addr_upper, sizeof remote_id_addr_upper - 1); len = strlen(remote_id_addr_upper) + strlen(remote_id_addr_lower) + 2; remote_id = calloc(len, sizeof(char)); if (!remote_id) { log_error("policy_callback: " "calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(remote_id, remote_id_addr_lower, len); strlcat(remote_id, "-", len); strlcat(remote_id, remote_id_addr_upper, len); break; } case IPSEC_ID_FQDN: remote_id_type = "FQDN"; remote_id = calloc(id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1, sizeof(char)); if (!remote_id) { log_error("policy_callback: " "calloc (%lu, %lu) failed", (unsigned long)id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1, (unsigned long)sizeof(char)); goto bad; } memcpy(remote_id, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); break; case IPSEC_ID_USER_FQDN: remote_id_type = "User FQDN"; remote_id = calloc(id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1, sizeof(char)); if (!remote_id) { log_error("policy_callback: " "calloc (%lu, %lu) failed", (unsigned long)id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1, (unsigned long)sizeof(char)); goto bad; } memcpy(remote_id, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); break; case IPSEC_ID_DER_ASN1_DN: remote_id_type = "ASN1 DN"; remote_id = x509_DN_string(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); if (!remote_id) { LOG_DBG((LOG_POLICY, 50, "policy_callback: failed to decode name")); goto bad; } break; case IPSEC_ID_DER_ASN1_GN: /* XXX */ remote_id_type = "ASN1 GN"; break; case IPSEC_ID_KEY_ID: remote_id_type = "Key ID"; remote_id = calloc(2 * (id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ) + 1, sizeof(char)); if (!remote_id) { log_error("policy_callback: " "calloc (%lu, %lu) failed", 2 * ((unsigned long)id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ) + 1, (unsigned long)sizeof(char)); goto bad; } /* Does it contain any non-printable characters ? */ for (i = 0; i < id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ; i++) if (!isprint(*(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ + i))) break; if (i >= id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ) { memcpy(remote_id, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ); break; } /* Non-printable characters, convert to hex */ for (i = 0; i < id_sz - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ; i++) { remote_id[2 * i] = hextab[*(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ) >> 4]; remote_id[2 * i + 1] = hextab[*(id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ) & 0xF]; } break; default: log_print("policy_callback: " "unknown remote ID type %u", id[0]); goto bad; } switch (id[1]) { case IPPROTO_TCP: remote_id_proto = "tcp"; break; case IPPROTO_UDP: remote_id_proto = "udp"; break; #ifdef IPPROTO_ETHERIP case IPPROTO_ETHERIP: remote_id_proto = "etherip"; break; #endif default: snprintf(remote_id_proto_num, sizeof remote_id_proto_num, "%d", id[1]); remote_id_proto = remote_id_proto_num; break; } snprintf(remote_id_port, sizeof remote_id_port, "%u", decode_16(id + 2)); if (policy_exchange->initiator) { initiator = "yes"; idlocal = ie->id_ci; idremote = ie->id_cr; idlocalsz = ie->id_ci_sz; idremotesz = ie->id_cr_sz; } else { initiator = "no"; idlocal = ie->id_cr; idremote = ie->id_ci; idlocalsz = ie->id_cr_sz; idremotesz = ie->id_ci_sz; } /* Initialize the ID variables. */ if (idremote) { switch (GET_ISAKMP_ID_TYPE(idremote)) { case IPSEC_ID_IPV4_ADDR: remote_filter_type = "IPv4 address"; net = decode_32(idremote + ISAKMP_ID_DATA_OFF); my_inet_ntop4(&net, remote_filter_addr_upper, sizeof remote_filter_addr_upper - 1, 1); my_inet_ntop4(&net, remote_filter_addr_lower, sizeof remote_filter_addr_lower - 1, 1); remote_filter = strdup(remote_filter_addr_upper); if (!remote_filter) { log_error("policy_callback: strdup " "(\"%s\") failed", remote_filter_addr_upper); goto bad; } break; case IPSEC_ID_IPV4_RANGE: remote_filter_type = "IPv4 range"; net = decode_32(idremote + ISAKMP_ID_DATA_OFF); my_inet_ntop4(&net, remote_filter_addr_lower, sizeof remote_filter_addr_lower - 1, 1); net = decode_32(idremote + ISAKMP_ID_DATA_OFF + 4); my_inet_ntop4(&net, remote_filter_addr_upper, sizeof remote_filter_addr_upper - 1, 1); len = strlen(remote_filter_addr_upper) + strlen(remote_filter_addr_lower) + 2; remote_filter = calloc(len, sizeof(char)); if (!remote_filter) { log_error("policy_callback: calloc " "(%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(remote_filter, remote_filter_addr_lower, len); strlcat(remote_filter, "-", len); strlcat(remote_filter, remote_filter_addr_upper, len); break; case IPSEC_ID_IPV4_ADDR_SUBNET: remote_filter_type = "IPv4 subnet"; net = decode_32(idremote + ISAKMP_ID_DATA_OFF); subnet = decode_32(idremote + ISAKMP_ID_DATA_OFF + 4); net &= subnet; my_inet_ntop4(&net, remote_filter_addr_lower, sizeof remote_filter_addr_lower - 1, 1); net |= ~subnet; my_inet_ntop4(&net, remote_filter_addr_upper, sizeof remote_filter_addr_upper - 1, 1); len = strlen(remote_filter_addr_upper) + strlen(remote_filter_addr_lower) + 2; remote_filter = calloc(len, sizeof(char)); if (!remote_filter) { log_error("policy_callback: calloc " "(%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(remote_filter, remote_filter_addr_lower, len); strlcat(remote_filter, "-", len); strlcat(remote_filter, remote_filter_addr_upper, len); break; case IPSEC_ID_IPV6_ADDR: remote_filter_type = "IPv6 address"; my_inet_ntop6(idremote + ISAKMP_ID_DATA_OFF, remote_filter_addr_upper, sizeof remote_filter_addr_upper - 1); strlcpy(remote_filter_addr_lower, remote_filter_addr_upper, sizeof remote_filter_addr_lower); remote_filter = strdup(remote_filter_addr_upper); if (!remote_filter) { log_error("policy_callback: strdup " "(\"%s\") failed", remote_filter_addr_upper); goto bad; } break; case IPSEC_ID_IPV6_RANGE: remote_filter_type = "IPv6 range"; my_inet_ntop6(idremote + ISAKMP_ID_DATA_OFF, remote_filter_addr_lower, sizeof remote_filter_addr_lower - 1); my_inet_ntop6(idremote + ISAKMP_ID_DATA_OFF + 16, remote_filter_addr_upper, sizeof remote_filter_addr_upper - 1); len = strlen(remote_filter_addr_upper) + strlen(remote_filter_addr_lower) + 2; remote_filter = calloc(len, sizeof(char)); if (!remote_filter) { log_error("policy_callback: calloc " "(%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(remote_filter, remote_filter_addr_lower, len); strlcat(remote_filter, "-", len); strlcat(remote_filter, remote_filter_addr_upper, len); break; case IPSEC_ID_IPV6_ADDR_SUBNET: { struct in6_addr net, mask; remote_filter_type = "IPv6 subnet"; bcopy(idremote + ISAKMP_ID_DATA_OFF, &net, sizeof(net)); bcopy(idremote + ISAKMP_ID_DATA_OFF + 16, &mask, sizeof(mask)); for (i = 0; i < 16; i++) net.s6_addr[i] &= mask.s6_addr[i]; my_inet_ntop6((unsigned char *)&net, remote_filter_addr_lower, sizeof remote_filter_addr_lower - 1); for (i = 0; i < 16; i++) net.s6_addr[i] |= ~mask.s6_addr[i]; my_inet_ntop6((unsigned char *)&net, remote_filter_addr_upper, sizeof remote_filter_addr_upper - 1); len = strlen(remote_filter_addr_upper) + strlen(remote_filter_addr_lower) + 2; remote_filter = calloc(len, sizeof(char)); if (!remote_filter) { log_error("policy_callback: " "calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(remote_filter, remote_filter_addr_lower, len); strlcat(remote_filter, "-", len); strlcat(remote_filter, remote_filter_addr_upper, len); break; } case IPSEC_ID_FQDN: remote_filter_type = "FQDN"; remote_filter = malloc(idremotesz - ISAKMP_ID_DATA_OFF + 1); if (!remote_filter) { log_error("policy_callback: " "malloc (%lu) failed", (unsigned long)idremotesz - ISAKMP_ID_DATA_OFF + 1); goto bad; } memcpy(remote_filter, idremote + ISAKMP_ID_DATA_OFF, idremotesz - ISAKMP_ID_DATA_OFF); remote_filter[idremotesz - ISAKMP_ID_DATA_OFF] = '\0'; break; case IPSEC_ID_USER_FQDN: remote_filter_type = "User FQDN"; remote_filter = malloc(idremotesz - ISAKMP_ID_DATA_OFF + 1); if (!remote_filter) { log_error("policy_callback: " "malloc (%lu) failed", (unsigned long)idremotesz - ISAKMP_ID_DATA_OFF + 1); goto bad; } memcpy(remote_filter, idremote + ISAKMP_ID_DATA_OFF, idremotesz - ISAKMP_ID_DATA_OFF); remote_filter[idremotesz - ISAKMP_ID_DATA_OFF] = '\0'; break; case IPSEC_ID_DER_ASN1_DN: remote_filter_type = "ASN1 DN"; remote_filter = x509_DN_string(idremote + ISAKMP_ID_DATA_OFF, idremotesz - ISAKMP_ID_DATA_OFF); if (!remote_filter) { LOG_DBG((LOG_POLICY, 50, "policy_callback: " "failed to decode name")); goto bad; } break; case IPSEC_ID_DER_ASN1_GN: /* XXX -- not sure * what's in this. */ remote_filter_type = "ASN1 GN"; break; case IPSEC_ID_KEY_ID: remote_filter_type = "Key ID"; remote_filter = calloc(2 * (idremotesz - ISAKMP_ID_DATA_OFF) + 1, sizeof(char)); if (!remote_filter) { log_error("policy_callback: " "calloc (%lu, %lu) failed", 2 * ((unsigned long)idremotesz - ISAKMP_ID_DATA_OFF) + 1, (unsigned long)sizeof(char)); goto bad; } /* * Does it contain any non-printable * characters ? */ for (i = 0; i < idremotesz - ISAKMP_ID_DATA_OFF; i++) if (!isprint(*(idremote + ISAKMP_ID_DATA_OFF + i))) break; if (i >= idremotesz - ISAKMP_ID_DATA_OFF) { memcpy(remote_filter, idremote + ISAKMP_ID_DATA_OFF, idremotesz - ISAKMP_ID_DATA_OFF); break; } /* Non-printable characters, convert to hex */ for (i = 0; i < idremotesz - ISAKMP_ID_DATA_OFF; i++) { remote_filter[2 * i] = hextab[*(idremote + ISAKMP_ID_DATA_OFF) >> 4]; remote_filter[2 * i + 1] = hextab[*(idremote + ISAKMP_ID_DATA_OFF) & 0xF]; } break; default: log_print("policy_callback: " "unknown Remote ID type %u", GET_ISAKMP_ID_TYPE(idremote)); goto bad; } switch (idremote[ISAKMP_GEN_SZ + 1]) { case IPPROTO_TCP: remote_filter_proto = "tcp"; break; case IPPROTO_UDP: remote_filter_proto = "udp"; break; #ifdef IPPROTO_ETHERIP case IPPROTO_ETHERIP: remote_filter_proto = "etherip"; break; #endif default: snprintf(remote_filter_proto_num, sizeof remote_filter_proto_num, "%d", idremote[ISAKMP_GEN_SZ + 1]); remote_filter_proto = remote_filter_proto_num; break; } snprintf(remote_filter_port, sizeof remote_filter_port, "%u", decode_16(idremote + ISAKMP_GEN_SZ + 2)); } else { policy_sa->transport->vtbl->get_dst(policy_sa->transport, &sin); switch (sin->sa_family) { case AF_INET: remote_filter_type = "IPv4 address"; break; case AF_INET6: remote_filter_type = "IPv6 address"; break; default: log_print("policy_callback: " "unsupported protocol family %d", sin->sa_family); goto bad; } if (sockaddr2text(sin, &addr, 1)) { log_error("policy_callback: " "sockaddr2text failed"); goto bad; } memcpy(remote_filter_addr_upper, addr, sizeof remote_filter_addr_upper); memcpy(remote_filter_addr_lower, addr, sizeof remote_filter_addr_lower); free(addr); remote_filter = strdup(remote_filter_addr_upper); if (!remote_filter) { log_error("policy_callback: " "strdup (\"%s\") failed", remote_filter_addr_upper); goto bad; } } if (idlocal) { switch (GET_ISAKMP_ID_TYPE(idlocal)) { case IPSEC_ID_IPV4_ADDR: local_filter_type = "IPv4 address"; net = decode_32(idlocal + ISAKMP_ID_DATA_OFF); my_inet_ntop4(&net, local_filter_addr_upper, sizeof local_filter_addr_upper - 1, 1); my_inet_ntop4(&net, local_filter_addr_lower, sizeof local_filter_addr_upper - 1, 1); local_filter = strdup(local_filter_addr_upper); if (!local_filter) { log_error("policy_callback: " "strdup (\"%s\") failed", local_filter_addr_upper); goto bad; } break; case IPSEC_ID_IPV4_RANGE: local_filter_type = "IPv4 range"; net = decode_32(idlocal + ISAKMP_ID_DATA_OFF); my_inet_ntop4(&net, local_filter_addr_lower, sizeof local_filter_addr_lower - 1, 1); net = decode_32(idlocal + ISAKMP_ID_DATA_OFF + 4); my_inet_ntop4(&net, local_filter_addr_upper, sizeof local_filter_addr_upper - 1, 1); len = strlen(local_filter_addr_upper) + strlen(local_filter_addr_lower) + 2; local_filter = calloc(len, sizeof(char)); if (!local_filter) { log_error("policy_callback: " "calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(local_filter, local_filter_addr_lower, len); strlcat(local_filter, "-", len); strlcat(local_filter, local_filter_addr_upper, len); break; case IPSEC_ID_IPV4_ADDR_SUBNET: local_filter_type = "IPv4 subnet"; net = decode_32(idlocal + ISAKMP_ID_DATA_OFF); subnet = decode_32(idlocal + ISAKMP_ID_DATA_OFF + 4); net &= subnet; my_inet_ntop4(&net, local_filter_addr_lower, sizeof local_filter_addr_lower - 1, 1); net |= ~subnet; my_inet_ntop4(&net, local_filter_addr_upper, sizeof local_filter_addr_upper - 1, 1); len = strlen(local_filter_addr_upper) + strlen(local_filter_addr_lower) + 2; local_filter = calloc(len, sizeof(char)); if (!local_filter) { log_error("policy_callback: " "calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(local_filter, local_filter_addr_lower, len); strlcat(local_filter, "-", len); strlcat(local_filter, local_filter_addr_upper, len); break; case IPSEC_ID_IPV6_ADDR: local_filter_type = "IPv6 address"; my_inet_ntop6(idlocal + ISAKMP_ID_DATA_OFF, local_filter_addr_upper, sizeof local_filter_addr_upper - 1); strlcpy(local_filter_addr_lower, local_filter_addr_upper, sizeof local_filter_addr_lower); local_filter = strdup(local_filter_addr_upper); if (!local_filter) { log_error("policy_callback: " "strdup (\"%s\") failed", local_filter_addr_upper); goto bad; } break; case IPSEC_ID_IPV6_RANGE: local_filter_type = "IPv6 range"; my_inet_ntop6(idlocal + ISAKMP_ID_DATA_OFF, local_filter_addr_lower, sizeof local_filter_addr_lower - 1); my_inet_ntop6(idlocal + ISAKMP_ID_DATA_OFF + 16, local_filter_addr_upper, sizeof local_filter_addr_upper - 1); len = strlen(local_filter_addr_upper) + strlen(local_filter_addr_lower) + 2; local_filter = calloc(len, sizeof(char)); if (!local_filter) { log_error("policy_callback: " "calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(local_filter, local_filter_addr_lower, len); strlcat(local_filter, "-", len); strlcat(local_filter, local_filter_addr_upper, len); break; case IPSEC_ID_IPV6_ADDR_SUBNET: { struct in6_addr net, mask; local_filter_type = "IPv6 subnet"; bcopy(idlocal + ISAKMP_ID_DATA_OFF, &net, sizeof(net)); bcopy(idlocal + ISAKMP_ID_DATA_OFF + 16, &mask, sizeof(mask)); for (i = 0; i < 16; i++) net.s6_addr[i] &= mask.s6_addr[i]; my_inet_ntop6((unsigned char *)&net, local_filter_addr_lower, sizeof local_filter_addr_lower - 1); for (i = 0; i < 16; i++) net.s6_addr[i] |= ~mask.s6_addr[i]; my_inet_ntop6((unsigned char *)&net, local_filter_addr_upper, sizeof local_filter_addr_upper - 1); len = strlen(local_filter_addr_upper) + strlen(local_filter_addr_lower) + 2; local_filter = calloc(len, sizeof(char)); if (!local_filter) { log_error("policy_callback: " "calloc (%d, %lu) failed", len, (unsigned long)sizeof(char)); goto bad; } strlcpy(local_filter, local_filter_addr_lower, len); strlcat(local_filter, "-", len); strlcat(local_filter, local_filter_addr_upper, len); break; } case IPSEC_ID_FQDN: local_filter_type = "FQDN"; local_filter = malloc(idlocalsz - ISAKMP_ID_DATA_OFF + 1); if (!local_filter) { log_error("policy_callback: " "malloc (%lu) failed", (unsigned long)idlocalsz - ISAKMP_ID_DATA_OFF + 1); goto bad; } memcpy(local_filter, idlocal + ISAKMP_ID_DATA_OFF, idlocalsz - ISAKMP_ID_DATA_OFF); local_filter[idlocalsz - ISAKMP_ID_DATA_OFF] = '\0'; break; case IPSEC_ID_USER_FQDN: local_filter_type = "User FQDN"; local_filter = malloc(idlocalsz - ISAKMP_ID_DATA_OFF + 1); if (!local_filter) { log_error("policy_callback: " "malloc (%lu) failed", (unsigned long)idlocalsz - ISAKMP_ID_DATA_OFF + 1); goto bad; } memcpy(local_filter, idlocal + ISAKMP_ID_DATA_OFF, idlocalsz - ISAKMP_ID_DATA_OFF); local_filter[idlocalsz - ISAKMP_ID_DATA_OFF] = '\0'; break; case IPSEC_ID_DER_ASN1_DN: local_filter_type = "ASN1 DN"; local_filter = x509_DN_string(idlocal + ISAKMP_ID_DATA_OFF, idlocalsz - ISAKMP_ID_DATA_OFF); if (!local_filter) { LOG_DBG((LOG_POLICY, 50, "policy_callback: failed to decode" " name")); goto bad; } break; case IPSEC_ID_DER_ASN1_GN: /* XXX -- not sure what's in this. */ local_filter_type = "ASN1 GN"; break; case IPSEC_ID_KEY_ID: local_filter_type = "Key ID"; local_filter = calloc(2 * (idlocalsz - ISAKMP_ID_DATA_OFF) + 1, sizeof(char)); if (!local_filter) { log_error("policy_callback: " "calloc (%lu, %lu) failed", 2 * ((unsigned long)idlocalsz - ISAKMP_ID_DATA_OFF) + 1, (unsigned long)sizeof(char)); goto bad; } /* * Does it contain any non-printable * characters ? */ for (i = 0; i < idlocalsz - ISAKMP_ID_DATA_OFF; i++) if (!isprint(*(idlocal + ISAKMP_ID_DATA_OFF + i))) break; if (i >= idlocalsz - ISAKMP_ID_DATA_OFF) { memcpy(local_filter, idlocal + ISAKMP_ID_DATA_OFF, idlocalsz - ISAKMP_ID_DATA_OFF); break; } /* Non-printable characters, convert to hex */ for (i = 0; i < idlocalsz - ISAKMP_ID_DATA_OFF; i++) { local_filter[2 * i] = hextab[*(idlocal + ISAKMP_ID_DATA_OFF) >> 4]; local_filter[2 * i + 1] = hextab[*(idlocal + ISAKMP_ID_DATA_OFF) & 0xF]; } break; default: log_print("policy_callback: " "unknown Local ID type %u", GET_ISAKMP_ID_TYPE(idlocal)); goto bad; } switch (idlocal[ISAKMP_GEN_SZ + 1]) { case IPPROTO_TCP: local_filter_proto = "tcp"; break; case IPPROTO_UDP: local_filter_proto = "udp"; break; #ifdef IPPROTO_ETHERIP case IPPROTO_ETHERIP: local_filter_proto = "etherip"; break; #endif default: snprintf(local_filter_proto_num, sizeof local_filter_proto_num, "%d", idlocal[ISAKMP_GEN_SZ + 1]); local_filter_proto = local_filter_proto_num; break; } snprintf(local_filter_port, sizeof local_filter_port, "%u", decode_16(idlocal + ISAKMP_GEN_SZ + 2)); } else { policy_sa->transport->vtbl->get_src(policy_sa->transport, (struct sockaddr **)&sin); switch (sin->sa_family) { case AF_INET: local_filter_type = "IPv4 address"; break; case AF_INET6: local_filter_type = "IPv6 address"; break; default: log_print("policy_callback: " "unsupported protocol family %d", sin->sa_family); goto bad; } if (sockaddr2text(sin, &addr, 1)) { log_error("policy_callback: " "sockaddr2text failed"); goto bad; } memcpy(local_filter_addr_upper, addr, sizeof local_filter_addr_upper); memcpy(local_filter_addr_lower, addr, sizeof local_filter_addr_lower); free(addr); local_filter = strdup(local_filter_addr_upper); if (!local_filter) { log_error("policy_callback: " "strdup (\"%s\") failed", local_filter_addr_upper); goto bad; } } LOG_DBG((LOG_POLICY, 80, "Policy context (action attributes):")); LOG_DBG((LOG_POLICY, 80, "esp_present == %s", esp_present)); LOG_DBG((LOG_POLICY, 80, "ah_present == %s", ah_present)); LOG_DBG((LOG_POLICY, 80, "comp_present == %s", comp_present)); LOG_DBG((LOG_POLICY, 80, "ah_hash_alg == %s", ah_hash_alg)); LOG_DBG((LOG_POLICY, 80, "esp_enc_alg == %s", esp_enc_alg)); LOG_DBG((LOG_POLICY, 80, "comp_alg == %s", comp_alg)); LOG_DBG((LOG_POLICY, 80, "ah_auth_alg == %s", ah_auth_alg)); LOG_DBG((LOG_POLICY, 80, "esp_auth_alg == %s", esp_auth_alg)); LOG_DBG((LOG_POLICY, 80, "ah_life_seconds == %s", ah_life_seconds)); LOG_DBG((LOG_POLICY, 80, "ah_life_kbytes == %s", ah_life_kbytes)); LOG_DBG((LOG_POLICY, 80, "esp_life_seconds == %s", esp_life_seconds)); LOG_DBG((LOG_POLICY, 80, "esp_life_kbytes == %s", esp_life_kbytes)); LOG_DBG((LOG_POLICY, 80, "comp_life_seconds == %s", comp_life_seconds)); LOG_DBG((LOG_POLICY, 80, "comp_life_kbytes == %s", comp_life_kbytes)); LOG_DBG((LOG_POLICY, 80, "ah_encapsulation == %s", ah_encapsulation)); LOG_DBG((LOG_POLICY, 80, "esp_encapsulation == %s", esp_encapsulation)); LOG_DBG((LOG_POLICY, 80, "comp_encapsulation == %s", comp_encapsulation)); LOG_DBG((LOG_POLICY, 80, "comp_dict_size == %s", comp_dict_size)); LOG_DBG((LOG_POLICY, 80, "comp_private_alg == %s", comp_private_alg)); LOG_DBG((LOG_POLICY, 80, "ah_key_length == %s", ah_key_length)); LOG_DBG((LOG_POLICY, 80, "ah_key_rounds == %s", ah_key_rounds)); LOG_DBG((LOG_POLICY, 80, "esp_key_length == %s", esp_key_length)); LOG_DBG((LOG_POLICY, 80, "esp_key_rounds == %s", esp_key_rounds)); LOG_DBG((LOG_POLICY, 80, "ah_group_desc == %s", ah_group_desc)); LOG_DBG((LOG_POLICY, 80, "esp_group_desc == %s", esp_group_desc)); LOG_DBG((LOG_POLICY, 80, "comp_group_desc == %s", comp_group_desc)); LOG_DBG((LOG_POLICY, 80, "ah_ecn == %s", ah_ecn)); LOG_DBG((LOG_POLICY, 80, "esp_ecn == %s", esp_ecn)); LOG_DBG((LOG_POLICY, 80, "comp_ecn == %s", comp_ecn)); LOG_DBG((LOG_POLICY, 80, "remote_filter_type == %s", remote_filter_type)); LOG_DBG((LOG_POLICY, 80, "remote_filter_addr_upper == %s", remote_filter_addr_upper)); LOG_DBG((LOG_POLICY, 80, "remote_filter_addr_lower == %s", remote_filter_addr_lower)); LOG_DBG((LOG_POLICY, 80, "remote_filter == %s", (remote_filter ? remote_filter : ""))); LOG_DBG((LOG_POLICY, 80, "remote_filter_port == %s", remote_filter_port)); LOG_DBG((LOG_POLICY, 80, "remote_filter_proto == %s", remote_filter_proto)); LOG_DBG((LOG_POLICY, 80, "local_filter_type == %s", local_filter_type)); LOG_DBG((LOG_POLICY, 80, "local_filter_addr_upper == %s", local_filter_addr_upper)); LOG_DBG((LOG_POLICY, 80, "local_filter_addr_lower == %s", local_filter_addr_lower)); LOG_DBG((LOG_POLICY, 80, "local_filter == %s", (local_filter ? local_filter : ""))); LOG_DBG((LOG_POLICY, 80, "local_filter_port == %s", local_filter_port)); LOG_DBG((LOG_POLICY, 80, "local_filter_proto == %s", local_filter_proto)); LOG_DBG((LOG_POLICY, 80, "remote_id_type == %s", remote_id_type)); LOG_DBG((LOG_POLICY, 80, "remote_id_addr_upper == %s", remote_id_addr_upper)); LOG_DBG((LOG_POLICY, 80, "remote_id_addr_lower == %s", remote_id_addr_lower)); LOG_DBG((LOG_POLICY, 80, "remote_id == %s", (remote_id ? remote_id : ""))); LOG_DBG((LOG_POLICY, 80, "remote_id_port == %s", remote_id_port)); LOG_DBG((LOG_POLICY, 80, "remote_id_proto == %s", remote_id_proto)); LOG_DBG((LOG_POLICY, 80, "remote_negotiation_address == %s", remote_ike_address)); LOG_DBG((LOG_POLICY, 80, "local_negotiation_address == %s", local_ike_address)); LOG_DBG((LOG_POLICY, 80, "pfs == %s", pfs)); LOG_DBG((LOG_POLICY, 80, "initiator == %s", initiator)); LOG_DBG((LOG_POLICY, 80, "phase1_group_desc == %s", phase1_group)); /* Unset dirty now. */ dirty = 0; } if (strcmp(name, "phase_1") == 0) return phase_1; if (strcmp(name, "GMTTimeOfDay") == 0) { tt = time((time_t)NULL); strftime(mytimeofday, 14, "%Y%m%d%H%M%S", gmtime(&tt)); return mytimeofday; } if (strcmp(name, "LocalTimeOfDay") == 0) { tt = time((time_t)NULL); strftime(mytimeofday, 14, "%Y%m%d%H%M%S", localtime(&tt)); return mytimeofday; } if (strcmp(name, "initiator") == 0) return initiator; if (strcmp(name, "pfs") == 0) return pfs; if (strcmp(name, "app_domain") == 0) return "IPsec policy"; if (strcmp(name, "doi") == 0) return "ipsec"; if (strcmp(name, "esp_present") == 0) return esp_present; if (strcmp(name, "ah_present") == 0) return ah_present; if (strcmp(name, "comp_present") == 0) return comp_present; if (strcmp(name, "ah_hash_alg") == 0) return ah_hash_alg; if (strcmp(name, "ah_auth_alg") == 0) return ah_auth_alg; if (strcmp(name, "esp_auth_alg") == 0) return esp_auth_alg; if (strcmp(name, "esp_enc_alg") == 0) return esp_enc_alg; if (strcmp(name, "comp_alg") == 0) return comp_alg; if (strcmp(name, "ah_life_kbytes") == 0) return ah_life_kbytes; if (strcmp(name, "ah_life_seconds") == 0) return ah_life_seconds; if (strcmp(name, "esp_life_kbytes") == 0) return esp_life_kbytes; if (strcmp(name, "esp_life_seconds") == 0) return esp_life_seconds; if (strcmp(name, "comp_life_kbytes") == 0) return comp_life_kbytes; if (strcmp(name, "comp_life_seconds") == 0) return comp_life_seconds; if (strcmp(name, "ah_encapsulation") == 0) return ah_encapsulation; if (strcmp(name, "esp_encapsulation") == 0) return esp_encapsulation; if (strcmp(name, "comp_encapsulation") == 0) return comp_encapsulation; if (strcmp(name, "ah_key_length") == 0) return ah_key_length; if (strcmp(name, "ah_key_rounds") == 0) return ah_key_rounds; if (strcmp(name, "esp_key_length") == 0) return esp_key_length; if (strcmp(name, "esp_key_rounds") == 0) return esp_key_rounds; if (strcmp(name, "comp_dict_size") == 0) return comp_dict_size; if (strcmp(name, "comp_private_alg") == 0) return comp_private_alg; if (strcmp(name, "remote_filter_type") == 0) return remote_filter_type; if (strcmp(name, "remote_filter") == 0) return (remote_filter ? remote_filter : ""); if (strcmp(name, "remote_filter_addr_upper") == 0) return remote_filter_addr_upper; if (strcmp(name, "remote_filter_addr_lower") == 0) return remote_filter_addr_lower; if (strcmp(name, "remote_filter_port") == 0) return remote_filter_port; if (strcmp(name, "remote_filter_proto") == 0) return remote_filter_proto; if (strcmp(name, "local_filter_type") == 0) return local_filter_type; if (strcmp(name, "local_filter") == 0) return (local_filter ? local_filter : ""); if (strcmp(name, "local_filter_addr_upper") == 0) return local_filter_addr_upper; if (strcmp(name, "local_filter_addr_lower") == 0) return local_filter_addr_lower; if (strcmp(name, "local_filter_port") == 0) return local_filter_port; if (strcmp(name, "local_filter_proto") == 0) return local_filter_proto; if (strcmp(name, "remote_ike_address") == 0) return remote_ike_address; if (strcmp(name, "remote_negotiation_address") == 0) return remote_ike_address; if (strcmp(name, "local_ike_address") == 0) return local_ike_address; if (strcmp(name, "local_negotiation_address") == 0) return local_ike_address; if (strcmp(name, "remote_id_type") == 0) return remote_id_type; if (strcmp(name, "remote_id") == 0) return (remote_id ? remote_id : ""); if (strcmp(name, "remote_id_addr_upper") == 0) return remote_id_addr_upper; if (strcmp(name, "remote_id_addr_lower") == 0) return remote_id_addr_lower; if (strcmp(name, "remote_id_port") == 0) return remote_id_port; if (strcmp(name, "remote_id_proto") == 0) return remote_id_proto; if (strcmp(name, "phase1_group_desc") == 0) return phase1_group; if (strcmp(name, "esp_group_desc") == 0) return esp_group_desc; if (strcmp(name, "ah_group_desc") == 0) return ah_group_desc; if (strcmp(name, "comp_group_desc") == 0) return comp_group_desc; if (strcmp(name, "comp_ecn") == 0) return comp_ecn; if (strcmp(name, "ah_ecn") == 0) return ah_ecn; if (strcmp(name, "esp_ecn") == 0) return esp_ecn; return ""; bad: policy_callback(KEYNOTE_CALLBACK_INITIALIZE); return ""; } void policy_init(void) { char *ptr, *policy_file; char **asserts; size_t sz, len; int fd, i; LOG_DBG((LOG_POLICY, 30, "policy_init: initializing")); /* Do we want to use the policy modules? */ if (ignore_policy || strncmp("yes", conf_get_str("General", "Use-Keynote"), 3)) return; /* Get policy file from configuration. */ policy_file = conf_get_str("General", "Policy-file"); if (!policy_file) policy_file = CONF_DFLT_POLICY_FILE; /* Open policy file. */ fd = monitor_open(policy_file, O_RDONLY, 0); if (fd == -1) log_fatal("policy_init: open (\"%s\", O_RDONLY) failed", policy_file); /* Check file modes and collect file size */ if (check_file_secrecy_fd(fd, policy_file, &sz)) { close(fd); log_fatal("policy_init: cannot read %s", policy_file); } /* Allocate memory to keep policies. */ ptr = calloc(sz + 1, sizeof(char)); if (!ptr) log_fatal("policy_init: calloc (%lu, %lu) failed", (unsigned long)sz + 1, (unsigned long)sizeof(char)); /* Just in case there are short reads... */ for (len = 0; len < sz; len += i) { i = read(fd, ptr + len, sz - len); if (i == -1) log_fatal("policy_init: read (%d, %p, %lu) failed", fd, ptr + len, (unsigned long)(sz - len)); } /* We're done with this. */ close(fd); /* Parse buffer, break up into individual policies. */ asserts = kn_read_asserts(ptr, sz, &i); /* Begone! */ free(ptr); if (asserts == (char **)NULL) log_print("policy_init: all policies flushed"); /* Cleanup */ if (policy_asserts) { for (fd = 0; fd < policy_asserts_num; fd++) if (policy_asserts && policy_asserts[fd]) free(policy_asserts[fd]); free(policy_asserts); } policy_asserts = asserts; policy_asserts_num = i; } /* Nothing needed for initialization */ int keynote_cert_init(void) { return 1; } /* Just copy and return. */ void * keynote_cert_get(u_int8_t *data, u_int32_t len) { char *foo = malloc(len + 1); if (foo == NULL) return NULL; memcpy(foo, data, len); foo[len] = '\0'; return foo; } /* * We just verify the signature on the credentials. * On signature failure, just drop the whole payload. */ int keynote_cert_validate(void *scert) { char **foo; int num, i; if (scert == NULL) return 0; foo = kn_read_asserts((char *)scert, strlen((char *)scert), &num); if (foo == NULL) return 0; for (i = 0; i < num; i++) { if (kn_verify_assertion(scert, strlen((char *)scert)) != SIGRESULT_TRUE) { for (; i < num; i++) free(foo[i]); free(foo); return 0; } free(foo[i]); } free(foo); return 1; } /* Add received credentials. */ int keynote_cert_insert(int sid, void *scert) { char **foo; int num; if (scert == NULL) return 0; foo = kn_read_asserts((char *)scert, strlen((char *)scert), &num); if (foo == NULL) return 0; while (num--) kn_add_assertion(sid, foo[num], strlen(foo[num]), 0); return 1; } /* Just regular memory free. */ void keynote_cert_free(void *cert) { free(cert); } /* Verify that the key given to us is valid. */ int keynote_certreq_validate(u_int8_t *data, u_int32_t len) { struct keynote_deckey dc; int err = 1; char *dat; dat = calloc(len + 1, sizeof(char)); if (!dat) { log_error("keynote_certreq_validate: calloc (%d, %lu) failed", len + 1, (unsigned long)sizeof(char)); return 0; } memcpy(dat, data, len); if (kn_decode_key(&dc, dat, KEYNOTE_PUBLIC_KEY) != 0) err = 0; else kn_free_key(&dc); free(dat); return err; } /* Beats me what we should be doing with this. */ void * keynote_certreq_decode(u_int8_t *data, u_int32_t len) { /* XXX */ return NULL; } void keynote_free_aca(void *blob) { /* XXX */ } int keynote_cert_obtain(u_int8_t *id, size_t id_len, void *data, u_int8_t **cert, u_int32_t *certlen) { char *dirname, *file, *addr_str; struct stat sb; size_t size; int idtype, fd, len; if (!id) { log_print("keynote_cert_obtain: ID is missing"); return 0; } /* Get type of ID. */ idtype = id[0]; id += ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; id_len -= ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; dirname = conf_get_str("KeyNote", "Credential-directory"); if (!dirname) { LOG_DBG((LOG_POLICY, 30, "keynote_cert_obtain: no Credential-directory")); return 0; } len = strlen(dirname) + strlen(CREDENTIAL_FILE) + 3; switch (idtype) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: util_ntoa(&addr_str, idtype == IPSEC_ID_IPV4_ADDR ? AF_INET : AF_INET6, id); if (addr_str == 0) return 0; file = calloc(len + strlen(addr_str), sizeof(char)); if (file == NULL) { log_error("keynote_cert_obtain: failed to allocate " "%lu bytes", (unsigned long)len + strlen(addr_str)); free(addr_str); return 0; } snprintf(file, len + strlen(addr_str), "%s/%s/%s", dirname, addr_str, CREDENTIAL_FILE); free(addr_str); break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: { file = calloc(len + id_len, sizeof(char)); if (file == NULL) { log_error("keynote_cert_obtain: " "failed to allocate %lu bytes", (unsigned long)len + id_len); return 0; } snprintf(file, len + id_len, "%s/", dirname); memcpy(file + strlen(dirname) + 1, id, id_len); snprintf(file + strlen(dirname) + 1 + id_len, len - strlen(dirname) - 1, "/%s", CREDENTIAL_FILE); break; } default: return 0; } fd = monitor_open(file, O_RDONLY, 0); if (fd < 0) { LOG_DBG((LOG_POLICY, 30, "keynote_cert_obtain: " "failed to open \"%s\"", file)); free(file); return 0; } if (fstat(fd, &sb) < 0) { LOG_DBG((LOG_POLICY, 30, "keynote_cert_obtain: " "failed to stat \"%s\"", file)); free(file); close(fd); return 0; } size = (size_t)sb.st_size; *cert = calloc(size + 1, sizeof(char)); if (*cert == NULL) { log_error("keynote_cert_obtain: failed to allocate %lu bytes", (unsigned long)size); free(file); return 0; } if (read(fd, *cert, size) != (int)size) { LOG_DBG((LOG_POLICY, 30, "keynote_cert_obtain: " "failed to read %lu bytes from \"%s\"", (unsigned long)size, file)); free(file); close(fd); return 0; } close(fd); free(file); *certlen = size; return 1; } /* This should never be called. */ int keynote_cert_get_subjects(void *scert, int *n, u_int8_t ***id, u_int32_t **id_len) { return 0; } /* Get the authorizer key. */ int keynote_cert_get_key(void *scert, void *keyp) { struct keynote_keylist *kl; int sid, kid, num; char **foo; foo = kn_read_asserts((char *)scert, strlen((char *)scert), &num); if (foo == NULL || num == 0) { log_print("keynote_cert_get_key: " "failed to decompose credentials"); return 0; } kid = kn_init(); if (kid == -1) { log_print("keynote_cert_get_key: " "failed to initialize new policy session"); while (num--) free(foo[num]); free(foo); return 0; } sid = kn_add_assertion(kid, foo[num - 1], strlen(foo[num - 1]), 0); while (num--) free(foo[num]); free(foo); if (sid == -1) { log_print("keynote_cert_get_key: failed to add assertion"); kn_close(kid); return 0; } *(RSA **)keyp = NULL; kl = kn_get_licensees(kid, sid); while (kl) { if (kl->key_alg == KEYNOTE_ALGORITHM_RSA || kl->key_alg == KEYNOTE_ALGORITHM_X509) { *(RSA **)keyp = RSAPublicKey_dup(kl->key_key); break; } kl = kl->key_next; } kn_remove_assertion(kid, sid); kn_close(kid); return *(RSA **)keyp == NULL ? 0 : 1; } void * keynote_cert_dup(void *cert) { return strdup((char *)cert); } void keynote_serialize(void *cert, u_int8_t **data, u_int32_t *datalen) { *datalen = strlen((char *)cert) + 1; *data = (u_int8_t *)strdup(cert); /* i.e an extra character at * the end... */ if (*data == NULL) log_error("keynote_serialize: malloc (%d) failed", *datalen); } /* From cert to printable */ char * keynote_printable(void *cert) { return strdup((char *)cert); } /* From printable to cert */ void * keynote_from_printable(char *cert) { return strdup(cert); } isakmpd-20041012.orig/dnssec.h0000644000175000017500000000335010133045740016206 0ustar jdivejdive00000000000000/* $OpenBSD: dnssec.h,v 1.7 2004/05/14 08:42:56 hshoexer Exp $ */ /* * Copyright (c) 2001 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. * * 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 "libcrypto.h" #include "message.h" void *dns_get_key(int, struct message *, int *); int dns_RSA_dns_to_x509(u_int8_t *, int, RSA **); #ifndef DNS_KEYALG_RSA #define DNS_KEYALG_RSA 1 #endif #ifndef DNS_KEYPROTO_IPSEC #define DNS_KEYPROTO_IPSEC 4 #endif #ifndef DNS_KEYALG_RSA #define DNS_KEYALG_RSA 1 #endif #ifndef DNS_KEYPROTO_IPSEC #define DNS_KEYPROTO_IPSEC 4 #endif isakmpd-20041012.orig/isakmpd.80000644000175000017500000003771110133045740016307 0ustar jdivejdive00000000000000.\" $OpenBSD: isakmpd.8,v 1.65 2004/07/08 10:37:12 jmc Exp $ .\" $EOM: isakmpd.8,v 1.23 2000/05/02 00:30:23 niklas Exp $ .\" .\" Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. .\" All rights reserved. .\" Copyright (c) 1999 Angelos D. Keromytis. All rights reserved. .\" Copyright (c) 2001, 2002 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. .\" .\" 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. .\" .\" This code was written under funding by Ericsson Radio Systems. .\" .\" Manual page, using -mandoc macros .\" .Dd August 07, 2002 .Dt ISAKMPD 8 .Os .Sh NAME .Nm isakmpd .Nd ISAKMP/Oakley a.k.a. IKE key management daemon .Sh SYNOPSIS .Nm isakmpd .Bk -words .Op Fl 4 .Op Fl 6 .Op Fl c Ar config-file .Op Fl a .Op Fl d .Op Fl D Ar class=level .Op Fl f Ar fifo .Op Fl i Ar pid-file .Op Fl n .Op Fl p Ar listen-port .Op Fl P Ar local-port .Op Fl K .Op Fl L .Op Fl l Ar packetlog-file .Op Fl r Ar seed .Op Fl R Ar report-file .Op Fl v .Ek .Sh DESCRIPTION The .Nm daemon establishes security associations for encrypted and/or authenticated network traffic. At this moment, and probably forever, this means .Xr ipsec 4 traffic. .Pp The way .Nm goes about its work is by maintaining an internal configuration as well as a policy database which describes what kinds of SAs to negotiate, and by listening for different events that trigger these negotiations. The events that control .Nm consist of negotiation initiations from a remote party, user input via a FIFO or by signals, upcalls from the kernel via a .Dv PF_KEY socket, and lastly by scheduled events triggered by timers running out. .Pp Most uses of .Nm will be to implement so called "virtual private networks" or VPNs for short. The .Xr vpn 8 manual page describes how to set up .Nm for a simple VPN. For other uses, some more knowledge of IKE as a protocol is required. One source of information are the RFCs mentioned below. .Pp On startup .Nm forks into two processes for privilege separation. The unprivileged child jails itself with .Xr chroot 8 to .Pa /var/empty . The privileged process communicates with the child, reads configuration files and PKI information and binds to privileged ports on its behalf. See .Sx CAVEATS section below. .Pp The options are as follows: .Bl -tag -width Ds .It Fl 4 | Fl 6 These options control what address family .Pf ( Dv AF_INET and/or .Dv AF_INET6 ) .Nm will use. The default is to use both IPv4 and IPv6. .It Fl a If given, .Nm does not set up flows automatically. This is useful when flows are configured with .Xr ipsecadm 4 or by other programs like .Xr bgpd 8 . Thus .Nm only takes care of the SA establishment. .It Fl c Ar config-file If given, the .Fl c option specifies an alternate configuration file instead of .Pa /etc/isakmpd/isakmpd.conf . As this file may contain sensitive information, it must be readable only by the user running the daemon. .Nm will reread the configuration file when sent a .Dv SIGHUP signal. .It Fl d The .Fl d option is used to make the daemon run in the foreground, logging to stderr. .It Xo Fl D .Ar class Ns = Ns Ar level .Xc Debugging class. It's possible to specify this argument many times. It takes a parameter of the form .Ar class Ns = Ns Ar level , where both .Ar class and .Ar level are numbers. .Ar class denotes a debugging class, and .Ar level the level you want that debugging class to limit debug printouts at (i.e., all debug printouts above the level specified will not output anything). If .Ar class is set to .Sq A , then all debugging classes are set to the specified level. .Pp Valid values for .Ar class are as follows: .Pp .Bl -tag -width 2n -compact -offset indent .It 0 Misc .It 1 Transport .It 2 Message .It 3 Crypto .It 4 Timer .It 5 Sysdep .It 6 SA .It 7 Exchange .It 8 Negotiation .It 9 Policy .It 10 FIFO user interface .It A All .El .Pp Currently used values for .Ar level are 0 to 99. .It Fl f Ar fifo The .Fl f option specifies the .Tn FIFO (a.k.a. named pipe) where the daemon listens for user requests. If the path given is a dash .Pq Sq \&- , .Nm will listen to stdin instead. .It Fl i Ar pid-file By default the PID of the daemon process will be written to .Pa /var/run/isakmpd.pid . This path can be overridden by specifying another one as the argument to the .Fl i option. .It Fl n When the .Fl n option is given, the kernel will not take part in the negotiations. This is a non-destructive mode, so to speak, in that it won't alter any SAs in the IPsec stack. .It Fl p Ar listen-port The .Fl p option specifies the listen port the daemon will bind to. .It Fl P Ar local-port On the other hand, the port specified to capital .Fl P will be what the daemon binds its local end to when acting as initiator. .It Fl K When this option is given, .Nm does not read the policy configuration file and no .Xr keynote 4 policy check is accomplished. This option can be used when policies for flows and SA establishment are arranged by other programs like .Xr ipsecadm 8 or .Xr bgpd 8 . .It Fl L Enable IKE packet capture. When this option is given, .Nm will capture to file an unencrypted copy of the negotiation packets it is sending and receiving. This file can later be read by .Xr tcpdump 8 and other utilities using .Xr pcap 3 . .It Fl l Ar packetlog-file As option .Fl L above, but capture to a specified file. .It Fl r Ar seed If given, a deterministic random number sequence will be used internally. This is useful for setting up regression tests. .It Fl R Ar report-file When you signal .Nm a .Dv SIGUSR1 , it will report its internal state to a report file, normally .Pa /var/run/isakmpd.report , but this can be changed by feeding the file name as an argument to the .Fl R flag. .It Fl v Enables verbose logging. Normally, .Nm is silent and outputs only messages when a warning or an error occurs. With verbose logging .Nm reports successful completion of phase 1 (Main and Aggressive) and phase 2 (Quick) exchanges (Information and Transaction exchanges do not generate any additional status information). .El .Ss Setting up an IKE public key infrastructure (a.k.a. PKI) In order to use public key based authentication, there has to be an infrastructure managing the key signing. Either there is an already existing PKI .Nm should take part in, or there will be a need to set one up. In the former case, what is needed to be done varies depending on the actual Certificate Authority used, and is therefore not covered here, other than mentioning that .Xr openssl 1 needs to be used to create a certificate signing request that the CA understands. The latter case, however, is described here: .Bl -enum .It Create your own CA as root. .Bd -literal # openssl genrsa -out /etc/ssl/private/ca.key 1024 # openssl req -new -key /etc/ssl/private/ca.key \e -out /etc/ssl/private/ca.csr .Ed .Pp You are then asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name (DN). There are quite a few fields but you can leave some blank. For some fields there will be a default value; if you enter .Sq \&. , the field will be left blank. .Bd -literal # openssl x509 -req -days 365 -in /etc/ssl/private/ca.csr \e -signkey /etc/ssl/private/ca.key \e -extfile /etc/ssl/x509v3.cnf -extensions x509v3_CA \e -out /etc/ssl/ca.crt .Ed .Pp .It Create keys and certificates for your IKE peers. This step as well as the next one, needs to be done for every peer. Furthermore the last step will need to be done once for each ID you want the peer to have. The 10.0.0.1 below symbolizes that ID, in this case an IPv4 ID, and should be changed for each invocation. You will be asked for a DN for each run. Encoding the ID in the common name is recommended, as it should be unique. .Bd -literal # openssl genrsa -out /etc/isakmpd/private/local.key 1024 # openssl req -new -key /etc/isakmpd/private/local.key \e -out /etc/isakmpd/private/10.0.0.1.csr .Ed .Pp Now take these certificate signing requests to your CA and process them like below. You have to add a subjectAltName extension field to the certificate in order to make it usable by .Nm isakmpd . There are two possible ways to add the extensions to the certificate. Either you have to run .Xr certpatch 8 or you have to make use of an OpenSSL configuration file, for example .Pa /etc/ssl/x509v3.cnf . Replace 10.0.0.1 with the IP-address which .Nm will use as the certificate identity. .Pp To use .Xr certpatch 8 , do the following .Bd -literal # openssl x509 -req -days 365 -in 10.0.0.1.csr -CA /etc/ssl/ca.crt \e -CAkey /etc/ssl/private/ca.key -CAcreateserial \e -out 10.0.0.1.crt # certpatch -i 10.0.0.1 -k /etc/ssl/private/ca.key \e 10.0.0.1.crt 10.0.0.1.crt .Ed .Pp Otherwise do .Bd -literal # setenv CERTIP 10.0.0.1 # openssl x509 -req -days 365 -in 10.0.0.1.csr -CA /etc/ssl/ca.crt \e -CAkey /etc/ssl/private/ca.key -CAcreateserial \e -extfile /etc/ssl/x509v3.cnf -extensions x509v3_IPAddr \e -out 10.0.0.1.crt .Ed .Pp For a FQDN certificate, do .Bd -literal # setenv CERTFQDN somehost.somedomain # openssl x509 -req -days 365 -in somehost.somedomain.csr \e -CA /etc/ssl/ca.crt -CAkey /etc/ssl/private/ca.key \e -CAcreateserial \e -extfile /etc/ssl/x509v3.cnf -extensions x509v3_FQDN \e -out somehost.somedomain.crt .Ed .Pp or with .Xr certpatch 8 .Bd -literal # certpatch -t fqdn -i somehost.somedomain \e -k /etc/ssl/private/ca.key \e somehost.somedomain.crt somehost.somedomain.crt .Ed .Pp (This assumes the previous steps were used to create a request for somehost.somedomain instead of 10.0.0.1) .Pp Put the certificate (the file ending in .crt) in .Pa /etc/isakmpd/certs/ on your local system. Also carry over the CA cert .Pa /etc/ssl/ca.crt and put it in .Pa /etc/isakmpd/ca/ . .El .Pp To revoke certificates, create a Certificate Revocation List (CRL) file and install it in the .Pa /etc/isakmpd/crls/ directory. See .Xr openssl 1 and the .Sq crl subcommand for more info. .Pp It is also possible to store trusted public keys to make them directly usable by .Nm isakmpd . The keys should be saved in PEM format (see .Xr openssl 1 ) and named and stored after this easy formula: .Bl -tag -width for_ufqdn_identities .It For IPv4 identities /etc/isakmpd/pubkeys/ipv4/A.B.C.D .It For IPv6 identities /etc/isakmpd/pubkeys/ipv6/abcd:abcd::ab:bc .It For FQDN identities /etc/isakmpd/pubkeys/fqdn/foo.bar.org .It For UFQDN identities /etc/isakmpd/pubkeys/ufqdn/user@foo.bar.org .El .Ss The FIFO user interface When .Nm starts, it creates a FIFO (named pipe) where it listens for user requests. All commands start with a single letter, followed by command-specific options. Available commands are: .Bl -tag -width Ds -compact .Pp .It Ic "c " Start the named connection, if stopped or inactive. .Pp .It Ic "C set [section]:tag=value" .It Ic "C set [section]:tag=value force" .It Ic "C add [section]:tag=value" .It Ic "C rm [section]:tag" .It Ic "C rms [section]" Update the running .Nm configuration atomically. .Sq set sets a configuration value consisting of a section, tag and value triplet. .Sq set will fail if the configuration already contains a section with the named tag; use the .Sq force option to change this behaviour. .Sq add appends a configuration value to the named configuration list tag. .Sq rm removes a tag in a section. .Sq rms removes an entire section. .Pp NOTE: Sending isakmpd a SIGHUP or an "R" through the FIFO will void any updates done to the configuration. .Pp .It Ic "C get [section]:tag" Get the configuration value of the specified section and tag. The result is stored in .Pa /var/run/isakmpd.result . .Pp .It Ic "d " Delete the specified SA from the system. Specify as "-" to match a Phase 1 SA. .Pp .It Ic "D " .It Ic "D A " .It Ic "D T" Set debug class to level . If is specified as "A", the level applies to all debug classes. "D T" toggles all debug classes to level zero. Another "D T" command will toggle them back to the earlier levels. .Pp .It Ic "p on[=]" .It Ic "p off" Enable or disable cleartext IKE packet capture. When enabling, optionally specify which file .Nm should capture the packets to. .Pp .It Ic "Q" Cleanly shutdown the daemon, as when sent a .Dv SIGTERM signal. .Pp .It Ic "r" Report .Nm internal state to a file. See .Fl R option. Same as when sent a .Dv SIGUSR1 signal. .Pp .It Ic "R" Reinitialize .Nm isakmpd , as when sent a .Dv SIGHUP signal. .Pp .It Ic "S" Report information on all known SAs to the .Pa /var/run/isakmpd.result file. .Pp .It Ic "t " Tear down the named connection, if active. .Pp .It Ic "T" Tear down all active connections. .El .Sh FILES .Bl -tag -width /etc/isakmpd/private/local. .It Pa /etc/isakmpd/ca/ The directory where CA certificates can be found. .It Pa /etc/isakmpd/certs/ The directory where IKE certificates can be found, both the local certificate(s) and those of the peers, if a choice to have them kept permanently has been made. .It Pa /etc/isakmpd/crls/ The directory where CRLs can be found. .It Pa /etc/isakmpd/isakmpd.conf The configuration file. As this file can contain sensitive information it must not be readable by anyone but the user running .Nm isakmpd . .It Pa /etc/isakmpd/isakmpd.policy The keynote policy configuration file. The same mode requirements as .Nm isakmpd.conf . .It Pa /etc/isakmpd/private/local.key A local private key for certificate based authentication. There has to be a certificate for this key in the certificate directory mentioned above. The same mode requirements as .Nm isakmpd.conf . .It Pa /etc/isakmpd/pubkeys/ Directory in which trusted public keys can be kept. The keys must be named in the fashion described above. .It Pa /var/run/isakmpd.pid The PID of the current daemon. .It Pa /var/run/isakmpd.fifo The FIFO used to manually control .Nm isakmpd . .It Pa /var/run/isakmpd.pcap The default IKE packet capture file. .It Pa /var/run/isakmpd.report The report file written when .Dv SIGUSR1 is received. .It Pa /var/run/isakmpd.result The report file written when the .Sq S or .Sq "C get" command is issued in the command FIFO. .It Pa /usr/share/ipsec/isakmpd/ A directory containing some sample .Nm and keynote policy configuration files. .El .Sh SEE ALSO .Xr openssl 1 , .Xr getnameinfo 3 , .Xr pcap 3 , .Xr ipsec 4 , .Xr isakmpd.conf 5 , .Xr isakmpd.policy 5 , .Xr ssl 8 , .Xr tcpdump 8 , .Xr vpn 8 .Sh HISTORY The ISAKMP/Oakley key management protocol is described in the RFCs .%T RFC 2407 , .%T RFC 2408 and .%T RFC 2409 . This implementation was done 1998 by Niklas Hallqvist and Niels Provos, sponsored by Ericsson Radio Systems. .Sh CAVEATS When storing a trusted public key for an IPv6 identity, the .Em most efficient form of address representation, i.e "::" instead of ":0:0:0:", must be used or the matching will fail. .Nm uses the output from .Xr getnameinfo 3 for the address-to-name translation. The privileged process only allows binding to the default port 500 or unprivileged ports (>1024). It is not possible to change the interfaces .Nm listens on without a restart. .Sh BUGS The .Fl P flag does not do what we document, rather it does nothing. isakmpd-20041012.orig/isakmp_doi.c0000644000175000017500000001565310133045740017052 0ustar jdivejdive00000000000000/* $OpenBSD: isakmp_doi.c,v 1.22 2004/06/20 17:17:35 ho Exp $ */ /* $EOM: isakmp_doi.c,v 1.42 2000/09/12 16:29:41 ho Exp $ */ /* * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * XXX This DOI is very fuzzily defined, and should perhaps be short-circuited * to the IPsec DOI instead. At the moment I will have it as its own DOI, * as the ISAKMP architecture seems to imply it should be done like this. */ #include #include "sysdep.h" #include "doi.h" #include "exchange.h" #include "isakmp.h" #include "isakmp_doi.h" #include "ipsec.h" #include "log.h" #include "message.h" #include "sa.h" #include "util.h" #ifdef USE_DEBUG static int isakmp_debug_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); #endif static void isakmp_finalize_exchange(struct message *); static struct keystate *isakmp_get_keystate(struct message *); static int isakmp_initiator(struct message *); static int isakmp_responder(struct message *); static void isakmp_setup_situation(u_int8_t *); static size_t isakmp_situation_size(void); static u_int8_t isakmp_spi_size(u_int8_t); static int isakmp_validate_attribute(u_int16_t, u_int8_t *, u_int16_t, void *); static int isakmp_validate_exchange(u_int8_t); static int isakmp_validate_id_information(u_int8_t, u_int8_t *, u_int8_t *, size_t, struct exchange *); static int isakmp_validate_key_information(u_int8_t *, size_t); static int isakmp_validate_notification(u_int16_t); static int isakmp_validate_proto(u_int8_t); static int isakmp_validate_situation(u_int8_t *, size_t *, size_t); static int isakmp_validate_transform_id(u_int8_t, u_int8_t); static struct doi isakmp_doi = { {0}, ISAKMP_DOI_ISAKMP, 0, 0, 0, #ifdef USE_DEBUG isakmp_debug_attribute, #endif 0, /* delete_spi not needed. */ 0, /* exchange_script not needed. */ isakmp_finalize_exchange, 0, /* free_exchange_data not needed. */ 0, /* free_proto_data not needed. */ 0, /* free_sa_data not needed. */ isakmp_get_keystate, 0, /* get_spi not needed. */ 0, /* handle_leftover_payload not needed. */ 0, /* informational_post_hook not needed. */ 0, /* informational_pre_hook not needed. */ 0, /* XXX need maybe be filled-in. */ 0, /* proto_init not needed. */ isakmp_setup_situation, isakmp_situation_size, isakmp_spi_size, isakmp_validate_attribute, isakmp_validate_exchange, isakmp_validate_id_information, isakmp_validate_key_information, isakmp_validate_notification, isakmp_validate_proto, isakmp_validate_situation, isakmp_validate_transform_id, isakmp_initiator, isakmp_responder, #ifdef USE_DEBUG ipsec_decode_ids #endif }; /* Requires doi_init to already have been called. */ void isakmp_doi_init(void) { doi_register(&isakmp_doi); } #ifdef USE_DEBUG int isakmp_debug_attribute(u_int16_t type, u_int8_t *value, u_int16_t len, void *vmsg) { /* XXX Not implemented yet. */ return 0; } #endif /* USE_DEBUG */ static void isakmp_finalize_exchange(struct message *msg) { } static struct keystate * isakmp_get_keystate(struct message *msg) { return 0; } static void isakmp_setup_situation(u_int8_t *buf) { /* Nothing to do. */ } static size_t isakmp_situation_size(void) { return 0; } static u_int8_t isakmp_spi_size(u_int8_t proto) { /* One way to specify ISAKMP SPIs is to say they're zero-sized. */ return 0; } static int isakmp_validate_attribute(u_int16_t type, u_int8_t *value, u_int16_t len, void *vmsg) { /* XXX Not implemented yet. */ return -1; } static int isakmp_validate_exchange(u_int8_t exch) { /* If we get here the exchange is invalid. */ return -1; } static int isakmp_validate_id_information(u_int8_t type, u_int8_t *extra, u_int8_t *buf, size_t sz, struct exchange *exchange) { return zero_test(extra, ISAKMP_ID_DOI_DATA_LEN); } static int isakmp_validate_key_information(u_int8_t *buf, size_t sz) { /* Nothing to do. */ return 0; } static int isakmp_validate_notification(u_int16_t type) { /* If we get here the message type is invalid. */ return -1; } static int isakmp_validate_proto(u_int8_t proto) { /* If we get here the protocol is invalid. */ return -1; } static int isakmp_validate_situation(u_int8_t *buf, size_t *sz, size_t len) { /* There are no situations in the ISAKMP DOI. */ *sz = 0; return 0; } static int isakmp_validate_transform_id(u_int8_t proto, u_int8_t transform_id) { /* XXX Not yet implemented. */ return -1; } static int isakmp_initiator(struct message *msg) { if (msg->exchange->type != ISAKMP_EXCH_INFO) { log_print("isakmp_initiator: unsupported exchange type %d " "in phase %d", msg->exchange->type, msg->exchange->phase); return -1; } return message_send_info(msg); } static int isakmp_responder(struct message *msg) { struct payload *p; switch (msg->exchange->type) { case ISAKMP_EXCH_INFO: for (p = payload_first(msg, ISAKMP_PAYLOAD_NOTIFY); p; p = TAILQ_NEXT(p, link)) { LOG_DBG((LOG_EXCHANGE, 10, "isakmp_responder: " "got NOTIFY of type %s, ignoring", constant_name(isakmp_notify_cst, GET_ISAKMP_NOTIFY_MSG_TYPE(p->p)))); p->flags |= PL_MARK; } for (p = payload_first(msg, ISAKMP_PAYLOAD_DELETE); p; p = TAILQ_NEXT(p, link)) { LOG_DBG((LOG_EXCHANGE, 10, "isakmp_responder: got DELETE, ignoring")); p->flags |= PL_MARK; } return 0; #ifdef USE_ISAKMP_CFG case ISAKMP_EXCH_TRANSACTION: /* return 0 isakmp_cfg_responder (msg); */ #endif /* USE_ISAKMP_CFG */ default: /* XXX So far we don't accept any proposals. */ if (payload_first(msg, ISAKMP_PAYLOAD_SA)) { message_drop(msg, ISAKMP_NOTIFY_NO_PROPOSAL_CHOSEN, 0, 1, 0); return -1; } } return 0; } isakmpd-20041012.orig/init.h0000644000175000017500000000314510133045740015674 0ustar jdivejdive00000000000000/* $OpenBSD: init.h,v 1.6 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: init.h,v 1.2 1998/07/07 23:36:00 niklas Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _INIT_H_ #define _INIT_H_ extern void init(void); extern void reinit(void); #endif /* _INIT_H_ */ isakmpd-20041012.orig/constants.h0000644000175000017500000000375010133045740016747 0ustar jdivejdive00000000000000/* $OpenBSD: constants.h,v 1.6 2004/04/15 18:39:25 deraadt Exp $ */ /* $EOM: constants.h,v 1.5 1998/11/20 07:17:01 niklas Exp $ */ /* * Copyright (c) 1998 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _CONSTANTS_H_ #define _CONSTANTS_H_ struct constant_map { int value; char *name; struct constant_map *link; }; struct constant_map *constant_link_lookup(struct constant_map *, int); extern char *constant_lookup(struct constant_map *, int); extern char *constant_name(struct constant_map *, int); extern char *constant_name_maps(struct constant_map **, int); extern int constant_value(struct constant_map *, char *); #endif /* _CONSTANTS_H_ */ isakmpd-20041012.orig/CVS/0000755000175000017500000000000010133045751015212 5ustar jdivejdive00000000000000isakmpd-20041012.orig/crypto.c0000644000175000017500000002463610133045740016254 0ustar jdivejdive00000000000000/* $OpenBSD: crypto.c,v 1.22 2004/06/14 09:55:41 ho Exp $ */ /* $EOM: crypto.c,v 1.32 2000/03/07 20:08:51 niklas Exp $ */ /* * Copyright (c) 1998 Niels Provos. All rights reserved. * Copyright (c) 1999, 2000 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include "sysdep.h" #include "crypto.h" #include "log.h" enum cryptoerr des1_init(struct keystate *, u_int8_t *, u_int16_t); enum cryptoerr des3_init(struct keystate *, u_int8_t *, u_int16_t); enum cryptoerr blf_init(struct keystate *, u_int8_t *, u_int16_t); enum cryptoerr cast_init(struct keystate *, u_int8_t *, u_int16_t); enum cryptoerr aes_init(struct keystate *, u_int8_t *, u_int16_t); void des1_encrypt(struct keystate *, u_int8_t *, u_int16_t); void des1_decrypt(struct keystate *, u_int8_t *, u_int16_t); void des3_encrypt(struct keystate *, u_int8_t *, u_int16_t); void des3_decrypt(struct keystate *, u_int8_t *, u_int16_t); void blf_encrypt(struct keystate *, u_int8_t *, u_int16_t); void blf_decrypt(struct keystate *, u_int8_t *, u_int16_t); void cast1_encrypt(struct keystate *, u_int8_t *, u_int16_t); void cast1_decrypt(struct keystate *, u_int8_t *, u_int16_t); void aes_encrypt(struct keystate *, u_int8_t *, u_int16_t); void aes_decrypt(struct keystate *, u_int8_t *, u_int16_t); struct crypto_xf transforms[] = { #ifdef USE_DES { DES_CBC, "Data Encryption Standard (CBC-Mode)", 8, 8, BLOCKSIZE, 0, des1_init, des1_encrypt, des1_decrypt }, #endif #ifdef USE_TRIPLEDES { TRIPLEDES_CBC, "Triple-DES (CBC-Mode)", 24, 24, BLOCKSIZE, 0, des3_init, des3_encrypt, des3_decrypt }, #endif #ifdef USE_BLOWFISH { BLOWFISH_CBC, "Blowfish (CBC-Mode)", 12, 56, BLOCKSIZE, 0, blf_init, blf_encrypt, blf_decrypt }, #endif #ifdef USE_CAST { CAST_CBC, "CAST (CBC-Mode)", 12, 16, BLOCKSIZE, 0, cast_init, cast1_encrypt, cast1_decrypt }, #endif #ifdef USE_AES { AES_CBC, "AES (CBC-Mode)", 16, 32, AES_BLOCK_SIZE, 0, aes_init, aes_encrypt, aes_decrypt }, #endif }; /* Hmm, the function prototypes for des are really dumb */ #ifdef __OpenBSD__ #define DC (des_cblock *) #else #define DC (void *) #endif enum cryptoerr des1_init(struct keystate *ks, u_int8_t *key, u_int16_t len) { /* des_set_key returns -1 for parity problems, and -2 for weak keys */ des_set_odd_parity(DC key); switch (des_set_key(DC key, ks->ks_des[0])) { case -2: return EWEAKKEY; default: return EOKAY; } } void des1_encrypt(struct keystate *ks, u_int8_t *d, u_int16_t len) { des_cbc_encrypt(DC d, DC d, len, ks->ks_des[0], DC ks->riv, DES_ENCRYPT); } void des1_decrypt(struct keystate *ks, u_int8_t *d, u_int16_t len) { des_cbc_encrypt(DC d, DC d, len, ks->ks_des[0], DC ks->riv, DES_DECRYPT); } #ifdef USE_TRIPLEDES enum cryptoerr des3_init(struct keystate *ks, u_int8_t *key, u_int16_t len) { des_set_odd_parity(DC key); des_set_odd_parity(DC(key + 8)); des_set_odd_parity(DC(key + 16)); /* As of the draft Tripe-DES does not check for weak keys */ des_set_key(DC key, ks->ks_des[0]); des_set_key(DC(key + 8), ks->ks_des[1]); des_set_key(DC(key + 16), ks->ks_des[2]); return EOKAY; } void des3_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len) { u_int8_t iv[MAXBLK]; memcpy(iv, ks->riv, ks->xf->blocksize); des_ede3_cbc_encrypt(DC data, DC data, len, ks->ks_des[0], ks->ks_des[1], ks->ks_des[2], DC iv, DES_ENCRYPT); } void des3_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len) { u_int8_t iv[MAXBLK]; memcpy(iv, ks->riv, ks->xf->blocksize); des_ede3_cbc_encrypt(DC data, DC data, len, ks->ks_des[0], ks->ks_des[1], ks->ks_des[2], DC iv, DES_DECRYPT); } #undef DC #endif /* USE_TRIPLEDES */ #ifdef USE_BLOWFISH enum cryptoerr blf_init(struct keystate *ks, u_int8_t *key, u_int16_t len) { blf_key(&ks->ks_blf, key, len); return EOKAY; } void blf_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len) { u_int16_t i, blocksize = ks->xf->blocksize; u_int8_t *iv = ks->liv; u_int32_t xl, xr; memcpy(iv, ks->riv, blocksize); for (i = 0; i < len; data += blocksize, i += blocksize) { XOR64(data, iv); xl = GET_32BIT_BIG(data); xr = GET_32BIT_BIG(data + 4); Blowfish_encipher(&ks->ks_blf, &xl, &xr); SET_32BIT_BIG(data, xl); SET_32BIT_BIG(data + 4, xr); SET64(iv, data); } } void blf_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len) { u_int16_t i, blocksize = ks->xf->blocksize; u_int32_t xl, xr; data += len - blocksize; for (i = len - blocksize; i >= blocksize; data -= blocksize, i -= blocksize) { xl = GET_32BIT_BIG(data); xr = GET_32BIT_BIG(data + 4); Blowfish_decipher(&ks->ks_blf, &xl, &xr); SET_32BIT_BIG(data, xl); SET_32BIT_BIG(data + 4, xr); XOR64(data, data - blocksize); } xl = GET_32BIT_BIG(data); xr = GET_32BIT_BIG(data + 4); Blowfish_decipher(&ks->ks_blf, &xl, &xr); SET_32BIT_BIG(data, xl); SET_32BIT_BIG(data + 4, xr); XOR64(data, ks->riv); } #endif /* USE_BLOWFISH */ #ifdef USE_CAST enum cryptoerr cast_init(struct keystate *ks, u_int8_t *key, u_int16_t len) { cast_setkey(&ks->ks_cast, key, len); return EOKAY; } void cast1_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len) { u_int16_t i, blocksize = ks->xf->blocksize; u_int8_t *iv = ks->liv; memcpy(iv, ks->riv, blocksize); for (i = 0; i < len; data += blocksize, i += blocksize) { XOR64(data, iv); cast_encrypt(&ks->ks_cast, data, data); SET64(iv, data); } } void cast1_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len) { u_int16_t i, blocksize = ks->xf->blocksize; data += len - blocksize; for (i = len - blocksize; i >= blocksize; data -= blocksize, i -= blocksize) { cast_decrypt(&ks->ks_cast, data, data); XOR64(data, data - blocksize); } cast_decrypt(&ks->ks_cast, data, data); XOR64(data, ks->riv); } #endif /* USE_CAST */ #ifdef USE_AES enum cryptoerr aes_init(struct keystate *ks, u_int8_t *key, u_int16_t len) { AES_set_encrypt_key(key, len << 3, &ks->ks_aes[0]); AES_set_decrypt_key(key, len << 3, &ks->ks_aes[1]); return EOKAY; } void aes_encrypt(struct keystate *ks, u_int8_t *data, u_int16_t len) { u_int8_t iv[MAXBLK]; memcpy(iv, ks->riv, ks->xf->blocksize); AES_cbc_encrypt(data, data, len, &ks->ks_aes[0], iv, AES_ENCRYPT); } void aes_decrypt(struct keystate *ks, u_int8_t *data, u_int16_t len) { u_int8_t iv[MAXBLK]; memcpy(iv, ks->riv, ks->xf->blocksize); AES_cbc_encrypt(data, data, len, &ks->ks_aes[1], iv, AES_DECRYPT); } #endif /* USE_AES */ struct crypto_xf * crypto_get(enum transform id) { size_t i; for (i = 0; i < sizeof transforms / sizeof transforms[0]; i++) if (id == transforms[i].id) return &transforms[i]; return 0; } struct keystate * crypto_init(struct crypto_xf *xf, u_int8_t *key, u_int16_t len, enum cryptoerr *err) { struct keystate *ks; if (len < xf->keymin || len > xf->keymax) { LOG_DBG((LOG_CRYPTO, 10, "crypto_init: invalid key length %d", len)); *err = EKEYLEN; return 0; } ks = calloc(1, sizeof *ks); if (!ks) { log_error("crypto_init: calloc (1, %lu) failed", (unsigned long)sizeof *ks); *err = ENOCRYPTO; return 0; } ks->xf = xf; /* Setup the IV. */ ks->riv = ks->iv; ks->liv = ks->iv2; LOG_DBG_BUF((LOG_CRYPTO, 40, "crypto_init: key", key, len)); *err = xf->init(ks, key, len); if (*err != EOKAY) { LOG_DBG((LOG_CRYPTO, 30, "crypto_init: weak key found for %s", xf->name)); free(ks); return 0; } return ks; } void crypto_update_iv(struct keystate *ks) { u_int8_t *tmp; tmp = ks->riv; ks->riv = ks->liv; ks->liv = tmp; LOG_DBG_BUF((LOG_CRYPTO, 50, "crypto_update_iv: updated IV", ks->riv, ks->xf->blocksize)); } void crypto_init_iv(struct keystate *ks, u_int8_t *buf, size_t len) { memcpy(ks->riv, buf, len); LOG_DBG_BUF((LOG_CRYPTO, 50, "crypto_init_iv: initialized IV", ks->riv, len)); } void crypto_encrypt(struct keystate *ks, u_int8_t *buf, u_int16_t len) { LOG_DBG_BUF((LOG_CRYPTO, 10, "crypto_encrypt: before encryption", buf, len)); ks->xf->encrypt(ks, buf, len); memcpy(ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize); LOG_DBG_BUF((LOG_CRYPTO, 30, "crypto_encrypt: after encryption", buf, len)); } void crypto_decrypt(struct keystate *ks, u_int8_t *buf, u_int16_t len) { LOG_DBG_BUF((LOG_CRYPTO, 10, "crypto_decrypt: before decryption", buf, len)); /* * XXX There is controversy about the correctness of updating the IV * like this. */ memcpy(ks->liv, buf + len - ks->xf->blocksize, ks->xf->blocksize); ks->xf->decrypt(ks, buf, len); LOG_DBG_BUF((LOG_CRYPTO, 30, "crypto_decrypt: after decryption", buf, len)); } /* Make a copy of the keystate pointed to by OKS. */ struct keystate * crypto_clone_keystate(struct keystate *oks) { struct keystate *ks; ks = malloc(sizeof *ks); if (!ks) { log_error("crypto_clone_keystate: malloc (%lu) failed", (unsigned long)sizeof *ks); return 0; } memcpy(ks, oks, sizeof *ks); if (oks->riv == oks->iv) { ks->riv = ks->iv; ks->liv = ks->iv2; } else { ks->riv = ks->iv2; ks->liv = ks->iv; } return ks; } isakmpd-20041012.orig/isakmpd.policy.50000644000175000017500000005451510133045740017603 0ustar jdivejdive00000000000000.\" $OpenBSD: isakmpd.policy.5,v 1.35 2003/10/25 20:47:47 mcbride Exp $ .\" $EOM: isakmpd.policy.5,v 1.24 2000/11/23 12:55:25 niklas Exp $ .\" .\" Copyright (c) 1999-2001, Angelos D. Keromytis. 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. .\" .\" 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. .\" .\" .\" Manual page, using -mandoc macros .\" .Dd June 15, 2002 .Dt ISAKMPD.POLICY 5 .Os .Sh NAME .Nm isakmpd.policy .Nd policy configuration file for isakmpd .Sh DESCRIPTION .Nm is the policy configuration file for the .Nm isakmpd daemon managing security association and key management for the .Xr ipsec 4 layer of the kernel's networking stack. .Pp The .Xr isakmpd 8 daemon (also known as IKE, for Internet Key Exchange) is used when two systems need to automatically set up a pair of Security Associations (SAs) for securely communicating using IPsec. IKE operates in two stages: .Pp In the first stage (Main or Identity Protection Mode), the two IKE daemons establish a secure link between themselves, fully authenticating each other and establishing key material for encrypting/authenticating future communications between them. This step is typically only performed once for every pair of IKE daemons. .Pp In the second stage (also called Quick Mode), the two IKE daemons create the pair of SAs for the parties that wish to communicate using IPsec. These parties may be the hosts the IKE daemons run on, a host and a network behind a firewall, or two networks behind their respective firewalls. At this stage, the exact parameters of the SAs (e.g., algorithms to use, encapsulation mode, lifetime) and the identities of the communicating parties (hosts, networks, etc.) are specified. The reason for the existence of Quick Mode is to allow for fast SA setup, once the more heavy-weight Main Mode has been completed. Generally, Quick Mode uses the key material derived from Main Mode to provide keys to the IPsec transforms to be used. Alternatively, a new Diffie-Hellman computation may be performed (significantly slowing down the exchange, but at the same time providing Perfect Forward Secrecy (PFS)). Briefly, this means that even should an attacker manage to break long-term keys used in other sessions (or, specifically, if an attacker breaks the Diffie-Hellman exchange performed during Main Mode), they will not be able to decrypt this traffic. Normally, no PFS is provided (the key material used by the IPsec SAs established as a result of this exchange will be derived from the key material of the Main Mode exchange), allowing for a faster Quick Mode exchange (no public key computations). .Pp IKE proposals are "suggestions" by the initiator of an exchange to the responder as to what protocols and attributes should be used on a class of packets. For example, a given exchange may ask for ESP with 3DES and MD5 and AH with SHA1 (applied successively on the same packet), or just ESP with Blowfish and RIPEMD-160. The responder examines the proposals and determines which of them are acceptable, according to policy and any credentials. .Pp The following paragraphs assume some knowledge of the contents of the .Xr keynote 4 and .Xr keynote 5 man pages. .Pp In the KeyNote policy model for IPsec, no distinction is currently made based on the ordering of AH and ESP in the packet. Should this change in the future, an appropriate attribute (see below) will be added. .Pp The goal of security policy for IKE is thus to determine, based on local policy (provided in the .Nm isakmpd.policy file), credentials provided during the IKE exchanges (or obtained through other means), the SA attributes proposed during the exchange, and perhaps other (side-channel) information, whether a pair of SAs should be installed in the system (in fact, whether both the IPsec SAs and the flows should be installed). For each proposal suggested by or to the remote IKE daemon, the KeyNote system is consulted as to whether the proposal is acceptable based on local policy (contained in .Nm isakmpd.policy , in the form of policy assertions) and remote credentials (e.g., KeyNote credentials or X509 certificates provided by the remote IKE daemon). .Pp .Nm isakmpd.policy is simply a flat .Xr ascii 7 file containing KeyNote policy assertions, separated by blank lines (note that KeyNote assertions may not contain blank lines). .Nm isakmpd.policy is read when .Xr isakmpd 8 is first started, and every time it receives a .Dv SIGHUP signal. The new policies read will be used for all new Phase 2 (IPsec) SAs established from that point on (even if the associated Phase 1 SA was already established when the new policies were loaded). The policy change will not affect already established Phase 2 SAs. .Pp For more details on KeyNote assertion format, please see .Xr keynote 5 . Briefly, KeyNote policy assertions used in IKE have the following characteristics: .Bl -bullet .It The Authorizer field is typically "POLICY" (but see the examples below, for use of policy delegation). .It The Licensees field can be an expression of passphrases used for authentication of the Main Mode exchanges, and/or public keys (typically, X509 certificates), and/or X509 distinguished names. .It The Conditions field contains an expression of attributes from the IPsec policy action set (see below as well as the keynote syntax man page for more details). .It The ordered return-values set for IPsec policy is "false, true". .El .Pp For an explanation of these fields and their semantics, see .Xr keynote 5 . .Pp For example, the following policy assertion: .Bd -literal Authorizer: "POLICY" Licensees: "passphrase:foobar" || "x509-base64:abcd==" || "passphrase-md5-hex:3858f62230ac3c915f300c664312c63f" || "passphrase-sha1-hex:8843d7f92416211de9ebb963ff4ce28125932878" Conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg != "null" -> "true"; .Ed .Pp says that any proposal from a remote host that authenticates using the passphrase "foobar" or the public key contained in the X509 certificate encoded as "abcd==" will be accepted, as long as it contains ESP with a non-null algorithm (i.e., the packet will be encrypted). The last two authorizers are the MD5 and SHA1 hashes respectively of the passphrase "foobar". This form may be used instead of the "passphrase:..." one to protect the passphrase as included in the policy file (or as distributed in a signed credential). .Pp The following policy assertion: .Bd -literal Authorizer: "POLICY" Licensees: "DN:/CN=CA Certificate" Conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg != "null" -> "true"; .Ed .Pp is similar to the previous one, but instead of including a complete X509 credential in the Licensees field, only the X509 certificate's Subject Canonical Name needs to be specified (note that the "DN:" prefix is necessary). .Pp KeyNote credentials have the same format as policy assertions, with one difference: the Authorizer field always contains a public key, and the assertion is signed (and thus its integrity can be cryptographically verified). Credentials are used to build chains of delegation of authority. They can be exchanged during an IKE exchange, or can be retrieved through some out-of-band mechanism (no such mechanism is currently supported in this implementation however). See .Xr isakmpd.conf 5 on how to specify what credentials to send in an IKE exchange. .Pp Passphrases that appear in the Licensees field are encoded as the string "passphrase:", followed by the passphrase itself (case-sensitive). Alternatively (and preferably), they may be encoded using the "passphrase-md5-hex:" or "passphrase-sha1-hex:" prefixes, followed by the .Xr md5 1 or .Xr sha1 1 hash of the passphrase itself, encoded as a hexadecimal string (using lower-case letters only). .Pp When X509-based authentication is performed in Main Mode, any X509 certificates received from the remote IKE daemon are converted to very simple KeyNote credentials. The conversion is straightforward: the issuer of the X509 certificate becomes the Authorizer of the KeyNote credential, the subject becomes the only Licensees entry, while the Conditions field simply asserts that the credential is only valid for "IPsec policy" use (see the app_domain action attribute below). .Pp Similarly, any X509 CA certificates present in the directory pointed to by the appropriate .Xr isakmpd.conf 5 entry, are converted to such pseudo-credentials. This allows one to write KeyNote policies that delegate specific authority to CAs (and the keys those CAs certify, recursively). .Pp For more details on KeyNote assertion format, see .Xr keynote 5 . .Pp Information about the proposals, the identity of the remote IKE daemon, the packet classes to be protected, etc. are encoded in what is called an action set. The action set is composed of name-value attributes, similar in some ways to shell environment variables. These values are initialized by .Nm isakmpd before each query to the KeyNote system, and can be tested against in the Conditions field of assertions. See .Xr keynote 4 and .Xr keynote 5 for more details on the format and semantics of the Conditions field. .Pp Note that assertions and credentials can make references to non-existent attributes without catastrophic failures (access may be denied, depending on the overall structure, but will not be accidentally granted). One reason for credentials referencing non-existent attributes is that they were defined within a specific implementation or network only. .Pp In the following attribute set, IPv4 addresses are encoded as ASCII strings in the usual dotted-quad format. However, all quads are three digits long. For example, the IPv4 address .Va 10.128.1.12 would be encoded as .Va 010.128.001.012 . Similarly, IPv6 addresses are encoded in the standard x:x:x:x:x:x:x:x format, where the 'x's are the hexadecimal values of the eight 16-bit pieces of the address. All 'x's are four digits long. For example, the address .Va 1080:0:12:0:8:800:200C:417A would be encoded as .Va 1080:0000:0012:0000:0008:0800:200C:417A . .Pp The following attributes are currently defined: .Bl -tag -width -indent .It app_domain Always set to .Va IPsec policy . .It doi Always set to .Va ipsec . .It initiator Set to .Va yes if the local daemon is initiating the Phase 2 SA, .Va no otherwise. .It phase_1 Set to .Va aggressive if aggressive mode was used to establish the Phase 1 SA, or .Va main if main mode was used instead. .It pfs Set to .Va yes if a Diffie-Hellman exchange will be performed during this Quick Mode, .Va no otherwise. .It ah_present, esp_present, comp_present Set to .Va yes if an AH, ESP, or compression proposal was received respectively, .Va no otherwise. .It ah_hash_alg One of .Va md5 , .Va sha , .Va ripemd , .Va sha2-256 , .Va sha2-385 , .Va sha2-512 , or .Va des , based on the hash algorithm specified in the AH proposal. This attribute describes the generic transform to be used in the AH authentication. .It esp_enc_alg One of .Va des , .Va des-iv64 , .Va 3des , .Va rc4 , .Va idea , .Va cast , .Va blowfish , .Va 3idea , .Va des-iv32 , .Va rc4 , .Va null , or .Va aes , based on the encryption algorithm specified in the ESP proposal. .It comp_alg One of .Va oui , .Va deflate , .Va lzs , or .Va v42bis , based on the compression algorithm specified in the compression proposal. .It ah_auth_alg One of .Va hmac-md5 , .Va hmac-sha , .Va des-mac , .Va kpdk , .Va hmac-sha2-256 , .Va hmac-sha2-385 , .Va hmac-sha2-512 , or .Va hmac-ripemd . based on the authentication method specified in the AH proposal. .It esp_auth_alg One of .Va hmac-md5 , .Va hmac-sha , .Va des-mac , .Va kpdk , .Va hmac-sha2-256 , .Va hmac-sha2-385 , .Va hmac-sha2-512 , or .Va hmac-ripemd based on the authentication method specified in the ESP proposal. .It ah_life_seconds, esp_life_seconds, comp_life_seconds Set to the lifetime of the AH, ESP, and compression proposal, in seconds. If no lifetime was proposed for the corresponding protocol (e.g., there was no proposal for AH), the corresponding attribute will be set to zero. .It ah_life_kbytes, esp_life_kbytes, comp_life_kbytes Set to the lifetime of the AH, ESP, and compression proposal, in kbytes of traffic. If no lifetime was proposed for the corresponding protocol (e.g., there was no proposal for AH), the corresponding attribute will be set to zero. .It ah_encapsulation, esp_encapsulation, comp_encapsulation Set to .Va tunnel or .Va transport , based on the AH, ESP, and compression proposal. .It ah_ecn, esp_ecn, comp_ecn Set to .Va yes or .Va no , based on whether ECN was requested for the IPsec tunnel. .It comp_dict_size Specifies the log2 maximum size of the dictionary, according to the compression proposal. .It comp_private_alg Set to an integer specifying the private algorithm in use, according to the compression proposal. .It ah_key_length, esp_key_length The number of key bits to be used by the authentication and encryption algorithms respectively (for variable key-size algorithms). .It ah_key_rounds, esp_key length The number of rounds of the authentication and encryption algorithms respectively (for variable round algorithms). .It ah_group_desc, esp_group_desc, comp_group_desc The Diffie-Hellman group identifier from the AH, ESP, and compression proposal, used for PFS during Quick Mode (see the pfs attribute above). If more than one of these attributes are set to a value other than zero, they should have the same value (in valid IKE proposals). Valid values are 1 (768-bit MODP), 2 (1024-bit MODP), 3 (155-bit EC), 4 (185-bit EC), and 5 (1536-bit MODP). .It phase1_group_desc The Diffie-Hellman group identifier used in IKE Phase 1. Takes the same values as .Va ah_group_desc . .It remote_filter_type, local_filter_type, remote_id_type Set to .Va IPv4 address , .Va IPv4 range , .Va IPv4 subnet , .Va IPv6 address , .Va IPv6 range , .Va IPv6 subnet , .Va FQDN , .Va User FQDN , .Va ASN1 DN , .Va ASN1 GN , or .Va Key ID , based on the Quick Mode Initiator ID, Quick Mode Responder ID, and Main Mode peer ID respectively. .It remote_filter_addr_upper, local_filter_addr_upper, remote_id_addr_upper When the corresponding filter_type is .Va IPv4 address or .Va IPv6 address , these contain the respective address. For .Va IPv4 range or .Va IPv6 range , they contain the upper end of the address range. For .Va IPv4 subnet or .Va IPv6 subnet , they contain the highest address in the specified subnet. .It remote_filter_addr_lower, local_filter_addr_lower, remote_id_addr_lower When the corresponding filter_type is .Va IPv4 address or .Va IPv6 address , these contain the respective address. For .Va IPv4 range or .Va IPv6 range , these contain the lower end of the address range. For .Va IPv4 subnet or .Va IPv6 subnet , these contain the lowest address in the specified subnet. .It remote_filter, local_filter, remote_id When the corresponding filter_type specifies an address range or subnet, these are set to the upper and lower part of the address space separated by a dash ('-') character (if the type specifies a single address, they are set to that address). .Pp For FQDN and User FQDN types, these are set to the respective string. For Key ID, these are set to the hexadecimal representation of the associated byte string (lower-case letters used) if the Key ID payload contains non-printable characters. Otherwise, they are set to the respective string. .Pp For ASN1 DN, these are set to the text encoding of the Distinguished Name in the payload sent or received. The format is the same as that used in the Licensees field. .It remote_filter_port, local_filter_port, remote_id_port Set to the transport protocol port. .It remote_filter_proto, local_filter_proto, remote_id_proto Set to .Va etherip , .Va tcp , .Va udp , or the transport protocol number, depending on the transport protocol set in the IDci, IDcr, and Main Mode peer ID respectively. .It remote_negotiation_address Set to the IPv4 or IPv6 address of the remote IKE daemon. .It local_negotiation_address Set to the IPv4 or IPv6 address of the local interface used by the local IKE daemon for this exchange. .It GMTTimeOfDay Set to the UTC date/time, in YYYYMMDDHHmmSS format. .It LocalTimeOfDay Set to the local date/time, in YYYYMMDDHHmmSS format. .El .Sh FILES .Bl -tag -width /etc/isakmpd/isakmpd.policy .It Pa /etc/isakmpd/isakmpd.policy The default .Nm isakmpd policy configuration file. .It Pa /usr/share/ipsec/isakmpd/policy A sample .Nm isakmpd policy configuration file. .El .Sh EXAMPLES .Bd -literal Authorizer: "POLICY" Comment: This bare-bones assertion accepts everything Authorizer: "POLICY" Licensees: "passphrase-md5-hex:10838982612aff543e2e62a67c786550" Comment: This policy accepts anyone using shared-secret authentication using the password mekmitasisgoat, and does ESP with some form of encryption (not null). Conditions: app_domain == "IPsec policy" && esp_present == "yes" && esp_enc_alg != "null" -> "true"; Authorizer: "POLICY" Licensees: "subpolicy1" || "subpolicy2" Comment: Delegate to two other sub-policies, so we can manage our policy better. Since these subpolicies are not "owned" by a key (and are thus unsigned), they have to be in isakmpd.policy. Conditions: app_domain == "IPsec policy"; KeyNote-Version: 2 Licensees: "passphrase-md5-hex:9c42a1346e333a770904b2a2b37fa7d3" Conditions: esp_present == "yes" -> "true"; Authorizer: "subpolicy1" Conditions: ah_present == "yes" -> { ah_auth_alg == "md5" -> "true"; ah_auth_alg == "sha" && esp_present == "no" -> "true"; }; Licensees: "passphrase:otherpassword" || "passphrase-sha1-hex:f5ed6e4abd30c36a89409b5da7ecb542c9fbf00f" Authorizer: "subpolicy2" keynote-version: 2 comment: this is an example of a policy delegating to a CN. authorizer: "POLICY" licensees: "DN:/CN=CA Certificate/emailAddress=ca@foo.bar.com" keynote-version: 2 comment: This is an example of a policy delegating to a key. authorizer: "POLICY" licensees: "x509-base64:MIICGDCCAYGgAwIBAgIBADANBgkqhkiG9w0BAQQ\\ FADBSMQswCQYDVQQGEwJHQjEOMAwGA1UEChMFQmVuQ28xETAPBg\\ NVBAMTCEJlbkNvIENBMSAwHgYJKoZIhvcNAQkBFhFiZW5AYWxnc\\ m91cC5jby51azAeFw05OTEwMTEyMjQ5MzhaFw05OTExMTAyMjQ5\\ MzhaMFIxCzAJBgNVBAYTAkdCMQ4wDAYDVQQKEwVCZW5DbzERMA8\\ GA1UEAxMIQmVuQ28gQ0ExIDAeBgkqhkiG9w0BCQEWEWJlbkBhbG\\ dyb3VwLmNvLnVrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBg\\ QCxyAte2HEVouXg1Yu+vDihbnjDRn+6k00Rv6cZqbwA3BQ30mC/\\ 3TFJ09VGXCaM0UKfpnxIpkBYLmOA3FWkKI0RvPU7E1AhKkhC1Ds\\ PSBFjYHrB15T5lYzgfwKJCIxTDzZDx2iobUgPa0FRNGVUjpQ4/k\\ MJ2BF4Wh7zY3X08rMzsQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBA\\ DWJ5pbTcE7iKHWLQTMYiz8i9jGi5+Eo1yr1Bab90tgaGQV0zrRH\\ jDHgAAy1h8WSXuyQrXfgbx2rnWFPhx9CfmuAXn7sZmQE3mnUqeP\\ ZL2dW87jdBGqtoUdNcoz5zKBkC943yasNui/O01MiqgadTThTJH\\ d1Pn17LbJC1ZVRNjR5" conditions: app_domain == "IPsec policy" && doi == "ipsec" && pfs == "yes" && esp_present == "yes" && ah_present == "no" && (esp_enc_alg == "3des" || esp_enc_alg == "aes") -> "true"; keynote-version: 2 comment: This is an example of a credential, the signature does not really verify (although the keys are real). licensees: "x509-base64:MIICGDCCAYGgAwIBAgIBADANBgkqhkiG9w0BAQQ\\ FADBSMQswCQYDVQQGEwJHQjEOMAwGA1UEChMFQmVuQ28xETAPBg\\ NVBAMTCEJlbkNvIENBMSAwHgYJKoZIhvcNAQkBFhFiZW5AYWxnc\\ m91cC5jby51azAeFw05OTEwMTEyMzA2MjJaFw05OTExMTAyMzA2\\ MjJaMFIxCzAJBgNVBAYTAkdCMQ4wDAYDVQQKEwVCZW5DbzERMA8\\ GA1UEAxMIQmVuQ28gQ0ExIDAeBgkqhkiG9w0BCQEWEWJlbkBhbG\\ dyb3VwLmNvLnVrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBg\\ QDaCs+JAB6YRKAVkoi1NkOpE1V3syApjBj0Ahjq5HqYAACo1JhM\\ +QsPwuSWCNhBT51HX6G6UzfY3mOUz/vou6MJ/wor8EdeTX4nucx\\ NSz/r6XI262aXezAp+GdBviuJZx3Q67ON/IWYrB4QtvihI4bMn5\\ E55nF6TKtUMJTdATvs/wIDAQABMA0GCSqGSIb3DQEBBAUAA4GBA\\ MaQOSkaiR8id0h6Zo0VSB4HpBnjpWqz1jNG8N4RPN0W8muRA2b9\\ 85GNP1bkC3fK1ZPpFTB0A76lLn11CfhAf/gV1iz3ELlUHo5J8nx\\ Pu6XfsGJm3HsXJOuvOog8Aean4ODo4KInuAsnbLzpGl0d+Jqa5u\\ TZUxsyg4QOBwYEU92H" authorizer: "x509-base64:MIICGDCCAYGgAwIBAgIBADANBgkqhkiG9w0BAQQ\\ FADBSMQswCQYDVQQGEwJHQjEOMAwGA1UEChMFQmVuQ28xETAPBg\\ NVBAMTCEJlbkNvIENBMSAwHgYJKoZIhvcNAQkBFhFiZW5AYWxnc\\ m91cC5jby51azAeFw05OTEwMTEyMjQ5MzhaFw05OTExMTAyMjQ5\\ MzhaMFIxCzAJBgNVBAYTAkdCMQ4wDAYDVQQKEwVCZW5DbzERMA8\\ GA1UEAxMIQmVuQ28gQ0ExIDAeBgkqhkiG9w0BCQEWEWJlbkBhbG\\ dyb3VwLmNvLnVrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBg\\ QCxyAte2HEVouXg1Yu+vDihbnjDRn+6k00Rv6cZqbwA3BQ30mC/\\ 3TFJ09VGXCaM0UKfpnxIpkBYLmOA3FWkKI0RvPU7E1AhKkhC1Ds\\ PSBFjYHrB15T5lYzgfwKJCIxTDzZDx2iobUgPa0FRNGVUjpQ4/k\\ MJ2BF4Wh7zY3X08rMzsQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBA\\ DWJ5pbTcE7iKHWLQTMYiz8i9jGi5+Eo1yr1Bab90tgaGQV0zrRH\\ jDHgAAy1h8WSXuyQrXfgbx2rnWFPhx9CfmuAXn7sZmQE3mnUqeP\\ ZL2dW87jdBGqtoUdNcoz5zKBkC943yasNui/O01MiqgadTThTJH\\ d1Pn17LbJC1ZVRNjR5" conditions: app_domain == "IPsec policy" && doi == "ipsec" && pfs == "yes" && esp_present == "yes" && ah_present == "no" && (esp_enc_alg == "3des" || esp_enc_alg == "aes") -> "true"; Signature: "sig-x509-sha1-base64:ql+vrUxv14DcBOQHR2jsbXayq6T\\ mmtMiUB745a8rjwSrQwh+KIVDlUrghPnqhSIkWSDi9oWWMbfg\\ mkdudZ0wjgeTLMI2NI4GibMMsToakOKMex/0q4cpdpln3DKcQ\\ IcjzRv4khDws69FT3QfELjcpShvbLrXmh1Z00OFmxjyqDw=" .Ed .Sh SEE ALSO .Xr ipsec 4 , .Xr keynote 4 , .Xr keynote 5 , .Xr isakmpd 8 .Sh BUGS A more sane way of expressing IPv6 address ranges is needed. isakmpd-20041012.orig/isakmpd.conf.50000644000175000017500000007443310133045740017232 0ustar jdivejdive00000000000000.\" $OpenBSD: isakmpd.conf.5,v 1.94 2004/08/10 15:59:10 ho Exp $ .\" $EOM: isakmpd.conf.5,v 1.57 2000/12/21 14:43:17 ho Exp $ .\" .\" Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved. .\" Copyright (c) 2000, 2001, 2002 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. .\" .\" 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. .\" .\" This code was written under funding by Ericsson Radio Systems. .\" .\" Manual page, using -mandoc macros .\" .Dd August 07, 2002 .Dt ISAKMPD.CONF 5 .Os .Sh NAME .Nm isakmpd.conf .Nd configuration file for isakmpd .Sh DESCRIPTION .Nm is the configuration file for the .Nm isakmpd daemon managing security association and key management for the IPsec layer of the kernel's networking stack. .Pp The file is of a well known type of format called .INI style, named after the suffix used by an overrated windowing environment for its configuration files. This format consists of sections, each beginning with a line looking like: .Bd -literal [Section name] .Ed Between the brackets is the name of the section following this section header. Inside a section many tag/value pairs can be stored, each one looking like: .Bd -literal Tag=Value .Ed If the value needs more space than fits on a single line it's possible to continue it on the next by ending the first with a backslash character immediately before the newline character. This method can extend a value for an arbitrary number of lines. .Pp Comments can be put anywhere in the file by using a hash mark .Pq Sq \&# . The comment extends to the end of the current line. .Pp Often the right-hand side values consist of other section names. This results in a tree structure. Some values are treated as a list of several scalar values. Such lists always use a comma character as the separator. Some values are formatted like this: X,Y:Z, which is an offer/accept syntax, where X is a value we offer and Y:Z is a range of accepted values, inclusive. .Pp To activate changes to .Nm without restarting .Nm isakmpd , send a .Dv SIGHUP signal to the daemon process. .Ss Auto-generated parts of the configuration .Pp Some predefined section names are recognized by the daemon, avoiding the need to fully specify the Main Mode transforms and Quick Mode suites, protocols, and transforms. .Pp For Main Mode: .Bd -filled -compact .Ar {DES,BLF,3DES,CAST,AES}-{MD5,SHA}[-GRP{1,2,5,14}][-{DSS,RSA_SIG}] .Ed .Pp For Quick Mode: .Bd -filled -compact .Ar QM-{proto}[-TRP]-{cipher}[-{hash}][-PFS[-{group}]]-SUITE .Ed .Bd -literal where {proto} is either ESP or AH {cipher} is either DES, 3DES, CAST, BLF or AES {hash} is either MD5, SHA, RIPEMD, SHA2-{256,384,512} {group} is either GRP1, GRP2, GRP5 or GRP14 .Ed .Pp For example, 3DES-SHA means: 3DES encryption, SHA hash, and authorization by pre-shared keys. Similarly, QM-ESP-3DES-SHA-PFS-SUITE means: ESP protocol, 3DES encryption, SHA hash, and use Perfect Forward Secrecy. .Pp Unless explicitly stated with -GRP1, 2, 5 or 14 transforms and PFS suites use DH group 2. There are currently no predefined ESP+AH Quick Mode suites. .Pp The predefinitions include some default values for the special sections "General", "Keynote", "X509-certificates", and "Default-phase-1-configuration". These default values are presented in the example below. .Pp All autogenerated values can be overridden by manual entries by using the same section and tag names in the configuration file. In particular, the default phase 1 (Main or Aggressive Mode) and phase 2 (Quick Mode) lifetimes can be overridden by these tags under the "General" section; .Bd -literal [General] Default-phase-1-lifetime= 3600,60:86400 Default-phase-2-lifetime= 1200,60:86400 .Ed .Pp The Main Mode lifetime currently defaults to one hour (minimum 60 seconds, maximum 1 day). The Quick Mode lifetime defaults to 20 minutes (minimum 60 seconds, maximum 1 day). .Pp Also, the default phase 1 ID can be set by creating a section, as shown below, and adding this tag under the "General" section; .Bd -literal [General] Default-phase-1-ID= Phase1-ID-name [Phase1-ID-name] ID-type= USER_FQDN Name= foo@bar.com .Ed .Ss Roots .Bl -hang -width 12n .It Em General Generic global configuration parameters .Bl -tag -width 12n .It Em Default-phase-1-ID Optional default phase 1 ID name. .It Em Default-phase-1-lifetime The default lifetime for autogenerated transforms (phase 1). If unspecified, the value 3600,60:86400 is used as the default. .It Em Default-phase-2-lifetime The default lifetime for autogenerated suites (phase 2). If unspecified, the value 1200,60:86400 is used as the default. .It Em Default-phase-2-suites A list of phase 2 suites that will be used when establishing dynamic SAs. If left unspecified, QM-ESP-3DES-SHA-PFS-SUITE is used as the default. .It Em Acquire-Only If this tag is defined, .Nm isakmpd will not set up flows automatically. This is useful when flows are configured with .Xr ipsecadm 4 or by other programs like .Xr bgpd 8 . Thus .Nm isakmpd only takes care of the SA establishment. .It Em Check-interval The interval between watchdog checks of connections we want up at all times. .It Em DPD-check-interval The interval between RFC 3706 (Dead Peer Detection) messages. The default value is 0 (zero), which means DPD is disabled. .It Em Exchange-max-time How many seconds should an exchange maximally take to set up before we give up. .It Em Listen-on A list of IP-addresses OK to listen on. This list is used as a filter for the set of addresses the interfaces configured provides. This means that we won't see if an address given here does not exist on this host, and thus no error is given for that case. .It Em Loglevel A list of the form .Ar class Ns = Ns Ar level , where both .Ar class and .Ar level are numbers. This is similar to the .Fl D command line switch of .Em isakmpd . See .Xr isakmpd 8 for details. .It Em Logverbose If this tag is defined, whatever the value is, verbose logging is enabled. This is similar to the .Fl v command line switch of .Em isakmpd . See .Xr isakmpd 8 for details. .It Em NAT-T-Keepalive The number of seconds between NAT-T keepalive messages, sent by the peer behind NAT to keep the mapping active. Defaults to 20. .It Em Policy-file The name of the file that contains .Xr keynote 4 policies. The default is "/etc/isakmpd/isakmpd.policy". .It Em Pubkey-directory The directory in which .Nm looks for explicitly trusted public keys. The default is "/etc/isakmpd/pubkeys". Read .Xr isakmpd 8 for the required naming convention of the files in here. .It Em Renegotiate-on-HUP If this tag is defined, whatever the value is, .Nm isakmpd will renegotiate all current phase 2 SAs when the daemon receives a .Dv SIGHUP signal, or an .Sq R is sent to the FIFO interface (see .Xr isakmpd 8 ) . .It Em Retransmits How many times should a message be retransmitted before giving up. .It Em Shared-SADB If this tag is defined, whatever the value is, some semantics of .Nm are changed so that multiple instances can run on top of one SADB and set up SAs with each other. Specifically this means replay protection will not be asked for, and errors that can occur when updating an SA with its parameters a 2nd time will be ignored. .It Em Use-Keynote This tag controls the use of .Xr keynote 4 policy checking. The default value is .Qq yes , which enables the policy checking. When set to any other value, policies will not be checked. This is useful when policies for flows and SA establishment are arranged by other programs like .Xr ipsecadm 8 or .Xr bgpd 8 . .El .It Em Phase 1 ISAKMP SA negotiation parameter root .Bl -tag -width 12n .It Em A name of the ISAKMP peer at the given IP-address. .It Em Default A name of the default ISAKMP peer. Incoming phase 1 connections from other IP-addresses will use this peer name. .It "" This name is used as the section name for further information to be found. Look at below. .El .It Em Phase 2 IPsec SA negotiation parameter root .Bl -tag -width 12n .It Em Connections A list of directed IPsec "connection" names that should be brought up automatically, either on first use if the system supports it, or at startup of the daemon. These names are section names where further information can be found. Look at below. Normally any connections mentioned here are treated as part of the "Passive-connection" list we present below, however there is a flag: "Active-only" that disables this behaviour. This too is mentioned in the section, in the "Flags" tag. .It Em Passive-connections A list of IPsec "connection" names we recognize and accept initiations for. These names are section names where further information can be found. Look at below. Currently only the Local-ID and Remote-ID tags are looked at in those sections, as they are matched against the IDs given by the initiator. .El .It Em KeyNote .Bl -tag -width 12n .It Em Credential-directory A directory containing directories named after IDs (IP addresses, .Dq user@domain , or hostnames) that contain files named .Dq credentials and .Dq private_key . .Pp The credentials file contains .Xr keynote 4 credentials that are sent to a remote IKE daemon when we use the associated ID, or credentials that we may want to consider when doing an exchange with a remote IKE daemon that uses that ID. Note that, in the former case, the last credential in the file MUST contain our public key in its Licensees field. More than one credentials may exist in the file. They are separated by whitelines (the format is essentially the same as that of the policy file). The credentials are of the same format as the policies described in .Xr isakmpd.policy 5 . The only difference is that the Authorizer field contains a public key, and the assertion is signed. Signed assertions can be generated using the .Xr keynote 1 utility. .Pp The private_key file contains the private RSA key we use for authentication. If the directory (and the files) exist, they take precedence over X509-based authentication. .El .It Em X509-Certificates .Bl -tag -width 12n .It Em Accept-self-signed If this tag is defined, whatever the value is, certificates that do not originate from a trusted CA but are self-signed will be accepted. .It Em Ca-directory A directory containing PEM certificates of certification authorities that we trust to sign other certificates. Note that for a CA to be really trusted, it needs to be somehow referred to by policy, in .Xr isakmpd.policy 5 . The certificates in this directory are used for the actual X.509 authentication and for cross-referencing policies that refer to Distinguished Names (DNs). Keeping a separate directory (as opposed to integrating policies and X.509 CA certificates) allows for maintenance of a list of "well known" CAs without actually having to trust all (or any) of them. .It Em Cert-directory A directory containing PEM certificates that we trust to be valid. These certificates are used in preference to those passed in messages and are required to have a subjectAltName extension containing the certificate holder identity; usually IP address, FQDN, or User FQDN, as provided by .Xr certpatch 8 . .It Em Private-key The private key matching the public key of our certificate (which should be in the "Cert-directory", and have an appropriate subjectAltName field). .El .El .Ss Referred-to sections .Bl -hang -width 12n .It Em Parameters for negotiation with an ISAKMP peer .Bl -tag -width 12n .It Em Phase The constant .Li 1 , as ISAKMP-peers and IPsec-connections really are handled by the same code inside isakmpd. .It Em Transport The name of the transport protocol, defaults to .Li UDP . .It Em Port In case of .Li UDP , the .Li UDP port number to send to. This is optional, the default value is 500 which is the IANA-registered number for ISAKMP. .It Em Local-address The Local IP-address to use, if we are multi-homed, or have aliases. .It Em Address If existent, the IP-address of the peer. .It Em Configuration The name of the ISAKMP-configuration section to use. Look at below. If unspecified, defaults to "Default-phase-1-configuration". .It Em Authentication If existent, authentication data for this specific peer. In the case of preshared key, this is the key value itself. .It Em ID If existent, the name of the section that describes the local client ID that we should present to our peer. If not present, it defaults to the address of the local interface we are sending packets over to the remote daemon. Look at below. .It Em Remote-ID If existent, the name of the section that describes the remote client ID we expect the remote daemon to send us. If not present, it defaults to the address of the remote daemon. Look at below. .It Em Flags A comma-separated list of flags controlling the further handling of the ISAKMP SA. Currently there are no specific ISAKMP SA flags defined. .El .It Em .Bl -tag -width 12n .It Em ID-type The ID type as given by the RFC specifications. For phase 1 this is currently .Li IPV4_ADDR , .Li IPV4_ADDR_SUBNET , .Li IPV6_ADDR , .Li IPV6_ADDR_SUBNET , .Li FQDN , .Li USER_FQDN or .Li KEY_ID . .It Em Address If the ID-type is .Li IPV4_ADDR or .Li IPV6_ADDR , this tag should exist and be an IP-address. .It Em Network If the ID-type is .Li IPV4_ADDR_SUBNET or .Li IPV6_ADDR_SUBNET this tag should exist and be a network address. .It Em Netmask If the ID-type is .Li IPV4_ADDR_SUBNET or .Li IPV6_ADDR_SUBNET this tag should exist and be a network subnet mask. .It Em Name If the ID-type is .Li FQDN , .Li USER_FQDN or .Li KEY_ID , this tag should exist and contain a domain name, user@domain, or other identifying string respectively. .Pp In the case of .Li KEY_ID , note that the IKE protocol allows any octet sequence to be sent or received under this payload, potentially including non-printable ones. .Xr isakmpd 8 can only transmit printable .Li KEY_ID payloads, but can receive and process arbitrary .Li KEY_ID payloads. This effectively means that non-printable .Li KEY_ID remote identities cannot be verified through this means, although it is still possible to do so through .Xr isakmpd.policy 5 . .El .It Em .Bl -tag -width 12n .It Em DOI The domain of interpretation as given by the RFCs. Normally .Li IPSEC . If unspecified, defaults to .Li IPSEC . .It Em EXCHANGE_TYPE The exchange type as given by the RFCs. For main mode this is .Li ID_PROT and for aggressive mode it is .Li AGGRESSIVE . .It Em Transforms A list of proposed transforms to use for protecting the ISAKMP traffic. These are actually names for sections further describing the transforms. Look at below. .El .It Em .Bl -tag -width 12n .It Em ENCRYPTION_ALGORITHM The encryption algorithm as the RFCs name it, or ANY to denote that any encryption algorithm proposed will be accepted. .It Em KEY_LENGTH For encryption algorithms with variable key length, this is where the offered/accepted keylengths are described. The value is of the offer-accept kind described above. .It Em HASH_ALGORITHM The hash algorithm as the RFCs name it, or ANY. .It Em AUTHENTICATION_METHOD The authentication method as the RFCs name it, or ANY. .It Em GROUP_DESCRIPTION The group used for Diffie-Hellman exponentiations, or ANY. The names are symbolic, like .Li MODP_768 , MODP_1024 , EC_155 and .Li EC_185 . .It Em PRF The algorithm to use for the keyed pseudo-random function (used for key derivation and authentication in phase 1), or ANY. .It Em Life A list of lifetime descriptions, or ANY. In the former case, each element is in itself a name of the section that defines the lifetime. Look at below. If it is set to ANY, then any type of proposed lifetime type and value will be accepted. .El .It Em .Bl -tag -width 12n .It Em LIFE_TYPE .Li SECONDS or .Li KILOBYTES depending on the type of the duration. Notice that this field may NOT be set to ANY. .It Em LIFE_DURATION An offer/accept kind of value, see above. Can also be set to ANY. .El .It Em .Bl -tag -width 12n .It Em Phase The constant .Li 2 , as ISAKMP-peers and IPsec-connections really are handled by the same code inside isakmpd. .It Em ISAKMP-peer The name of the ISAKMP-peer which to talk to in order to set up this connection. The value is the name of an section. See above. .It Em Configuration The name of the IPsec-configuration section to use. Look at below. .It Em Local-ID If existent, the name of the section that describes the optional local client ID that we should present to our peer. It is also used when we act as responders to find out what we are dealing with. Look at below. .It Em Remote-ID If existent, the name of the section that describes the optional remote client ID that we should present to our peer. It is also used when we act as responders to find out what we are dealing with. Look at below. .It Em Flags A comma-separated list of flags controlling the further handling of the IPsec SA. Currently only one flag is defined: .Bl -tag -width 12n .It Em Active-only If this flag is given and this is part of the phase 2 connections we automatically keep up, it will not automatically be used for accepting connections from the peer. .El .El .It Em .Bl -tag -width 12n .It Em DOI The domain of interpretation as given by the RFCs. Normally .Li IPSEC . If unspecified, defaults to .Li IPSEC . .It Em EXCHANGE_TYPE The exchange type as given by the RFCs. For quick mode this is .Li QUICK_MODE . .It Em Suites A list of protection suites (bundles of protocols) usable for protecting the IP traffic. Each of the list elements is a name of an section. See below. .El .It Em .Bl -tag -width 12n .It Em Protocols A list of the protocols included in this protection suite. Each of the list elements is a name of an section. See below. .El .It Em .Bl -tag -width 12n .It Em PROTOCOL_ID The protocol as given by the RFCs. Acceptable values today are .Li IPSEC_AH and .Li IPSEC_ESP . .It Em Transforms A list of transforms usable for implementing the protocol. Each of the list elements is a name of an section. See below. .It Em ReplayWindow The size of the window used for replay protection. This is normally left alone. Look at the .Nm ESP and .Nm AH RFCs for a better description. .El .It Em .Bl -tag -width 12n .It Em TRANSFORM_ID The transform ID as given by the RFCs. .It Em ENCAPSULATION_MODE The encapsulation mode as given by the RFCs. This means TRANSPORT or TUNNEL. .It Em AUTHENTICATION_ALGORITHM The optional authentication algorithm in the case of this being an ESP transform. .It Em GROUP_DESCRIPTION An optional (provides PFS if present) Diffie-Hellman group description. The values are the same as GROUP_DESCRIPTION's in sections shown above. .It Em Life List of lifetimes, each element is a section name. .El .It Em .Bl -tag -width 12n .It Em ID-type The ID type as given by the RFCs. For IPsec this is currently .Li IPV4_ADDR , .Li IPV6_ADDR , .Li IPV4_ADDR_SUBNET or .Li IPV6_ADDR_SUBNET . .It Em Address If the ID-type is .Li IPV4_ADDR or .Li IPV6_ADDR this tag should exist and be an IP-address. .It Em Network If the ID-type is .Li IPV4_ADDR_SUBNET or .Li IPV6_ADDR_SUBNET this tag should exist and be a network address. .It Em Netmask If the ID-type is .Li IPV4_ADDR_SUBNET or .Li IPV6_ADDR_SUBNET this tag should exist and be a network subnet mask. .It Em Protocol If the ID-type is .Li IPV4_ADDR , .Li IPV4_ADDR_SUBNET , .Li IPV6_ADDR or .Li IPV6_ADDR_SUBNET this tag indicates what transport protocol should be transmitted over the SA. If left unspecified, all transport protocols between the two address (ranges) will be sent (or permitted) over that SA. .It Em Port If the ID-type is .Li IPV4_ADDR , .Li IPV4_ADDR_SUBNET , .Li IPV6_ADDR or .Li IPV6_ADDR_SUBNET this tag indicates what source or destination port is allowed to be transported over the SA (depending on whether this is a local or remote ID). If left unspecified, all ports of the given transport protocol will be transmitted (or permitted) over the SA. The Protocol tag must be specified in conjunction with this tag. .El .El .Ss Other sections .Bl -hang -width 12n .It Em Parameters to use with IKE mode-config. One ID per peer. .Pp An IKECFG-ID is written as [/]. The following ID types are supported: .Bl -tag -width 12n .It IPv4 [ipv4/A.B.C.D] .It IPv6 [ipv6/abcd:abcd::ab:cd] .It FQDN [fqdn/foo.bar.org] .It UFQDN [ufqdn/user@foo.bar.org] .It ASN1_DN [asn1_dn//C=aa/O=cc/...] (Note the double slashes as the DN itself starts with a .Sq / . ) .El .Pp Each section specifies what configuration values to return to the peer requesting IKE mode-config. Currently supported values are: .Bl -tag -width 12n .It Em Address The peer's network address. .It Em Netmask The peer's netmask. .It Em Nameserver The IP address of a DNS nameserver. .It Em WINS-server The IP address of a WINS server. .El .It Em .Pp During phase 1 negotiation .Nm isakmpd looks for a pre-shared key in the section. If no Authentication data is specified in that section, and .Nm isakmpd is not the initiator, it looks for Authentication data in a section named after the initiator's phase 1 ID. This allows mobile users with dynamic IP addresses to have different shared secrets. .Pp This only works for aggressive mode because in main mode the remote initiator ID would not yet be known. .Pp The name of the section depends on the ID type sent by the initiator. Currently this can be: .Bl -tag -width 12n .It IPv4 [A.B.C.D] .It IPv6 [abcd:abcd::ab:cd] .It FQDN [foo.bar.org] .It UFQDN [user@foo.bar.org] .El .El .Sh FILES .Bl -tag -width /etc/isakmpd/isakmpd.conf .It Pa /etc/isakmpd/isakmpd.conf The default .Nm isakmpd configuration file. .It Pa /usr/share/ipsec/isakmpd/ A directory containing some sample .Nm isakmpd configuration files. .El .Sh EXAMPLES An example of a configuration file: .Bd -literal # A configuration sample for the isakmpd ISAKMP/Oakley (aka IKE) daemon. [General] Listen-on= 10.1.0.2 # Incoming phase 1 negotiations are multiplexed on the source IP address [Phase 1] 10.1.0.1= ISAKMP-peer-west # These connections are walked over after config file parsing and told # to the application layer so that it will inform us when traffic wants to # pass over them. This means we can do on-demand keying. [Phase 2] Connections= IPsec-east-west # Default values are commented out. [ISAKMP-peer-west] Phase= 1 #Transport= udp Local-address= 10.1.0.2 Address= 10.1.0.1 #Port= isakmp #Port= 500 #Configuration= Default-phase-1-configuration Authentication= mekmitasdigoat #Flags= [IPsec-east-west] Phase= 2 ISAKMP-peer= ISAKMP-peer-west Configuration= Default-quick-mode Local-ID= Net-east Remote-ID= Net-west #Flags= [Net-west] ID-type= IPV4_ADDR_SUBNET Network= 192.168.1.0 Netmask= 255.255.255.0 [Net-east] ID-type= IPV4_ADDR_SUBNET Network= 192.168.2.0 Netmask= 255.255.255.0 # Quick mode descriptions [Default-quick-mode] EXCHANGE_TYPE= QUICK_MODE Suites= QM-ESP-3DES-SHA-PFS-SUITE,QM-ESP-AES-SHA-PFS-SUITE # Data for an IKE mode-config peer [asn1_dn//C=SE/L=SomeCity/O=SomeCompany/CN=SomePeer.company.com] Address= 192.168.1.123 Netmask= 255.255.255.0 Nameserver= 192.168.1.10 WINS-server= 192.168.1.11 # pre-shared key based on initiator's phase 1 ID [foo.bar.org] Authentication= mekmitasdigoat # # ##################################################################### # All configuration data below this point is not required as the example # uses the predefined Main Mode transform and Quick Mode suite names. # It is included here for completeness. Note the default values for the # [General] and [X509-certificates] sections just below. # ##################################################################### # [General] Policy-file= /etc/isakmpd/isakmpd.policy Retransmits= 3 Exchange-max-time= 120 # KeyNote credential storage [KeyNote] Credential-directory= /etc/isakmpd/keynote/ # Certificates stored in PEM format [X509-certificates] CA-directory= /etc/isakmpd/ca/ Cert-directory= /etc/isakmpd/certs/ CRL-directory= /etc/isakmpd/crls/ Private-key= /etc/isakmpd/private/local.key # Default phase 1 description (Main Mode) [Default-phase-1-configuration] EXCHANGE_TYPE= ID_PROT Transforms= 3DES-SHA # Main mode transforms ###################### # DES [DES-MD5] ENCRYPTION_ALGORITHM= DES_CBC HASH_ALGORITHM= MD5 AUTHENTICATION_METHOD= PRE_SHARED GROUP_DESCRIPTION= MODP_1024 Life= Default-phase-1-lifetime [DES-SHA] ENCRYPTION_ALGORITHM= DES_CBC HASH_ALGORITHM= SHA AUTHENTICATION_METHOD= PRE_SHARED GROUP_DESCRIPTION= MODP_1024 Life= Default-phase-1-lifetime # 3DES [3DES-SHA] ENCRYPTION_ALGORITHM= 3DES_CBC HASH_ALGORITHM= SHA AUTHENTICATION_METHOD= PRE_SHARED GROUP_DESCRIPTION= MODP_1024 Life= Default-phase-1-lifetime # Blowfish [BLF-SHA] ENCRYPTION_ALGORITHM= BLOWFISH_CBC KEY_LENGTH= 128,96:192 HASH_ALGORITHM= SHA AUTHENTICATION_METHOD= PRE_SHARED GROUP_DESCRIPTION= MODP_1024 Life= Default-phase-1-lifetime # Blowfish, using DH group 4 (non-default) [BLF-SHA-EC185] ENCRYPTION_ALGORITHM= BLOWFISH_CBC KEY_LENGTH= 128,96:192 HASH_ALGORITHM= SHA AUTHENTICATION_METHOD= PRE_SHARED GROUP_DESCRIPTION= EC2N_185 Life= Default-phase-1-lifetime # Quick mode protection suites ############################## # DES [QM-ESP-DES-SUITE] Protocols= QM-ESP-DES [QM-ESP-DES-PFS-SUITE] Protocols= QM-ESP-DES-PFS [QM-ESP-DES-MD5-SUITE] Protocols= QM-ESP-DES-MD5 [QM-ESP-DES-MD5-PFS-SUITE] Protocols= QM-ESP-DES-MD5-PFS [QM-ESP-DES-SHA-SUITE] Protocols= QM-ESP-DES-SHA [QM-ESP-DES-SHA-PFS-SUITE] Protocols= QM-ESP-DES-SHA-PFS # 3DES [QM-ESP-3DES-SHA-SUITE] Protocols= QM-ESP-3DES-SHA [QM-ESP-3DES-SHA-PFS-SUITE] Protocols= QM-ESP-3DES-SHA-PFS # AES [QM-ESP-AES-SHA-SUITE] Protocols= QM-ESP-AES-SHA [QM-ESP-AES-SHA-PFS-SUITE] Protocols= QM-ESP-AES-SHA-PFS # AH [QM-AH-MD5-SUITE] Protocols= QM-AH-MD5 [QM-AH-MD5-PFS-SUITE] Protocols= QM-AH-MD5-PFS # AH + ESP (non-default) [QM-AH-MD5-ESP-DES-SUITE] Protocols= QM-AH-MD5,QM-ESP-DES [QM-AH-MD5-ESP-DES-MD5-SUITE] Protocols= QM-AH-MD5,QM-ESP-DES-MD5 [QM-ESP-DES-MD5-AH-MD5-SUITE] Protocols= QM-ESP-DES-MD5,QM-AH-MD5 # Quick mode protocols # DES [QM-ESP-DES] PROTOCOL_ID= IPSEC_ESP Transforms= QM-ESP-DES-XF [QM-ESP-DES-MD5] PROTOCOL_ID= IPSEC_ESP Transforms= QM-ESP-DES-MD5-XF [QM-ESP-DES-MD5-PFS] PROTOCOL_ID= IPSEC_ESP Transforms= QM-ESP-DES-MD5-PFS-XF [QM-ESP-DES-SHA] PROTOCOL_ID= IPSEC_ESP Transforms= QM-ESP-DES-SHA-XF # 3DES [QM-ESP-3DES-SHA] PROTOCOL_ID= IPSEC_ESP Transforms= QM-ESP-3DES-SHA-XF [QM-ESP-3DES-SHA-PFS] PROTOCOL_ID= IPSEC_ESP Transforms= QM-ESP-3DES-SHA-PFS-XF [QM-ESP-3DES-SHA-TRP] PROTOCOL_ID= IPSEC_ESP Transforms= QM-ESP-3DES-SHA-TRP-XF # AES [QM-ESP-AES-SHA] PROTOCOL_ID= IPSEC_ESP Transforms= QM-ESP-AES-SHA-XF [QM-ESP-AES-SHA-PFS] PROTOCOL_ID= IPSEC_ESP Transforms= QM-ESP-AES-SHA-PFS-XF [QM-ESP-AES-SHA-TRP] PROTOCOL_ID= IPSEC_ESP Transforms= QM-ESP-AES-SHA-TRP-XF # AH MD5 [QM-AH-MD5] PROTOCOL_ID= IPSEC_AH Transforms= QM-AH-MD5-XF [QM-AH-MD5-PFS] PROTOCOL_ID= IPSEC_AH Transforms= QM-AH-MD5-PFS-XF # Quick mode transforms # ESP DES+MD5 [QM-ESP-DES-XF] TRANSFORM_ID= DES ENCAPSULATION_MODE= TUNNEL Life= Default-phase-2-lifetime [QM-ESP-DES-MD5-XF] TRANSFORM_ID= DES ENCAPSULATION_MODE= TUNNEL AUTHENTICATION_ALGORITHM= HMAC_MD5 Life= Default-phase-2-lifetime [QM-ESP-DES-MD5-PFS-XF] TRANSFORM_ID= DES ENCAPSULATION_MODE= TUNNEL GROUP_DESCRIPTION= MODP_1024 AUTHENTICATION_ALGORITHM= HMAC_MD5 Life= Default-phase-2-lifetime [QM-ESP-DES-SHA-XF] TRANSFORM_ID= DES ENCAPSULATION_MODE= TUNNEL AUTHENTICATION_ALGORITHM= HMAC_SHA Life= Default-phase-2-lifetime # 3DES [QM-ESP-3DES-SHA-XF] TRANSFORM_ID= 3DES ENCAPSULATION_MODE= TUNNEL AUTHENTICATION_ALGORITHM= HMAC_SHA Life= Default-phase-2-lifetime [QM-ESP-3DES-SHA-PFS-XF] TRANSFORM_ID= 3DES ENCAPSULATION_MODE= TUNNEL AUTHENTICATION_ALGORITHM= HMAC_SHA GROUP_DESCRIPTION= MODP_1024 Life= Default-phase-2-lifetime [QM-ESP-3DES-SHA-TRP-XF] TRANSFORM_ID= 3DES ENCAPSULATION_MODE= TRANSPORT AUTHENTICATION_ALGORITHM= HMAC_SHA Life= Default-phase-2-lifetime # AES [QM-ESP-AES-SHA-XF] TRANSFORM_ID= AES ENCAPSULATION_MODE= TUNNEL AUTHENTICATION_ALGORITHM= HMAC_SHA Life= Default-phase-2-lifetime [QM-ESP-AES-SHA-PFS-XF] TRANSFORM_ID= AES ENCAPSULATION_MODE= TUNNEL AUTHENTICATION_ALGORITHM= HMAC_SHA GROUP_DESCRIPTION= MODP_1024 Life= Default-phase-2-lifetime [QM-ESP-AES-SHA-TRP-XF] TRANSFORM_ID= AES ENCAPSULATION_MODE= TRANSPORT AUTHENTICATION_ALGORITHM= HMAC_SHA Life= Default-phase-2-lifetime # AH [QM-AH-MD5-XF] TRANSFORM_ID= MD5 ENCAPSULATION_MODE= TUNNEL AUTHENTICATION_ALGORITHM= HMAC_MD5 Life= Default-phase-2-lifetime [QM-AH-MD5-PFS-XF] TRANSFORM_ID= MD5 ENCAPSULATION_MODE= TUNNEL GROUP_DESCRIPTION= MODP_1024 Life= Default-phase-2-lifetime [Sample-Life-Time] LIFE_TYPE= SECONDS LIFE_DURATION= 3600,1800:7200 [Sample-Life-Volume] LIFE_TYPE= KILOBYTES LIFE_DURATION= 1000,768:1536 .Ed .Sh SEE ALSO .Xr keynote 1 , .Xr ipsec 4 , .Xr keynote 4 , .Xr isakmpd.policy 5 , .Xr isakmpd 8 .Sh BUGS The RFCs do not permit differing DH groups in the same proposal for aggressive and quick mode exchanges. Mixing both PFS and non-PFS suites in a quick mode proposal is not possible, as PFS implies using a DH group. isakmpd-20041012.orig/ike_phase_1.c0000644000175000017500000011633710133045740017104 0ustar jdivejdive00000000000000/* $OpenBSD: ike_phase_1.c,v 1.56 2004/08/08 19:11:06 deraadt Exp $ */ /* $EOM: ike_phase_1.c,v 1.31 2000/12/11 23:47:56 niklas Exp $ */ /* * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2001, 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include "sysdep.h" #include "attribute.h" #include "conf.h" #include "constants.h" #include "crypto.h" #include "dh.h" #include "doi.h" #ifdef USE_DPD #include "dpd.h" #endif #include "exchange.h" #include "hash.h" #include "ike_auth.h" #include "ike_phase_1.h" #include "ipsec.h" #include "ipsec_doi.h" #include "isakmp.h" #include "log.h" #include "math_group.h" #include "message.h" #if defined (USE_NAT_TRAVERSAL) #include "nat_traversal.h" #endif #include "prf.h" #include "sa.h" #include "transport.h" #include "util.h" static int attribute_unacceptable(u_int16_t, u_int8_t *, u_int16_t, void *); static int ike_phase_1_validate_prop(struct exchange *, struct sa *, struct sa *); /* Offer a set of transforms to the responder in the MSG message. */ int ike_phase_1_initiator_send_SA(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; u_int8_t *proposal = 0, *sa_buf = 0, *saved_nextp, *attr; u_int8_t **transform = 0; size_t transforms_len = 0, proposal_len, sa_len; size_t *transform_len = 0; struct conf_list *conf, *life_conf; struct conf_list_node *xf, *life; int value, update_nextp; size_t i; struct payload *p; struct proto *proto; struct proto_attr *pa; int group_desc = -1, new_group_desc; /* Get the list of transforms. */ conf = conf_get_list(exchange->policy, "Transforms"); if (!conf) return -1; transform = calloc(conf->cnt, sizeof *transform); if (!transform) { log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) " "failed", (u_long)conf->cnt, (u_long) sizeof *transform); goto bail_out; } transform_len = calloc(conf->cnt, sizeof *transform_len); if (!transform_len) { log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) " "failed", (u_long)conf->cnt, (u_long) sizeof *transform_len); goto bail_out; } for (xf = TAILQ_FIRST(&conf->fields), i = 0; i < conf->cnt; i++, xf = TAILQ_NEXT(xf, link)) { /* XXX The sizing needs to be dynamic. */ transform[i] = malloc(ISAKMP_TRANSFORM_SA_ATTRS_OFF + 16 * ISAKMP_ATTR_VALUE_OFF); if (!transform[i]) { log_error("ike_phase_1_initiator_send_SA: malloc (%d) " "failed", ISAKMP_TRANSFORM_SA_ATTRS_OFF + 16 * ISAKMP_ATTR_VALUE_OFF); goto bail_out; } SET_ISAKMP_TRANSFORM_NO(transform[i], i); SET_ISAKMP_TRANSFORM_ID(transform[i], IPSEC_TRANSFORM_KEY_IKE); SET_ISAKMP_TRANSFORM_RESERVED(transform[i], 0); attr = transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF; if (attribute_set_constant(xf->field, "ENCRYPTION_ALGORITHM", ike_encrypt_cst, IKE_ATTR_ENCRYPTION_ALGORITHM, &attr)) goto bail_out; if (attribute_set_constant(xf->field, "HASH_ALGORITHM", ike_hash_cst, IKE_ATTR_HASH_ALGORITHM, &attr)) goto bail_out; if (attribute_set_constant(xf->field, "AUTHENTICATION_METHOD", ike_auth_cst, IKE_ATTR_AUTHENTICATION_METHOD, &attr)) goto bail_out; if (attribute_set_constant(xf->field, "GROUP_DESCRIPTION", ike_group_desc_cst, IKE_ATTR_GROUP_DESCRIPTION, &attr)) { /* * If no group description exists, try looking for * a user-defined one. */ if (attribute_set_constant(xf->field, "GROUP_TYPE", ike_group_cst, IKE_ATTR_GROUP_TYPE, &attr)) goto bail_out; #if 0 if (attribute_set_bignum(xf->field, "GROUP_PRIME", IKE_ATTR_GROUP_PRIME, &attr)) goto bail_out; if (attribute_set_bignum(xf->field, "GROUP_GENERATOR_2", IKE_ATTR_GROUP_GENERATOR_2, &attr)) goto bail_out; if (attribute_set_bignum(xf->field, "GROUP_GENERATOR_2", IKE_ATTR_GROUP_GENERATOR_2, &attr)) goto bail_out; if (attribute_set_bignum(xf->field, "GROUP_CURVE_A", IKE_ATTR_GROUP_CURVE_A, &attr)) goto bail_out; if (attribute_set_bignum(xf->field, "GROUP_CURVE_B", IKE_ATTR_GROUP_CURVE_B, &attr)) goto bail_out; #endif } /* * Life durations are special, we should be able to specify * several, one per type. */ life_conf = conf_get_list(xf->field, "Life"); if (life_conf) { for (life = TAILQ_FIRST(&life_conf->fields); life; life = TAILQ_NEXT(life, link)) { attribute_set_constant(life->field, "LIFE_TYPE", ike_duration_cst, IKE_ATTR_LIFE_TYPE, &attr); /* * XXX Deals with 16 and 32 bit lifetimes * only */ value = conf_get_num(life->field, "LIFE_DURATION", 0); if (value) { if (value <= 0xffff) attr = attribute_set_basic( attr, IKE_ATTR_LIFE_DURATION, value); else { value = htonl(value); attr = attribute_set_var(attr, IKE_ATTR_LIFE_DURATION, (u_int8_t *)&value, sizeof value); } } } conf_free_list(life_conf); } attribute_set_constant(xf->field, "PRF", ike_prf_cst, IKE_ATTR_PRF, &attr); value = conf_get_num(xf->field, "KEY_LENGTH", 0); if (value) attr = attribute_set_basic(attr, IKE_ATTR_KEY_LENGTH, value); value = conf_get_num(xf->field, "FIELD_SIZE", 0); if (value) attr = attribute_set_basic(attr, IKE_ATTR_FIELD_SIZE, value); value = conf_get_num(xf->field, "GROUP_ORDER", 0); if (value) attr = attribute_set_basic(attr, IKE_ATTR_GROUP_ORDER, value); /* Record the real transform size. */ transforms_len += transform_len[i] = attr - transform[i]; /* XXX I don't like exchange-specific stuff in here. */ if (exchange->type == ISAKMP_EXCH_AGGRESSIVE) { /* * Make sure that if a group description is specified, * it is specified for all transforms equally. */ attr = (u_int8_t *) conf_get_str(xf->field, "GROUP_DESCRIPTION"); new_group_desc = attr ? constant_value(ike_group_desc_cst, (char *) attr) : 0; if (group_desc == -1) group_desc = new_group_desc; else if (group_desc != new_group_desc) { log_print("ike_phase_1_initiator_send_SA: " "differing group descriptions in a " "proposal"); goto bail_out; } } /* * We need to check that we actually support our * configuration. */ if (attribute_map(transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF, transform_len[i] - ISAKMP_TRANSFORM_SA_ATTRS_OFF, exchange->doi->is_attribute_incompatible, msg)) { log_print("ike_phase_1_initiator_send_SA: " "section [%s] has unsupported attribute(s)", xf->field); goto bail_out; } } /* XXX I don't like exchange-specific stuff in here. */ if (exchange->type == ISAKMP_EXCH_AGGRESSIVE) ie->group = group_get(group_desc); proposal_len = ISAKMP_PROP_SPI_OFF; proposal = malloc(proposal_len); if (!proposal) { log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", (unsigned long) proposal_len); goto bail_out; } SET_ISAKMP_PROP_NO(proposal, 1); SET_ISAKMP_PROP_PROTO(proposal, ISAKMP_PROTO_ISAKMP); SET_ISAKMP_PROP_SPI_SZ(proposal, 0); SET_ISAKMP_PROP_NTRANSFORMS(proposal, conf->cnt); /* XXX I would like to see this factored out. */ proto = calloc(1, sizeof *proto); if (!proto) { log_error("ike_phase_1_initiator_send_SA: " "calloc (1, %lu) failed", (unsigned long) sizeof *proto); goto bail_out; } proto->no = 1; proto->proto = ISAKMP_PROTO_ISAKMP; proto->sa = TAILQ_FIRST(&exchange->sa_list); proto->xf_cnt = conf->cnt; TAILQ_INIT(&proto->xfs); for (i = 0; i < proto->xf_cnt; i++) { pa = (struct proto_attr *) calloc(1, sizeof *pa); if (!pa) goto bail_out; pa->len = transform_len[i]; pa->attrs = (u_int8_t *) malloc(pa->len); if (!pa->attrs) { free(pa); goto bail_out; } memcpy(pa->attrs, transform[i], pa->len); TAILQ_INSERT_TAIL(&proto->xfs, pa, next); } TAILQ_INSERT_TAIL(&TAILQ_FIRST(&exchange->sa_list)->protos, proto, link); sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN; sa_buf = malloc(sa_len); if (!sa_buf) { log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", (unsigned long) sa_len); goto bail_out; } SET_ISAKMP_SA_DOI(sa_buf, IPSEC_DOI_IPSEC); SET_IPSEC_SIT_SIT(sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY); /* * Add the payloads. As this is a SA, we need to recompute the * lengths of the payloads containing others. */ if (message_add_payload(msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1)) goto bail_out; SET_ISAKMP_GEN_LENGTH(sa_buf, sa_len + proposal_len + transforms_len); sa_buf = 0; saved_nextp = msg->nextp; if (message_add_payload(msg, ISAKMP_PAYLOAD_PROPOSAL, proposal, proposal_len, 0)) goto bail_out; SET_ISAKMP_GEN_LENGTH(proposal, proposal_len + transforms_len); proposal = 0; update_nextp = 0; for (i = 0; i < conf->cnt; i++) { if (message_add_payload(msg, ISAKMP_PAYLOAD_TRANSFORM, transform[i], transform_len[i], update_nextp)) goto bail_out; update_nextp = 1; transform[i] = 0; } msg->nextp = saved_nextp; /* Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len. */ ie->sa_i_b_len = sa_len + proposal_len + transforms_len - ISAKMP_GEN_SZ; ie->sa_i_b = malloc(ie->sa_i_b_len); if (!ie->sa_i_b) { log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", (unsigned long) ie->sa_i_b_len); goto bail_out; } memcpy(ie->sa_i_b, payload_first(msg, ISAKMP_PAYLOAD_SA)->p + ISAKMP_GEN_SZ, sa_len - ISAKMP_GEN_SZ); memcpy(ie->sa_i_b + sa_len - ISAKMP_GEN_SZ, payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL)->p, proposal_len); transforms_len = 0; for (i = 0, p = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM); i < conf->cnt; i++, p = TAILQ_NEXT(p, link)) { memcpy(ie->sa_i_b + sa_len + proposal_len + transforms_len - ISAKMP_GEN_SZ, p->p, transform_len[i]); transforms_len += transform_len[i]; } #if defined (USE_NAT_TRAVERSAL) /* Advertise NAT-T capability. */ if (nat_t_add_vendor_payloads(msg)) goto bail_out; #endif #if defined (USE_DPD) /* Advertise DPD capability. */ if (dpd_add_vendor_payload(msg)) goto bail_out; #endif conf_free_list(conf); free(transform); free(transform_len); return 0; bail_out: if (sa_buf) free(sa_buf); if (proposal) free(proposal); if (transform) { for (i = 0; i < conf->cnt; i++) if (transform[i]) free(transform[i]); free(transform); } if (transform_len) free(transform_len); conf_free_list(conf); return -1; } /* Figure out what transform the responder chose. */ int ike_phase_1_initiator_recv_SA(struct message *msg) { struct exchange *exchange = msg->exchange; struct sa *sa = TAILQ_FIRST(&exchange->sa_list); struct ipsec_exch *ie = exchange->data; struct ipsec_sa *isa = sa->data; struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA); struct payload *prop = payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL); struct payload *xf = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM); /* * IKE requires that only one SA with only one proposal exists and * since we are getting an answer on our transform offer, only one * transform. */ if (TAILQ_NEXT(sa_p, link) || TAILQ_NEXT(prop, link) || TAILQ_NEXT(xf, link)) { log_print("ike_phase_1_initiator_recv_SA: " "multiple SA, proposal or transform payloads in phase 1"); /* XXX Is there a better notification type? */ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } /* Check that the chosen transform matches an offer. */ if (message_negotiate_sa(msg, ike_phase_1_validate_prop) || !TAILQ_FIRST(&sa->protos)) return -1; ipsec_decode_transform(msg, sa, TAILQ_FIRST(&sa->protos), xf->p); /* XXX I don't like exchange-specific stuff in here. */ if (exchange->type != ISAKMP_EXCH_AGGRESSIVE) ie->group = group_get(isa->group_desc); /* Mark the SA as handled. */ sa_p->flags |= PL_MARK; return 0; } /* Send our public DH value and a nonce to the responder. */ int ike_phase_1_initiator_send_KE_NONCE(struct message *msg) { struct ipsec_exch *ie = msg->exchange->data; ie->g_x_len = dh_getlen(ie->group); /* XXX I want a better way to specify the nonce's size. */ return ike_phase_1_send_KE_NONCE(msg, 16); } /* Accept responder's public DH value and nonce. */ int ike_phase_1_initiator_recv_KE_NONCE(struct message *msg) { if (ike_phase_1_recv_KE_NONCE(msg)) return -1; return ike_phase_1_post_exchange_KE_NONCE(msg); } /* * Accept a set of transforms offered by the initiator and chose one we can * handle. */ int ike_phase_1_responder_recv_SA(struct message *msg) { struct exchange *exchange = msg->exchange; struct sa *sa = TAILQ_FIRST(&exchange->sa_list); struct ipsec_sa *isa = sa->data; struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA); struct payload *prop = payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL); struct ipsec_exch *ie = exchange->data; /* Mark the SA as handled. */ sa_p->flags |= PL_MARK; /* IKE requires that only one SA with only one proposal exists. */ if (TAILQ_NEXT(sa_p, link) || TAILQ_NEXT(prop, link)) { log_print("ike_phase_1_responder_recv_SA: " "multiple SA or proposal payloads in phase 1"); /* XXX Is there a better notification type? */ message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } /* Chose a transform from the SA. */ if (message_negotiate_sa(msg, ike_phase_1_validate_prop) || !TAILQ_FIRST(&sa->protos)) return -1; /* XXX Move into message_negotiate_sa? */ ipsec_decode_transform(msg, sa, TAILQ_FIRST(&sa->protos), TAILQ_FIRST(&sa->protos)->chosen->p); ie->group = group_get(isa->group_desc); /* * Check that the mandatory attributes: encryption, hash, * authentication method and Diffie-Hellman group description, has * been supplied. */ if (!exchange->crypto || !ie->hash || !ie->ike_auth || !ie->group) { message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED, 0, 1, 0); return -1; } /* Save the body for later hash computation. */ ie->sa_i_b_len = GET_ISAKMP_GEN_LENGTH(sa_p->p) - ISAKMP_GEN_SZ; ie->sa_i_b = malloc(ie->sa_i_b_len); if (!ie->sa_i_b) { /* XXX How to notify peer? */ log_error("ike_phase_1_responder_recv_SA: malloc (%lu) failed", (unsigned long) ie->sa_i_b_len); return -1; } memcpy(ie->sa_i_b, sa_p->p + ISAKMP_GEN_SZ, ie->sa_i_b_len); return 0; } /* Reply with the transform we chose. */ int ike_phase_1_responder_send_SA(struct message *msg) { /* Add the SA payload with the transform that was chosen. */ if (message_add_sa_payload(msg)) return -1; #if defined (USE_NAT_TRAVERSAL) /* Advertise NAT-T capability. */ if (nat_t_add_vendor_payloads(msg)) return -1; #endif #if defined (USE_DPD) /* Advertise DPD capability. */ if (dpd_add_vendor_payload(msg)) return -1; #endif return 0; } /* Send our public DH value and a nonce to the peer. */ int ike_phase_1_send_KE_NONCE(struct message *msg, size_t nonce_sz) { /* Public DH key. */ if (ipsec_gen_g_x(msg)) { /* XXX How to log and notify peer? */ return -1; } /* Generate a nonce, and add it to the message. */ if (exchange_gen_nonce(msg, nonce_sz)) { /* XXX Log? */ return -1; } /* Try to add certificates which are acceptable for the CERTREQs */ if (exchange_add_certs(msg)) { /* XXX Log? */ return -1; } #if defined (USE_NAT_TRAVERSAL) /* If this exchange uses NAT-Traversal, add NAT-D payloads now. */ if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER) if (nat_t_exchange_add_nat_d(msg)) { /* XXX Log? */ return -1; } #endif return 0; } /* Receive our peer's public DH value and nonce. */ int ike_phase_1_recv_KE_NONCE(struct message *msg) { /* Copy out the initiator's DH public value. */ if (ipsec_save_g_x(msg)) { /* XXX How to log and notify peer? */ return -1; } /* Copy out the initiator's nonce. */ if (exchange_save_nonce(msg)) { /* XXX How to log and notify peer? */ return -1; } /* Copy out the initiator's cert requests. */ if (exchange_save_certreq(msg)) { /* XXX How to log and notify peer? */ return -1; } #if defined (USE_NAT_TRAVERSAL) /* MainMode: Check for NAT-D payloads and contents. */ if (msg->exchange->type == ISAKMP_EXCH_ID_PROT && msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER) (void)nat_t_exchange_check_nat_d(msg); #endif return 0; } /* * Compute DH values and key material. This is done in a post-send function * as that means we can do parallel work in both the initiator and responder * thus speeding up exchanges. */ int ike_phase_1_post_exchange_KE_NONCE(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct prf *prf; struct hash *hash = ie->hash; enum cryptoerr err; /* Compute Diffie-Hellman shared value. */ ie->g_xy = malloc(ie->g_x_len); if (!ie->g_xy) { /* XXX How to notify peer? */ log_error("ike_phase_1_post_exchange_KE_NONCE: " "malloc (%lu) failed", (unsigned long) ie->g_x_len); return -1; } if (dh_create_shared(ie->group, ie->g_xy, exchange->initiator ? ie->g_xr : ie->g_xi)) { log_print("ike_phase_1_post_exchange_KE_NONCE: " "dh_create_shared failed"); return -1; } LOG_DBG_BUF((LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: g^xy", ie->g_xy, ie->g_x_len)); /* Compute the SKEYID depending on the authentication method. */ ie->skeyid = ie->ike_auth->gen_skeyid(exchange, &ie->skeyid_len); if (!ie->skeyid) { /* XXX Log and teardown? */ return -1; } LOG_DBG_BUF((LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID", ie->skeyid, ie->skeyid_len)); /* SKEYID_d. */ ie->skeyid_d = malloc(ie->skeyid_len); if (!ie->skeyid_d) { /* XXX How to notify peer? */ log_error("ike_phase_1_post_exchange_KE_NONCE: " "malloc (%lu) failed", (unsigned long) ie->skeyid_len); return -1; } prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len); if (!prf) { /* XXX Log and teardown? */ return -1; } prf->Init(prf->prfctx); prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len); prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN); prf->Update(prf->prfctx, (unsigned char *) "\0", 1); prf->Final(ie->skeyid_d, prf->prfctx); LOG_DBG_BUF((LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d", ie->skeyid_d, ie->skeyid_len)); /* SKEYID_a. */ ie->skeyid_a = malloc(ie->skeyid_len); if (!ie->skeyid_a) { log_error("ike_phase_1_post_exchange_KE_NONCE: " "malloc (%lu) failed", (unsigned long) ie->skeyid_len); prf_free(prf); return -1; } prf->Init(prf->prfctx); prf->Update(prf->prfctx, ie->skeyid_d, ie->skeyid_len); prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len); prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN); prf->Update(prf->prfctx, (unsigned char *) "\1", 1); prf->Final(ie->skeyid_a, prf->prfctx); LOG_DBG_BUF((LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a", ie->skeyid_a, ie->skeyid_len)); /* SKEYID_e. */ ie->skeyid_e = malloc(ie->skeyid_len); if (!ie->skeyid_e) { /* XXX How to notify peer? */ log_error("ike_phase_1_post_exchange_KE_NONCE: " "malloc (%lu) failed", (unsigned long) ie->skeyid_len); prf_free(prf); return -1; } prf->Init(prf->prfctx); prf->Update(prf->prfctx, ie->skeyid_a, ie->skeyid_len); prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len); prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN); prf->Update(prf->prfctx, (unsigned char *) "\2", 1); prf->Final(ie->skeyid_e, prf->prfctx); prf_free(prf); LOG_DBG_BUF((LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e", ie->skeyid_e, ie->skeyid_len)); /* Key length determination. */ if (!exchange->key_length) exchange->key_length = exchange->crypto->keymax; /* Derive a longer key from skeyid_e */ if (ie->skeyid_len < exchange->key_length) { u_int16_t len, keylen; u_int8_t *key, *p; prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid_e, ie->skeyid_len); if (!prf) { /* XXX - notify peer */ return -1; } /* Make keylen a multiple of prf->blocksize */ keylen = exchange->key_length; if (keylen % prf->blocksize) keylen += prf->blocksize - (keylen % prf->blocksize); key = malloc(keylen); if (!key) { /* XXX - Notify peer. */ log_error("ike_phase_1_post_exchange_KE_NONCE: " "malloc (%d) failed", keylen); return -1; } prf->Init(prf->prfctx); prf->Update(prf->prfctx, (unsigned char *) "\0", 1); prf->Final(key, prf->prfctx); for (len = prf->blocksize, p = key; len < exchange->key_length; len += prf->blocksize, p += prf->blocksize) { prf->Init(prf->prfctx); prf->Update(prf->prfctx, p, prf->blocksize); prf->Final(p + prf->blocksize, prf->prfctx); } prf_free(prf); /* Setup our keystate using the derived encryption key. */ exchange->keystate = crypto_init(exchange->crypto, key, exchange->key_length, &err); free(key); } else /* Setup our keystate using the raw skeyid_e. */ exchange->keystate = crypto_init(exchange->crypto, ie->skeyid_e, exchange->key_length, &err); /* Special handling for DES weak keys. */ if (!exchange->keystate && err == EWEAKKEY && (exchange->key_length << 1) <= ie->skeyid_len) { log_print("ike_phase_1_post_exchange_KE_NONCE: " "weak key, trying subseq. skeyid_e"); exchange->keystate = crypto_init(exchange->crypto, ie->skeyid_e + exchange->key_length, exchange->key_length, &err); } if (!exchange->keystate) { log_print("ike_phase_1_post_exchange_KE_NONCE: " "exchange->crypto->init () failed: %d", err); /* * XXX We really need to know if problems are of transient * nature or fatal (like failed assertions etc.) */ return -1; } /* Setup IV. XXX Only for CBC transforms, no? */ hash->Init(hash->ctx); hash->Update(hash->ctx, ie->g_xi, ie->g_x_len); hash->Update(hash->ctx, ie->g_xr, ie->g_x_len); hash->Final(hash->digest, hash->ctx); crypto_init_iv(exchange->keystate, hash->digest, exchange->crypto->blocksize); return 0; } int ike_phase_1_responder_send_ID_AUTH(struct message *msg) { if (ike_phase_1_send_ID(msg)) return -1; return ike_phase_1_send_AUTH(msg); } int ike_phase_1_send_ID(struct message *msg) { struct exchange *exchange = msg->exchange; u_int8_t *buf; char header[80]; ssize_t sz; struct sockaddr *src; int initiator = exchange->initiator; u_int8_t **id; size_t *id_len; char *my_id = 0, *data; u_int8_t id_type; /* Choose the right fields to fill-in. */ id = initiator ? &exchange->id_i : &exchange->id_r; id_len = initiator ? &exchange->id_i_len : &exchange->id_r_len; if (exchange->name) my_id = conf_get_str(exchange->name, "ID"); if (!my_id) my_id = conf_get_str("General", "Default-phase-1-ID"); msg->transport->vtbl->get_src(msg->transport, &src); sz = my_id ? ipsec_id_size(my_id, &id_type) : sockaddr_addrlen(src); if (sz == -1) return -1; sz += ISAKMP_ID_DATA_OFF; buf = malloc(sz); if (!buf) { log_error("ike_phase_1_send_ID: malloc (%lu) failed", (unsigned long) sz); return -1; } SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0); SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0); if (my_id) { SET_ISAKMP_ID_TYPE(buf, id_type); switch (id_type) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: /* Already in network byteorder. */ memcpy(buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src), sockaddr_addrlen(src)); break; case IPSEC_ID_IPV4_ADDR_SUBNET: case IPSEC_ID_IPV6_ADDR_SUBNET: /* Network */ data = conf_get_str(my_id, "Network"); if (!data) { log_print("ike_phase_1_send_ID: section %s " "has no \"Network\" tag", my_id); return -1; } if (text2sockaddr(data, NULL, &src)) { log_error("ike_phase_1_send_ID: " "text2sockaddr() failed"); return -1; } memcpy(buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src), sockaddr_addrlen(src)); free(src); /* Netmask */ data = conf_get_str(my_id, "Netmask"); if (!data) { log_print("ike_phase_1_send_ID: section %s " "has no \"Netmask\" tag", my_id); return -1; } if (text2sockaddr(data, NULL, &src)) { log_error("ike_phase_1_send_ID: " "text2sockaddr() failed"); return -1; } memcpy(buf + ISAKMP_ID_DATA_OFF + sockaddr_addrlen(src), sockaddr_addrdata(src), sockaddr_addrlen(src)); free(src); break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: case IPSEC_ID_KEY_ID: data = conf_get_str(my_id, "Name"); if (!data) { log_print("ike_phase_1_send_ID: section %s " "has no \"Name\" tag", my_id); return -1; } memcpy(buf + ISAKMP_ID_DATA_OFF, data, sz - ISAKMP_ID_DATA_OFF); break; default: log_print("ike_phase_1_send_ID: " "unsupported ID type %d", id_type); free(buf); return -1; } } else { switch (src->sa_family) { case AF_INET: SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR); break; case AF_INET6: SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR); break; } /* Already in network byteorder. */ memcpy(buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata(src), sockaddr_addrlen(src)); } if (message_add_payload(msg, ISAKMP_PAYLOAD_ID, buf, sz, 1)) { free(buf); return -1; } *id_len = sz - ISAKMP_GEN_SZ; *id = malloc(*id_len); if (!*id) { log_error("ike_phase_1_send_ID: malloc (%lu) failed", (unsigned long) *id_len); return -1; } memcpy(*id, buf + ISAKMP_GEN_SZ, *id_len); snprintf(header, sizeof header, "ike_phase_1_send_ID: %s", constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(buf))); LOG_DBG_BUF((LOG_NEGOTIATION, 40, header, buf + ISAKMP_ID_DATA_OFF, sz - ISAKMP_ID_DATA_OFF)); return 0; } int ike_phase_1_send_AUTH(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; if (ie->ike_auth->encode_hash(msg)) { /* XXX Log? */ return -1; } /* * XXX Many people say the COMMIT flag is just junk, especially in * Phase 1. */ #ifdef notyet if ((exchange->flags & EXCHANGE_FLAG_COMMITTED) == 0) exchange->flags |= EXCHANGE_FLAG_I_COMMITTED; #endif return 0; } /* Receive ID and HASH and check that the exchange has been consistent. */ int ike_phase_1_recv_ID_AUTH(struct message *msg) { if (ike_phase_1_recv_ID(msg)) return -1; return ike_phase_1_recv_AUTH(msg); } /* Receive ID. */ int ike_phase_1_recv_ID(struct message *msg) { struct exchange *exchange = msg->exchange; struct payload *payload; char header[80], *rs = 0, *rid = 0, *p; int initiator = exchange->initiator; u_int8_t **id, id_type; size_t *id_len; ssize_t sz; struct sockaddr *sa; payload = payload_first(msg, ISAKMP_PAYLOAD_ID); if (exchange->name) rs = conf_get_str(exchange->name, "Remote-ID"); if (rs) { sz = ipsec_id_size(rs, &id_type); if (sz == -1) { log_print("ike_phase_1_recv_ID: could not handle " "specified Remote-ID [%s]", rs); return -1; } rid = malloc(sz); if (!rid) { log_error("ike_phase_1_recv_ID: malloc (%lu) failed", (unsigned long) sz); return -1; } switch (id_type) { case IPSEC_ID_IPV4_ADDR: case IPSEC_ID_IPV6_ADDR: p = conf_get_str(rs, "Address"); if (!p) { log_print("ike_phase_1_recv_ID: failed to get " "Address in Remote-ID section [%s]", rs); free(rid); return -1; } if (text2sockaddr(p, 0, &sa) == -1) { log_print("ike_phase_1_recv_ID: " "failed to parse address %s", p); free(rid); return -1; } if ((id_type == IPSEC_ID_IPV4_ADDR && sa->sa_family != AF_INET) || (id_type == IPSEC_ID_IPV6_ADDR && sa->sa_family != AF_INET6)) { log_print("ike_phase_1_recv_ID: " "address %s not of expected family", p); free(rid); free(sa); return -1; } memcpy(rid, sockaddr_addrdata(sa), sockaddr_addrlen(sa)); free(sa); break; case IPSEC_ID_FQDN: case IPSEC_ID_USER_FQDN: case IPSEC_ID_KEY_ID: p = conf_get_str(rs, "Name"); if (!p) { log_print("ike_phase_1_recv_ID: failed to " "get Name in Remote-ID section [%s]", rs); free(rid); return -1; } memcpy(rid, p, sz); break; default: log_print("ike_phase_1_recv_ID: " "unsupported ID type %d", id_type); free(rid); return -1; } /* Compare expected/desired and received remote ID */ if (bcmp(rid, payload->p + ISAKMP_ID_DATA_OFF, sz)) { free(rid); log_print("ike_phase_1_recv_ID: " "received remote ID other than expected %s", p); return -1; } free(rid); } /* Choose the right fields to fill in */ id = initiator ? &exchange->id_r : &exchange->id_i; id_len = initiator ? &exchange->id_r_len : &exchange->id_i_len; *id_len = GET_ISAKMP_GEN_LENGTH(payload->p) - ISAKMP_GEN_SZ; *id = malloc(*id_len); if (!*id) { log_error("ike_phase_1_recv_ID: malloc (%lu) failed", (unsigned long) *id_len); return -1; } memcpy(*id, payload->p + ISAKMP_GEN_SZ, *id_len); snprintf(header, sizeof header, "ike_phase_1_recv_ID: %s", constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(payload->p))); LOG_DBG_BUF((LOG_NEGOTIATION, 40, header, payload->p + ISAKMP_ID_DATA_OFF, *id_len + ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF)); payload->flags |= PL_MARK; return 0; } /* Receive HASH and check that the exchange has been consistent. */ int ike_phase_1_recv_AUTH(struct message *msg) { struct exchange *exchange = msg->exchange; struct ipsec_exch *ie = exchange->data; struct prf *prf; struct hash *hash = ie->hash; char header[80]; size_t hashsize = hash->hashsize; int initiator = exchange->initiator; u_int8_t **hash_p, *id; size_t id_len; /* Choose the right fields to fill in */ hash_p = initiator ? &ie->hash_r : &ie->hash_i; id = initiator ? exchange->id_r : exchange->id_i; id_len = initiator ? exchange->id_r_len : exchange->id_i_len; /* The decoded hash will be in ie->hash_r or ie->hash_i */ if (ie->ike_auth->decode_hash(msg)) { message_drop(msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION, 0, 1, 0); return -1; } /* Allocate the prf and start calculating his HASH. */ prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len); if (!prf) { /* XXX Log? */ return -1; } prf->Init(prf->prfctx); prf->Update(prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len); prf->Update(prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len); prf->Update(prf->prfctx, exchange->cookies + (initiator ? ISAKMP_HDR_RCOOKIE_OFF : ISAKMP_HDR_ICOOKIE_OFF), ISAKMP_HDR_ICOOKIE_LEN); prf->Update(prf->prfctx, exchange->cookies + (initiator ? ISAKMP_HDR_ICOOKIE_OFF : ISAKMP_HDR_RCOOKIE_OFF), ISAKMP_HDR_ICOOKIE_LEN); prf->Update(prf->prfctx, ie->sa_i_b, ie->sa_i_b_len); prf->Update(prf->prfctx, id, id_len); prf->Final(hash->digest, prf->prfctx); prf_free(prf); snprintf(header, sizeof header, "ike_phase_1_recv_AUTH: " "computed HASH_%c", initiator ? 'R' : 'I'); LOG_DBG_BUF((LOG_NEGOTIATION, 80, header, hash->digest, hashsize)); /* Check that the hash we got matches the one we computed. */ if (memcmp(*hash_p, hash->digest, hashsize) != 0) { /* XXX Log? */ return -1; } /* Mark message as authenticated. */ msg->flags |= MSG_AUTHENTICATED; return 0; } struct attr_node { LIST_ENTRY(attr_node) link; u_int16_t type; }; struct validation_state { struct conf_list_node *xf; LIST_HEAD(attr_head, attr_node) attrs; char *life; }; /* Validate a proposal inside SA according to EXCHANGE's policy. */ static int ike_phase_1_validate_prop(struct exchange *exchange, struct sa *sa, struct sa *isakmp_sa) { struct conf_list *conf, *tags; struct conf_list_node *xf, *tag; struct proto *proto; struct validation_state vs; struct attr_node *node, *next_node; /* Get the list of transforms. */ conf = conf_get_list(exchange->policy, "Transforms"); if (!conf) return 0; for (xf = TAILQ_FIRST(&conf->fields); xf; xf = TAILQ_NEXT(xf, link)) { for (proto = TAILQ_FIRST(&sa->protos); proto; proto = TAILQ_NEXT(proto, link)) { /* Mark all attributes in our policy as unseen. */ LIST_INIT(&vs.attrs); vs.xf = xf; vs.life = 0; if (attribute_map(proto->chosen->p + ISAKMP_TRANSFORM_SA_ATTRS_OFF, GET_ISAKMP_GEN_LENGTH(proto->chosen->p) - ISAKMP_TRANSFORM_SA_ATTRS_OFF, attribute_unacceptable, &vs)) goto try_next; /* Sweep over unseen tags in this section. */ tags = conf_get_tag_list(xf->field); if (tags) { for (tag = TAILQ_FIRST(&tags->fields); tag; tag = TAILQ_NEXT(tag, link)) /* * XXX Should we care about attributes * we have, they do not provide? */ for (node = LIST_FIRST(&vs.attrs); node; node = next_node) { next_node = LIST_NEXT(node, link); if (node->type == constant_value(ike_attr_cst, tag->field)) { LIST_REMOVE(node, link); free(node); } } conf_free_list(tags); } /* Are there leftover tags in this section? */ node = LIST_FIRST(&vs.attrs); if (node) goto try_next; } /* All protocols were OK, we succeeded. */ LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: " "success")); conf_free_list(conf); if (vs.life) free(vs.life); return 1; try_next: /* Are there leftover tags in this section? */ node = LIST_FIRST(&vs.attrs); while (node) { LIST_REMOVE(node, link); free(node); node = LIST_FIRST(&vs.attrs); } if (vs.life) free(vs.life); } LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: failure")); conf_free_list(conf); return 0; } /* * Look at the attribute of type TYPE, located at VALUE for LEN bytes forward. * The VVS argument holds a validation state kept across invocations. * If the attribute is unacceptable to use, return non-zero, otherwise zero. */ static int attribute_unacceptable(u_int16_t type, u_int8_t *value, u_int16_t len, void *vvs) { struct validation_state *vs = vvs; struct conf_list *life_conf; struct conf_list_node *xf = vs->xf, *life; char *tag = constant_lookup(ike_attr_cst, type); char *str; struct constant_map *map; struct attr_node *node; int rv; if (!tag) { LOG_DBG((LOG_NEGOTIATION, 60, "attribute_unacceptable: " "attribute type %d not known", type)); return 1; } switch (type) { case IKE_ATTR_ENCRYPTION_ALGORITHM: case IKE_ATTR_HASH_ALGORITHM: case IKE_ATTR_AUTHENTICATION_METHOD: case IKE_ATTR_GROUP_DESCRIPTION: case IKE_ATTR_GROUP_TYPE: case IKE_ATTR_PRF: str = conf_get_str(xf->field, tag); if (!str) { /* This attribute does not exist in this policy. */ LOG_DBG((LOG_NEGOTIATION, 70, "attribute_unacceptable: attr %s does not exist " "in %s", tag, xf->field)); return 1; } map = constant_link_lookup(ike_attr_cst, type); if (!map) return 1; if ((constant_value(map, str) == decode_16(value)) || (!strcmp(str, "ANY"))) { /* Mark this attribute as seen. */ node = malloc(sizeof *node); if (!node) { log_error("attribute_unacceptable: " "malloc (%lu) failed", (unsigned long) sizeof *node); return 1; } node->type = type; LIST_INSERT_HEAD(&vs->attrs, node, link); return 0; } LOG_DBG((LOG_NEGOTIATION, 70, "attribute_unacceptable: %s: got %s, expected %s", tag, constant_name(map, decode_16(value)), str)); return 1; case IKE_ATTR_GROUP_PRIME: case IKE_ATTR_GROUP_GENERATOR_1: case IKE_ATTR_GROUP_GENERATOR_2: case IKE_ATTR_GROUP_CURVE_A: case IKE_ATTR_GROUP_CURVE_B: /* XXX Bignums not handled yet. */ return 1; case IKE_ATTR_LIFE_TYPE: case IKE_ATTR_LIFE_DURATION: life_conf = conf_get_list(xf->field, "Life"); if (life_conf && !strcmp(conf_get_str(xf->field, "Life"), "ANY")) return 0; rv = 1; if (!life_conf) { /* Life attributes given, but not in our policy. */ LOG_DBG((LOG_NEGOTIATION, 70, "attribute_unacceptable: received unexpected life " "attribute")); return 1; } /* * Each lifetime type must match, otherwise we turn the * proposal down. In order to do this we need to find the * specific section of our policy's "Life" list and match * its duration. */ switch (type) { case IKE_ATTR_LIFE_TYPE: for (life = TAILQ_FIRST(&life_conf->fields); life; life = TAILQ_NEXT(life, link)) { str = conf_get_str(life->field, "LIFE_TYPE"); if (!str) { LOG_DBG((LOG_NEGOTIATION, 70, "attribute_unacceptable: " "section [%s] has no LIFE_TYPE", life->field)); continue; } /* * If this is the type we are looking at, * to save a pointer this section in vs->life. */ if (constant_value(ike_duration_cst, str) == decode_16(value)) { vs->life = strdup(life->field); rv = 0; goto bail_out; } } LOG_DBG((LOG_NEGOTIATION, 70, "attribute_unacceptable:" " unrecognized LIFE_TYPE %d", decode_16(value))); vs->life = 0; break; case IKE_ATTR_LIFE_DURATION: if (!vs->life) { LOG_DBG((LOG_NEGOTIATION, 70, "attribute_unacceptable: " "LIFE_DURATION without LIFE_TYPE")); rv = 1; goto bail_out; } str = conf_get_str(vs->life, "LIFE_DURATION"); if (str) { if (!strcmp(str, "ANY")) rv = 0; else rv = !conf_match_num(vs->life, "LIFE_DURATION", len == 4 ? decode_32(value) : decode_16(value)); } else { LOG_DBG((LOG_NEGOTIATION, 70, "attribute_unacceptable: section [%s] has " "no LIFE_DURATION", vs->life)); rv = 1; } free(vs->life); vs->life = 0; break; } bail_out: conf_free_list(life_conf); return rv; case IKE_ATTR_KEY_LENGTH: case IKE_ATTR_FIELD_SIZE: case IKE_ATTR_GROUP_ORDER: if (conf_match_num(xf->field, tag, decode_16(value))) { /* Mark this attribute as seen. */ node = malloc(sizeof *node); if (!node) { log_error("attribute_unacceptable: " "malloc (%lu) failed", (unsigned long) sizeof *node); return 1; } node->type = type; LIST_INSERT_HEAD(&vs->attrs, node, link); return 0; } return 1; } return 1; } isakmpd-20041012.orig/.depend0000644000175000017500000002540510133045740016023 0ustar jdivejdive00000000000000app.o: app.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ app.h log.h attribute.o: attribute.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ attribute.h conf.h log.h isakmp.h isakmp_fld.h field.h isakmp_num.h \ constants.h util.h cert.o: cert.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ isakmp_num.h constants.h log.h cert.h connection.o: connection.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ conf.h connection.h doi.h ipsec.h ipsec_doi.h ipsec_fld.h field.h \ ipsec_num.h constants.h isakmp.h isakmp_fld.h isakmp_num.h log.h \ timer.h util.h constants.o: constants.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ constants.h conf.o: conf.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ app.h conf.h log.h util.h cookie.o: cookie.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ cookie.h exchange.h exchange_num.h constants.h isakmp.h isakmp_fld.h \ field.h isakmp_num.h hash.h transport.h message.h util.h crypto.o: crypto.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ crypto.h log.h dh.o: dh.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ math_group.h dh.h log.h doi.o: doi.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ doi.h exchange.o: exchange.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ cert.h conf.h connection.h constants.h cookie.h crypto.h doi.h \ exchange.h exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h \ ipsec_num.h libcrypto.h log.h message.h timer.h transport.h ipsec.h \ ipsec_doi.h ipsec_fld.h sa.h util.h key.h exchange_num.o: exchange_num.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ constants.h exchange_num.h field.o: field.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ constants.h field.h log.h util.h gmp_util.o: gmp_util.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ gmp_util.h math_mp.h hash.o: hash.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ hash.h log.h if.o: if.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ log.h if.h ike_auth.o: ike_auth.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ cert.h conf.h constants.h exchange.h exchange_num.h isakmp.h \ isakmp_fld.h field.h isakmp_num.h gmp_util.h math_mp.h hash.h \ ike_auth.h ipsec.h ipsec_doi.h ipsec_fld.h ipsec_num.h libcrypto.h \ log.h message.h prf.h transport.h util.h key.h ike_main_mode.o: ike_main_mode.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \ exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \ ike_auth.h ike_main_mode.h ike_phase_1.h ipsec.h ipsec_doi.h \ ipsec_fld.h ipsec_num.h log.h math_group.h message.h prf.h sa.h \ transport.h util.h ike_phase_1.o: ike_phase_1.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \ exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \ ike_auth.h ike_phase_1.h ipsec.h ipsec_doi.h ipsec_fld.h ipsec_num.h \ log.h math_group.h message.h prf.h sa.h transport.h util.h ike_quick_mode.o: ike_quick_mode.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ attribute.h conf.h connection.h dh.h doi.h exchange.h exchange_num.h \ constants.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \ ike_quick_mode.h ipsec.h ipsec_doi.h ipsec_fld.h ipsec_num.h log.h \ math_group.h message.h policy.h prf.h sa.h transport.h util.h key.h init.o: init.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ app.h cert.h conf.h connection.h doi.h exchange.h exchange_num.h \ constants.h isakmp.h isakmp_fld.h field.h isakmp_num.h init.h ipsec.h \ ipsec_doi.h ipsec_fld.h ipsec_num.h isakmp_doi.h libcrypto.h log.h \ math_group.h sa.h timer.h transport.h message.h udp.h ui.h util.h ipsec.o: ipsec.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \ exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \ ike_aggressive.h ike_auth.h ike_main_mode.h ike_quick_mode.h ipsec.h \ ipsec_doi.h ipsec_fld.h ipsec_num.h isakmp_cfg.h log.h math_group.h \ message.h prf.h sa.h timer.h transport.h util.h x509.h libcrypto.h ipsec_fld.o: ipsec_fld.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ constants.h field.h ipsec_fld.h isakmp_num.h ipsec_num.h ipsec_num.o: ipsec_num.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ constants.h ipsec_num.h isakmpd.o: isakmpd.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ app.h conf.h connection.h init.h libcrypto.h log.h sa.h isakmp.h \ isakmp_fld.h field.h isakmp_num.h constants.h timer.h transport.h \ message.h udp.h ui.h util.h cert.h isakmp_doi.o: isakmp_doi.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ doi.h exchange.h exchange_num.h constants.h isakmp.h isakmp_fld.h \ field.h isakmp_num.h isakmp_doi.h ipsec.h ipsec_doi.h ipsec_fld.h \ ipsec_num.h log.h message.h sa.h util.h isakmp_fld.o: isakmp_fld.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ constants.h field.h isakmp_fld.h isakmp_num.h ipsec_num.h isakmp_num.o: isakmp_num.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ constants.h isakmp_num.h key.o: key.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ key.h libcrypto.h log.h util.h x509.h libcrypto.o: libcrypto.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ libcrypto.h log.o: log.c sysdep/common/pcap.h isakmp_num.h sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ constants.h log.h message.o: message.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ attribute.h cert.h constants.h crypto.h doi.h exchange.h \ exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h ipsec_num.h \ log.h message.h sa.h timer.h transport.h util.h math_2n.o: math_2n.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ math_2n.h util.h math_group.o: math_group.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ gmp_util.h math_mp.h log.h math_2n.h math_ec2n.h math_group.h prf.o: prf.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ hash.h log.h prf.h sa.o: sa.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ connection.h cookie.h doi.h exchange.h exchange_num.h constants.h \ isakmp.h isakmp_fld.h field.h isakmp_num.h log.h message.h sa.h \ timer.h transport.h util.h cert.h policy.h key.h ipsec.h ipsec_doi.h \ ipsec_fld.h ipsec_num.h sysdep.o: \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep.c \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/app.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/conf.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_doi.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_fld.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/field.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_num.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/constants.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/klips.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/log.h timer.o: timer.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ log.h timer.h transport.o: transport.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ conf.h exchange.h exchange_num.h constants.h isakmp.h isakmp_fld.h \ field.h isakmp_num.h log.h message.h sa.h timer.h transport.h udp.o: udp.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ conf.h if.h isakmp.h isakmp_fld.h field.h isakmp_num.h constants.h \ log.h message.h transport.h udp.h util.h ui.o: ui.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ conf.h connection.h doi.h exchange.h exchange_num.h constants.h \ isakmp.h isakmp_fld.h field.h isakmp_num.h init.h log.h sa.h timer.h \ transport.h message.h ui.h util.h util.o: util.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ log.h message.h isakmp.h isakmp_fld.h field.h isakmp_num.h \ constants.h transport.h util.h klips.o: \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/klips.c \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/conf.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/exchange.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/exchange_num.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/constants.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/isakmp.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/isakmp_fld.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/field.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/isakmp_num.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/hash.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_doi.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_fld.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/ipsec_num.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/log.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/klips.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sa.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/timer.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/transport.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/message.h math_ec2n.o: ./math_ec2n.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ math_2n.h math_ec2n.h ike_aggressive.o: ./ike_aggressive.c sysdep.h \ /home/jdive/devel/isakmpd/src/sbin/isakmpd/sysdep/linux/sysdep-os.h \ attribute.h conf.h constants.h crypto.h dh.h doi.h exchange.h \ exchange_num.h isakmp.h isakmp_fld.h field.h isakmp_num.h hash.h \ ike_auth.h ike_aggressive.h ike_phase_1.h ipsec.h ipsec_doi.h \ ipsec_fld.h ipsec_num.h log.h math_group.h message.h prf.h sa.h \ transport.h util.h isakmpd-20041012.orig/init.c0000644000175000017500000000770510133045740015675 0ustar jdivejdive00000000000000/* $OpenBSD: init.c,v 1.33 2004/09/17 13:46:34 ho Exp $ */ /* $EOM: init.c,v 1.25 2000/03/30 14:27:24 ho Exp $ */ /* * Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved. * Copyright (c) 2000 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2003, 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* XXX This file could easily be built dynamically instead. */ #include #include "sysdep.h" #include "app.h" #include "cert.h" #include "conf.h" #include "connection.h" #include "doi.h" #include "exchange.h" #include "init.h" #include "ipsec.h" #include "isakmp_doi.h" #include "libcrypto.h" #include "log.h" #include "math_group.h" #include "monitor.h" #include "sa.h" #include "timer.h" #include "transport.h" #include "virtual.h" #include "udp.h" #include "ui.h" #include "util.h" #if defined (USE_POLICY) #include "policy.h" #endif #if defined (USE_NAT_TRAVERSAL) #include "nat_traversal.h" #include "udp_encap.h" #endif void init(void) { app_init(); doi_init(); exchange_init(); group_init(); ipsec_init(); isakmp_doi_init(); message_init(); libcrypto_init(); timer_init(); /* The following group are depending on timer_init having run. */ conf_init(); connection_init(); /* This depends on conf_init, thus check as soon as possible. */ log_reinit(); #if defined (USE_POLICY) /* policy_init depends on conf_init having run. */ policy_init(); #endif /* Depends on conf_init and policy_init having run */ cert_init(); crl_init(); sa_init(); transport_init(); virtual_init(); udp_init(); #if defined (USE_NAT_TRAVERSAL) nat_t_init(); udp_encap_init(); #endif monitor_ui_init(); } /* Reinitialize, either after a SIGHUP reception or by FIFO UI cmd. */ void reinit(void) { log_print("isakmpd: reinitializing daemon"); /* * XXX Remove all(/some?) pending exchange timers? - they may not be * possible to complete after we've re-read the config file. * User-initiated SIGHUP's maybe "authorizes" a wait until * next connection-check. * XXX This means we discard exchange->last_msg, is this really ok? */ /* Reinitialize PRNG if we are in deterministic mode. */ if (regrand) srandom(seed); /* Reread config file. */ conf_reinit(); log_reinit(); #if defined (USE_POLICY) /* Reread the policies. */ policy_init(); #endif /* Reinitialize certificates */ cert_init(); crl_init(); /* Reinitialize our connection list. */ connection_reinit(); /* * Rescan interfaces (call reinit() in all transports). */ transport_reinit(); /* * XXX "These" (non-existent) reinitializations should not be done. * cookie_reinit (); * ui_reinit (); */ sa_reinit(); } isakmpd-20041012.orig/conf.c0000644000175000017500000006652010133045740015657 0ustar jdivejdive00000000000000/* $OpenBSD: conf.c,v 1.73 2004/08/08 19:11:06 deraadt Exp $ */ /* $EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $ */ /* * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2000, 2001, 2002 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sysdep.h" #include "app.h" #include "conf.h" #include "log.h" #include "monitor.h" #include "util.h" static char *conf_get_trans_str(int, char *, char *); static void conf_load_defaults(int); #if 0 static int conf_find_trans_xf(int, char *); #endif struct conf_trans { TAILQ_ENTRY(conf_trans) link; int trans; enum conf_op { CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION } op; char *section; char *tag; char *value; int override; int is_default; }; #define CONF_SECT_MAX 256 TAILQ_HEAD(conf_trans_head, conf_trans) conf_trans_queue; /* * Radix-64 Encoding. */ const u_int8_t bin2asc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const u_int8_t asc2bin[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255 }; struct conf_binding { LIST_ENTRY(conf_binding) link; char *section; char *tag; char *value; int is_default; }; char *conf_path = CONFIG_FILE; LIST_HEAD(conf_bindings, conf_binding) conf_bindings[256]; static char *conf_addr; static __inline__ u_int8_t conf_hash(char *s) { u_int8_t hash = 0; while (*s) { hash = ((hash << 1) | (hash >> 7)) ^ tolower(*s); s++; } return hash; } /* * Insert a tag-value combination from LINE (the equal sign is at POS) */ static int conf_remove_now(char *section, char *tag) { struct conf_binding *cb, *next; for (cb = LIST_FIRST(&conf_bindings[conf_hash(section)]); cb; cb = next) { next = LIST_NEXT(cb, link); if (strcasecmp(cb->section, section) == 0 && strcasecmp(cb->tag, tag) == 0) { LIST_REMOVE(cb, link); LOG_DBG((LOG_MISC, 95, "[%s]:%s->%s removed", section, tag, cb->value)); free(cb->section); free(cb->tag); free(cb->value); free(cb); return 0; } } return 1; } static int conf_remove_section_now(char *section) { struct conf_binding *cb, *next; int unseen = 1; for (cb = LIST_FIRST(&conf_bindings[conf_hash(section)]); cb; cb = next) { next = LIST_NEXT(cb, link); if (strcasecmp(cb->section, section) == 0) { unseen = 0; LIST_REMOVE(cb, link); LOG_DBG((LOG_MISC, 95, "[%s]:%s->%s removed", section, cb->tag, cb->value)); free(cb->section); free(cb->tag); free(cb->value); free(cb); } } return unseen; } /* * Insert a tag-value combination from LINE (the equal sign is at POS) * into SECTION of our configuration database. */ static int conf_set_now(char *section, char *tag, char *value, int override, int is_default) { struct conf_binding *node = 0; if (override) conf_remove_now(section, tag); else if (conf_get_str(section, tag)) { if (!is_default) log_print("conf_set_now: duplicate tag [%s]:%s, " "ignoring...\n", section, tag); return 1; } node = calloc(1, sizeof *node); if (!node) { log_error("conf_set_now: calloc (1, %lu) failed", (unsigned long)sizeof *node); return 1; } node->section = strdup(section); node->tag = strdup(tag); node->value = strdup(value); node->is_default = is_default; LIST_INSERT_HEAD(&conf_bindings[conf_hash(section)], node, link); LOG_DBG((LOG_MISC, 95, "conf_set_now: [%s]:%s->%s", node->section, node->tag, node->value)); return 0; } /* * Parse the line LINE of SZ bytes. Skip Comments, recognize section * headers and feed tag-value pairs into our configuration database. */ static void conf_parse_line(int trans, char *line, size_t sz) { char *val; size_t i; int j; static char *section = 0; static int ln = 0; ln++; /* Lines starting with '#' or ';' are comments. */ if (*line == '#' || *line == ';') return; /* '[section]' parsing... */ if (*line == '[') { for (i = 1; i < sz; i++) if (line[i] == ']') break; if (section) free(section); if (i == sz) { log_print("conf_parse_line: %d:" "unmatched ']', ignoring until next section", ln); section = 0; return; } section = malloc(i); if (!section) { log_print("conf_parse_line: %d: malloc (%lu) failed", ln, (unsigned long)i); return; } strlcpy(section, line + 1, i); return; } /* Deal with assignments. */ for (i = 0; i < sz; i++) if (line[i] == '=') { /* If no section, we are ignoring the lines. */ if (!section) { log_print("conf_parse_line: %d: ignoring line " "due to no section", ln); return; } line[strcspn(line, " \t=")] = '\0'; val = line + i + 1 + strspn(line + i + 1, " \t"); /* Skip trailing whitespace, if any */ for (j = sz - (val - line) - 1; j > 0 && isspace(val[j]); j--) val[j] = '\0'; /* XXX Perhaps should we not ignore errors? */ conf_set(trans, section, line, val, 0, 0); return; } /* Other non-empty lines are weird. */ i = strspn(line, " \t"); if (line[i]) log_print("conf_parse_line: %d: syntax error", ln); } /* Parse the mapped configuration file. */ static void conf_parse(int trans, char *buf, size_t sz) { char *cp = buf; char *bufend = buf + sz; char *line; line = cp; while (cp < bufend) { if (*cp == '\n') { /* Check for escaped newlines. */ if (cp > buf && *(cp - 1) == '\\') *(cp - 1) = *cp = ' '; else { *cp = '\0'; conf_parse_line(trans, line, cp - line); line = cp + 1; } } cp++; } if (cp != line) log_print("conf_parse: last line unterminated, ignored."); } /* * Auto-generate default configuration values for the transforms and * suites the user wants. * * Resulting section names can be: * For main mode: * {DES,BLF,3DES,CAST,AES}-{MD5,SHA}[-GRP{1,2,5,14}][-{DSS,RSA_SIG}] * For quick mode: * QM-{proto}[-TRP]-{cipher}[-{hash}][-PFS[-{group}]]-SUITE * where * {proto} = ESP, AH * {cipher} = DES, 3DES, CAST, BLF, AES * {hash} = MD5, SHA, RIPEMD, SHA2-{-256,384,512} * {group} = GRP1, GRP2, GRP5, GRP14 * * DH group defaults to MODP_1024. * * XXX We may want to support USE_BLOWFISH, USE_TRIPLEDES, etc... * XXX No EC2N DH support here yet. */ /* Find the value for a section+tag in the transaction list. */ static char * conf_get_trans_str(int trans, char *section, char *tag) { struct conf_trans *node, *nf = 0; for (node = TAILQ_FIRST(&conf_trans_queue); node; node = TAILQ_NEXT(node, link)) if (node->trans == trans && strcasecmp(section, node->section) == 0 && strcasecmp(tag, node->tag) == 0) { if (!nf) nf = node; else if (node->override) nf = node; } return nf ? nf->value : 0; } #if 0 /* XXX Currently unused. */ static int conf_find_trans_xf(int phase, char *xf) { struct conf_trans *node; char *p; /* Find the relevant transforms and suites, if any. */ for (node = TAILQ_FIRST(&conf_trans_queue); node; node = TAILQ_NEXT(node, link)) if ((phase == 1 && strcmp("Transforms", node->tag) == 0) || (phase == 2 && strcmp("Suites", node->tag) == 0)) { p = node->value; while ((p = strstr(p, xf)) != NULL) if (*(p + strlen(p)) && *(p + strlen(p)) != ',') p += strlen(p); else return 1; } return 0; } #endif static void conf_load_defaults_mm(int tr, char *mme, char *mmh, char *mma, char *dhg, char *mme_p, char *mma_p, char *dhg_p) { char sect[CONF_SECT_MAX]; snprintf(sect, sizeof sect, "%s-%s%s%s", mme_p, mmh, dhg_p, mma_p); LOG_DBG((LOG_MISC, 95, "conf_load_defaults_mm: main mode %s", sect)); conf_set(tr, sect, "ENCRYPTION_ALGORITHM", mme, 0, 1); if (strcmp(mme, "BLOWFISH_CBC") == 0) conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN, 0, 1); else if (strcmp(mme, "AES_CBC") == 0) conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_AES_KEYLEN, 0, 1); conf_set(tr, sect, "HASH_ALGORITHM", mmh, 0, 1); conf_set(tr, sect, "AUTHENTICATION_METHOD", mma, 0, 1); conf_set(tr, sect, "GROUP_DESCRIPTION", dhg, 0, 1); conf_set(tr, sect, "Life", CONF_DFLT_TAG_LIFE_MAIN_MODE, 0, 1); } static void conf_load_defaults_qm(int tr, char *qme, char *qmh, char *dhg, char *qme_p, char *qmh_p, char *dhg_p, int proto, int mode, int pfs) { char sect[CONF_SECT_MAX], tmp[CONF_SECT_MAX]; /* Helper #defines, incl abbreviations. */ #define PROTO(x) ((x) ? "AH" : "ESP") #define PFS(x) ((x) ? "-PFS" : "") #define MODE(x) ((x) ? "TRANSPORT" : "TUNNEL") #define MODE_p(x) ((x) ? "-TRP" : "") if (proto == 1 && strcmp(qmh, "NONE") == 0) /* AH */ return; snprintf(tmp, sizeof tmp, "QM-%s%s%s%s%s%s", PROTO(proto), MODE_p(mode), qme_p, qmh_p, PFS(pfs), dhg_p); strlcpy(sect, tmp, CONF_SECT_MAX); strlcat(sect, "-SUITE", CONF_SECT_MAX); LOG_DBG((LOG_MISC, 95, "conf_load_defaults_qm: quick mode %s", sect)); conf_set(tr, sect, "Protocols", tmp, 0, 1); snprintf(sect, sizeof sect, "IPSEC_%s", PROTO(proto)); conf_set(tr, tmp, "PROTOCOL_ID", sect, 0, 1); strlcpy(sect, tmp, CONF_SECT_MAX); strlcat(sect, "-XF", CONF_SECT_MAX); conf_set(tr, tmp, "Transforms", sect, 0, 1); /* * XXX For now, defaults * contain one xf per protocol. */ conf_set(tr, sect, "TRANSFORM_ID", qme, 0, 1); if (strcmp(qme ,"BLOWFISH") == 0) conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN, 0, 1); else if (strcmp(qme ,"AES") == 0) conf_set(tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_AES_KEYLEN, 0, 1); conf_set(tr, sect, "ENCAPSULATION_MODE", MODE(mode), 0, 1); if (strcmp(qmh, "NONE")) { conf_set(tr, sect, "AUTHENTICATION_ALGORITHM", qmh, 0, 1); /* XXX Another shortcut to keep length down */ if (pfs) conf_set(tr, sect, "GROUP_DESCRIPTION", dhg, 0, 1); } /* XXX Lifetimes depending on enc/auth strength? */ conf_set(tr, sect, "Life", CONF_DFLT_TAG_LIFE_QUICK_MODE, 0, 1); } static void conf_load_defaults(int tr) { int enc, auth, hash, group, proto, mode, pfs; char *dflt; char *mm_auth[] = {"PRE_SHARED", "DSS", "RSA_SIG", 0}; char *mm_auth_p[] = {"", "-DSS", "-RSA_SIG", 0}; char *mm_hash[] = {"MD5", "SHA", 0}; char *mm_enc[] = {"DES_CBC", "BLOWFISH_CBC", "3DES_CBC", "CAST_CBC", "AES_CBC", 0}; char *mm_enc_p[] = {"DES", "BLF", "3DES", "CAST", "AES", 0}; char *dhgroup[] = {"MODP_1024", "MODP_768", "MODP_1024", "MODP_1536", "MODP_2048", 0}; char *dhgroup_p[] = {"", "-GRP1", "-GRP2", "-GRP5", "-GRP14", 0}; char *qm_enc[] = {"DES", "3DES", "CAST", "BLOWFISH", "AES", 0}; char *qm_enc_p[] = {"-DES", "-3DES", "-CAST", "-BLF", "-AES", 0}; char *qm_hash[] = {"HMAC_MD5", "HMAC_SHA", "HMAC_RIPEMD", "HMAC_SHA2_256", "HMAC_SHA2_384", "HMAC_SHA2_512", "NONE", 0}; char *qm_hash_p[] = {"-MD5", "-SHA", "-RIPEMD", "-SHA2-256", "-SHA2-384", "-SHA2-512", "", 0}; /* General and X509 defaults */ conf_set(tr, "General", "Retransmits", CONF_DFLT_RETRANSMITS, 0, 1); conf_set(tr, "General", "Exchange-max-time", CONF_DFLT_EXCH_MAX_TIME, 0, 1); conf_set(tr, "General", "Use-Keynote", CONF_DFLT_USE_KEYNOTE, 0, 1); conf_set(tr, "General", "Policy-file", CONF_DFLT_POLICY_FILE, 0, 1); conf_set(tr, "General", "Pubkey-directory", CONF_DFLT_PUBKEY_DIR, 0, 1); #ifdef USE_X509 conf_set(tr, "X509-certificates", "CA-directory", CONF_DFLT_X509_CA_DIR, 0, 1); conf_set(tr, "X509-certificates", "Cert-directory", CONF_DFLT_X509_CERT_DIR, 0, 1); conf_set(tr, "X509-certificates", "Private-key", CONF_DFLT_X509_PRIVATE_KEY, 0, 1); conf_set(tr, "X509-certificates", "CRL-directory", CONF_DFLT_X509_CRL_DIR, 0, 1); #endif #ifdef USE_KEYNOTE conf_set(tr, "KeyNote", "Credential-directory", CONF_DFLT_KEYNOTE_CRED_DIR, 0, 1); #endif /* Lifetimes. XXX p1/p2 vs main/quick mode may be unclear. */ dflt = conf_get_trans_str(tr, "General", "Default-phase-1-lifetime"); conf_set(tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_TYPE", CONF_DFLT_TYPE_LIFE_MAIN_MODE, 0, 1); conf_set(tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_DURATION", (dflt ? dflt : CONF_DFLT_VAL_LIFE_MAIN_MODE), 0, 1); dflt = conf_get_trans_str(tr, "General", "Default-phase-2-lifetime"); conf_set(tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_TYPE", CONF_DFLT_TYPE_LIFE_QUICK_MODE, 0, 1); conf_set(tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_DURATION", (dflt ? dflt : CONF_DFLT_VAL_LIFE_QUICK_MODE), 0, 1); /* Default Phase-1 Configuration section */ conf_set(tr, CONF_DFLT_TAG_PHASE1_CONFIG, "EXCHANGE_TYPE", CONF_DFLT_PHASE1_EXCH_TYPE, 0, 1); conf_set(tr, CONF_DFLT_TAG_PHASE1_CONFIG, "Transforms", CONF_DFLT_PHASE1_TRANSFORMS, 0, 1); /* Main modes */ for (enc = 0; mm_enc[enc]; enc++) for (hash = 0; mm_hash[hash]; hash++) for (auth = 0; mm_auth[auth]; auth++) for (group = 0; dhgroup_p[group]; group++) conf_load_defaults_mm (tr, mm_enc[enc], mm_hash[hash], mm_auth[auth], dhgroup[group], mm_enc_p[enc], mm_auth_p[auth], dhgroup_p[group]); /* Setup a default Phase 1 entry */ conf_set(tr, "Phase 1", "Default", "Default-phase-1", 0, 1); conf_set(tr, "Default-phase-1", "Phase", "1", 0, 1); conf_set(tr, "Default-phase-1", "Configuration", "Default-phase-1-configuration", 0, 1); dflt = conf_get_trans_str(tr, "General", "Default-phase-1-ID"); if (dflt) conf_set(tr, "Default-phase-1", "ID", dflt, 0, 1); /* Quick modes */ for (enc = 0; qm_enc[enc]; enc++) for (proto = 0; proto < 2; proto++) for (mode = 0; mode < 2; mode++) for (pfs = 0; pfs < 2; pfs++) for (hash = 0; qm_hash[hash]; hash++) for (group = 0; dhgroup_p[group]; group++) conf_load_defaults_qm( tr, qm_enc[enc], qm_hash[hash], dhgroup[group], qm_enc_p[enc], qm_hash_p[hash], dhgroup_p[group], proto, mode, pfs); } void conf_init(void) { unsigned int i; for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) LIST_INIT(&conf_bindings[i]); TAILQ_INIT(&conf_trans_queue); conf_reinit(); } /* Open the config file and map it into our address space, then parse it. */ void conf_reinit(void) { struct conf_binding *cb = 0; int fd, trans; unsigned int i; size_t sz; char *new_conf_addr = 0; if ((fd = monitor_open(conf_path, O_RDONLY, 0)) != -1) { if (check_file_secrecy_fd(fd, conf_path, &sz)) goto fail; new_conf_addr = malloc(sz); if (!new_conf_addr) { log_error("conf_reinit: malloc (%lu) failed", (unsigned long)sz); goto fail; } /* XXX I assume short reads won't happen here. */ if (read(fd, new_conf_addr, sz) != (int)sz) { log_error("conf_reinit: read (%d, %p, %lu) failed", fd, new_conf_addr, (unsigned long)sz); goto fail; } close(fd); trans = conf_begin(); /* XXX Should we not care about errors and rollback? */ conf_parse(trans, new_conf_addr, sz); } else { if (errno != ENOENT) log_error("conf_reinit: open(\"%s\", O_RDONLY, 0) " "failed", conf_path); trans = conf_begin(); } /* Load default configuration values. */ conf_load_defaults(trans); /* Free potential existing configuration. */ if (conf_addr) { for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) for (cb = LIST_FIRST(&conf_bindings[i]); cb; cb = LIST_FIRST(&conf_bindings[i])) conf_remove_now(cb->section, cb->tag); free(conf_addr); } conf_end(trans, 1); conf_addr = new_conf_addr; return; fail: if (new_conf_addr) free(new_conf_addr); close(fd); } /* * Return the numeric value denoted by TAG in section SECTION or DEF * if that tag does not exist. */ int conf_get_num(char *section, char *tag, int def) { char *value = conf_get_str(section, tag); if (value) return atoi(value); return def; } /* * Return the socket endpoint address denoted by TAG in SECTION as a * struct sockaddr. It is the callers responsibility to deallocate * this structure when it is finished with it. */ struct sockaddr * conf_get_address(char *section, char *tag) { char *value = conf_get_str(section, tag); struct sockaddr *sa; if (!value) return 0; if (text2sockaddr(value, 0, &sa) == -1) return 0; return sa; } /* Validate X according to the range denoted by TAG in section SECTION. */ int conf_match_num(char *section, char *tag, int x) { char *value = conf_get_str(section, tag); int val, min, max, n; if (!value) return 0; n = sscanf(value, "%d,%d:%d", &val, &min, &max); switch (n) { case 1: LOG_DBG((LOG_MISC, 95, "conf_match_num: %s:%s %d==%d?", section, tag, val, x)); return x == val; case 3: LOG_DBG((LOG_MISC, 95, "conf_match_num: %s:%s %d<=%d<=%d?", section, tag, min, x, max)); return min <= x && max >= x; default: log_error("conf_match_num: section %s tag %s: invalid number " "spec %s", section, tag, value); } return 0; } /* Return the string value denoted by TAG in section SECTION. */ char * conf_get_str(char *section, char *tag) { struct conf_binding *cb; for (cb = LIST_FIRST(&conf_bindings[conf_hash(section)]); cb; cb = LIST_NEXT(cb, link)) if (strcasecmp(section, cb->section) == 0 && strcasecmp(tag, cb->tag) == 0) { LOG_DBG((LOG_MISC, 95, "conf_get_str: [%s]:%s->%s", section, tag, cb->value)); return cb->value; } LOG_DBG((LOG_MISC, 95, "conf_get_str: configuration value not found [%s]:%s", section, tag)); return 0; } /* * Build a list of string values out of the comma separated value denoted by * TAG in SECTION. */ struct conf_list * conf_get_list(char *section, char *tag) { char *liststr = 0, *p, *field, *t; struct conf_list *list = 0; struct conf_list_node *node; list = malloc(sizeof *list); if (!list) goto cleanup; TAILQ_INIT(&list->fields); list->cnt = 0; liststr = conf_get_str(section, tag); if (!liststr) goto cleanup; liststr = strdup(liststr); if (!liststr) goto cleanup; p = liststr; while ((field = strsep(&p, ",")) != NULL) { /* Skip leading whitespace */ while (isspace(*field)) field++; /* Skip trailing whitespace */ if (p) for (t = p - 1; t > field && isspace(*t); t--) *t = '\0'; if (*field == '\0') { log_print("conf_get_list: empty field, ignoring..."); continue; } list->cnt++; node = calloc(1, sizeof *node); if (!node) goto cleanup; node->field = strdup(field); if (!node->field) goto cleanup; TAILQ_INSERT_TAIL(&list->fields, node, link); } free(liststr); return list; cleanup: if (list) conf_free_list(list); if (liststr) free(liststr); return 0; } struct conf_list * conf_get_tag_list(char *section) { struct conf_list *list = 0; struct conf_list_node *node; struct conf_binding *cb; list = malloc(sizeof *list); if (!list) goto cleanup; TAILQ_INIT(&list->fields); list->cnt = 0; for (cb = LIST_FIRST(&conf_bindings[conf_hash(section)]); cb; cb = LIST_NEXT(cb, link)) if (strcasecmp(section, cb->section) == 0) { list->cnt++; node = calloc(1, sizeof *node); if (!node) goto cleanup; node->field = strdup(cb->tag); if (!node->field) goto cleanup; TAILQ_INSERT_TAIL(&list->fields, node, link); } return list; cleanup: if (list) conf_free_list(list); return 0; } /* Decode a PEM encoded buffer. */ int conf_decode_base64(u_int8_t *out, u_int32_t *len, u_char *buf) { u_int32_t c = 0; u_int8_t c1, c2, c3, c4; while (*buf) { if (*buf > 127 || (c1 = asc2bin[*buf]) == 255) return 0; buf++; if (*buf > 127 || (c2 = asc2bin[*buf]) == 255) return 0; buf++; if (*buf == '=') { c3 = c4 = 0; c++; /* Check last four bit */ if (c2 & 0xF) return 0; if (strcmp((char *)buf, "==") == 0) buf++; else return 0; } else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255) return 0; else { if (*++buf == '=') { c4 = 0; c += 2; /* Check last two bit */ if (c3 & 3) return 0; if (strcmp((char *)buf, "=")) return 0; } else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255) return 0; else c += 3; } buf++; *out++ = (c1 << 2) | (c2 >> 4); *out++ = (c2 << 4) | (c3 >> 2); *out++ = (c3 << 6) | c4; } *len = c; return 1; } void conf_free_list(struct conf_list *list) { struct conf_list_node *node = TAILQ_FIRST(&list->fields); while (node) { TAILQ_REMOVE(&list->fields, node, link); if (node->field) free(node->field); free(node); node = TAILQ_FIRST(&list->fields); } free(list); } int conf_begin(void) { static int seq = 0; return ++seq; } static struct conf_trans * conf_trans_node(int transaction, enum conf_op op) { struct conf_trans *node; node = calloc(1, sizeof *node); if (!node) { log_error("conf_trans_node: calloc (1, %lu) failed", (unsigned long)sizeof *node); return 0; } node->trans = transaction; node->op = op; TAILQ_INSERT_TAIL(&conf_trans_queue, node, link); return node; } /* Queue a set operation. */ int conf_set(int transaction, char *section, char *tag, char *value, int override, int is_default) { struct conf_trans *node; node = conf_trans_node(transaction, CONF_SET); if (!node) return 1; node->section = strdup(section); if (!node->section) { log_error("conf_set: strdup (\"%s\") failed", section); goto fail; } node->tag = strdup(tag); if (!node->tag) { log_error("conf_set: strdup (\"%s\") failed", tag); goto fail; } node->value = strdup(value); if (!node->value) { log_error("conf_set: strdup (\"%s\") failed", value); goto fail; } node->override = override; node->is_default = is_default; return 0; fail: if (node->tag) free(node->tag); if (node->section) free(node->section); if (node) free(node); return 1; } /* Queue a remove operation. */ int conf_remove(int transaction, char *section, char *tag) { struct conf_trans *node; node = conf_trans_node(transaction, CONF_REMOVE); if (!node) goto fail; node->section = strdup(section); if (!node->section) { log_error("conf_remove: strdup (\"%s\") failed", section); goto fail; } node->tag = strdup(tag); if (!node->tag) { log_error("conf_remove: strdup (\"%s\") failed", tag); goto fail; } return 0; fail: if (node->section) free(node->section); if (node) free(node); return 1; } /* Queue a remove section operation. */ int conf_remove_section(int transaction, char *section) { struct conf_trans *node; node = conf_trans_node(transaction, CONF_REMOVE_SECTION); if (!node) goto fail; node->section = strdup(section); if (!node->section) { log_error("conf_remove_section: strdup (\"%s\") failed", section); goto fail; } return 0; fail: if (node) free(node); return 1; } /* Execute all queued operations for this transaction. Cleanup. */ int conf_end(int transaction, int commit) { struct conf_trans *node, *next; for (node = TAILQ_FIRST(&conf_trans_queue); node; node = next) { next = TAILQ_NEXT(node, link); if (node->trans == transaction) { if (commit) switch (node->op) { case CONF_SET: conf_set_now(node->section, node->tag, node->value, node->override, node->is_default); break; case CONF_REMOVE: conf_remove_now(node->section, node->tag); break; case CONF_REMOVE_SECTION: conf_remove_section_now(node->section); break; default: log_print("conf_end: unknown " "operation: %d", node->op); } TAILQ_REMOVE(&conf_trans_queue, node, link); if (node->section) free(node->section); if (node->tag) free(node->tag); if (node->value) free(node->value); free(node); } } return 0; } /* * Dump running configuration upon SIGUSR1. * Configuration is "stored in reverse order", so reverse it again. */ struct dumper { char *s, *v; struct dumper *next; }; static void conf_report_dump(struct dumper *node) { /* Recursive, cleanup when we're done. */ if (node->next) conf_report_dump(node->next); if (node->v) LOG_DBG((LOG_REPORT, 0, "%s=\t%s", node->s, node->v)); else if (node->s) { LOG_DBG((LOG_REPORT, 0, "%s", node->s)); if (strlen(node->s) > 0) free(node->s); } free(node); } void conf_report(void) { struct conf_binding *cb, *last = 0; unsigned int i, len; char *current_section = (char *)0; struct dumper *dumper, *dnode; dumper = dnode = (struct dumper *)calloc(1, sizeof *dumper); if (!dumper) goto mem_fail; LOG_DBG((LOG_REPORT, 0, "conf_report: dumping running configuration")); for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) for (cb = LIST_FIRST(&conf_bindings[i]); cb; cb = LIST_NEXT(cb, link)) { if (!cb->is_default) { /* Dump this entry. */ if (!current_section || strcmp(cb->section, current_section)) { if (current_section) { len = strlen(current_section) + 3; dnode->s = malloc(len); if (!dnode->s) goto mem_fail; snprintf(dnode->s, len, "[%s]", current_section); dnode->next = (struct dumper *) calloc(1, sizeof(struct dumper)); dnode = dnode->next; if (!dnode) goto mem_fail; dnode->s = ""; dnode->next = (struct dumper *) calloc(1, sizeof(struct dumper)); dnode = dnode->next; if (!dnode) goto mem_fail; } current_section = cb->section; } dnode->s = cb->tag; dnode->v = cb->value; dnode->next = (struct dumper *) calloc(1, sizeof(struct dumper)); dnode = dnode->next; if (!dnode) goto mem_fail; last = cb; } } if (last) { len = strlen(last->section) + 3; dnode->s = malloc(len); if (!dnode->s) goto mem_fail; snprintf(dnode->s, len, "[%s]", last->section); } conf_report_dump(dumper); return; mem_fail: log_error("conf_report: malloc/calloc failed"); while ((dnode = dumper) != 0) { dumper = dumper->next; if (dnode->s) free(dnode->s); free(dnode); } } isakmpd-20041012.orig/transport.h0000644000175000017500000001246010133045740016765 0ustar jdivejdive00000000000000/* $OpenBSD: transport.h,v 1.15 2004/06/20 15:24:05 ho Exp $ */ /* $EOM: transport.h,v 1.16 2000/07/17 18:57:59 provos Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. * Copyright (c) 2001, 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ /* * The transport module tries to separate out details concerning the * actual transferral of ISAKMP messages to other parties. */ #ifndef _TRANSPORT_H_ #define _TRANSPORT_H_ #include #include #include #include #include "message.h" struct transport; /* This describes a tranport "method" like UDP or similar. */ struct transport_vtbl { /* All transport methods are linked together. */ LIST_ENTRY(transport_vtbl) link; /* A textual name of the transport method. */ char *name; /* Create a transport instance of this method. */ struct transport *(*create) (char *); /* Reinitialize specific transport. */ void (*reinit) (void); /* Remove a transport instance of this method. */ void (*remove) (struct transport *); /* Report status of given transport */ void (*report) (struct transport *); /* Let the given transport set it's bit in the fd_set passed in. */ int (*fd_set) (struct transport *, fd_set *, int); /* Is the given transport ready for I/O? */ int (*fd_isset) (struct transport *, fd_set *); /* * Read a message from the transport's incoming pipe and start * handling it. */ void (*handle_message) (struct transport *); /* Send a message through the outgoing pipe. */ int (*send_message) (struct message *, struct transport *); /* * Fill out a sockaddr structure with the transport's destination end's * address info. */ void (*get_dst) (struct transport *, struct sockaddr **); /* * Fill out a sockaddr structure with the transport's source end's * address info. */ void (*get_src) (struct transport *, struct sockaddr **); /* * Return a string with decoded src and dst information */ char *(*decode_ids) (struct transport *); /* * Clone a transport for outbound use. */ struct transport *(*clone) (struct transport *, struct sockaddr *); /* * Locate the correct sendq to use for outbound messages. */ struct msg_head *(*get_queue) (struct message *); }; struct transport { /* All transports used are linked together. */ LIST_ENTRY(transport) link; /* What transport method is this an instance of? */ struct transport_vtbl *vtbl; /* The queue holding messages to send on this transport. */ struct msg_head sendq; /* * Prioritized send queue. Messages in this queue will be transmitted * before the normal sendq, they will also all be transmitted prior * to a daemon shutdown. Currently only used for DELETE notifications. */ struct msg_head prio_sendq; /* Flags describing the transport. */ int flags; /* Reference counter. */ int refcnt; /* Pointer to parent virtual transport, if any. */ struct transport *virtual; }; /* Set if this is a transport we want to listen on. */ #define TRANSPORT_LISTEN 1 /* Used for mark-and-sweep-type garbage collection of transports */ #define TRANSPORT_MARK 2 extern struct transport *transport_create(char *, char *); extern int transport_fd_set(fd_set *); extern void transport_handle_messages(fd_set *); extern void transport_init(void); extern void transport_map(void (*) (struct transport *)); extern void transport_method_add(struct transport_vtbl *); extern int transport_pending_wfd_set(fd_set *); extern int transport_prio_sendqs_empty(void); extern void transport_reference(struct transport *); extern void transport_reinit(void); extern void transport_release(struct transport *); extern void transport_report(void); extern void transport_send_messages(fd_set *); extern void transport_setup(struct transport *, int); #endif /* _TRANSPORT_H_ */ isakmpd-20041012.orig/x509.c0000644000175000017500000010502410133045740015430 0ustar jdivejdive00000000000000/* $OpenBSD: x509.c,v 1.95 2004/08/10 19:21:01 deraadt Exp $ */ /* $EOM: x509.c,v 1.54 2001/01/16 18:42:16 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifdef USE_X509 #include #include #include #include #include #include #include #include #include #include #ifdef USE_POLICY #include #include #endif /* USE_POLICY */ #include "sysdep.h" #include "cert.h" #include "conf.h" #include "exchange.h" #include "hash.h" #include "ike_auth.h" #include "ipsec.h" #include "log.h" #include "math_mp.h" #include "monitor.h" #include "policy.h" #include "sa.h" #include "util.h" #include "x509.h" static u_int16_t x509_hash(u_int8_t *, size_t); static void x509_hash_init(void); static X509 *x509_hash_find(u_int8_t *, size_t); static int x509_hash_enter(X509 *); /* * X509_STOREs do not support subjectAltNames, so we have to build * our own hash table. */ /* * XXX Actually this store is not really useful, we never use it as we have * our own hash table. It also gets collisons if we have several certificates * only differing in subjectAltName. */ static X509_STORE *x509_certs = 0; static X509_STORE *x509_cas = 0; /* Initial number of bits used as hash. */ #define INITIAL_BUCKET_BITS 6 struct x509_hash { LIST_ENTRY(x509_hash) link; X509 *cert; }; static LIST_HEAD(x509_list, x509_hash) *x509_tab = 0; /* Works both as a maximum index and a mask. */ static int bucket_mask; #ifdef USE_POLICY /* * Given an X509 certificate, create a KeyNote assertion where * Issuer/Subject -> Authorizer/Licensees. * XXX RSA-specific. */ int x509_generate_kn(int id, X509 *cert) { char *fmt = "Authorizer: \"rsa-hex:%s\"\nLicensees: \"rsa-hex:%s" "\"\nConditions: %s >= \"%s\" && %s <= \"%s\";\n"; char *ikey, *skey, *buf, isname[256], subname[256]; char *fmt2 = "Authorizer: \"DN:%s\"\nLicensees: \"DN:%s\"\n" "Conditions: %s >= \"%s\" && %s <= \"%s\";\n"; X509_NAME *issuer, *subject; struct keynote_deckey dc; X509_STORE_CTX csc; X509_OBJECT obj; X509 *icert; RSA *key; time_t tt; char before[15], after[15], *timecomp, *timecomp2; ASN1_TIME *tm; int i, buf_len; LOG_DBG((LOG_POLICY, 90, "x509_generate_kn: generating KeyNote policy for certificate %p", cert)); issuer = X509_get_issuer_name(cert); subject = X509_get_subject_name(cert); /* Missing or self-signed, ignore cert but don't report failure. */ if (!issuer || !subject || !X509_name_cmp(issuer, subject)) return 1; if (!x509_cert_get_key(cert, &key)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert")); return 0; } dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; dc.dec_key = key; ikey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX, KEYNOTE_PUBLIC_KEY); if (keynote_errno == ERROR_MEMORY) { log_print("x509_generate_kn: failed to get memory for " "public key"); RSA_free(key); LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key")); return 0; } if (!ikey) { RSA_free(key); LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key")); return 0; } RSA_free(key); /* Now find issuer's certificate so we can get the public key. */ X509_STORE_CTX_init(&csc, x509_cas, cert, NULL); if (X509_STORE_get_by_subject(&csc, X509_LU_X509, issuer, &obj) != X509_LU_X509) { X509_STORE_CTX_cleanup(&csc); X509_STORE_CTX_init(&csc, x509_certs, cert, NULL); if (X509_STORE_get_by_subject(&csc, X509_LU_X509, issuer, &obj) != X509_LU_X509) { X509_STORE_CTX_cleanup(&csc); LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: no certificate found for " "issuer")); return 0; } } X509_STORE_CTX_cleanup(&csc); icert = obj.data.x509; if (icert == NULL) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: " "missing certificates, cannot construct X509 chain")); free(ikey); return 0; } if (!x509_cert_get_key(icert, &key)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert")); free(ikey); return 0; } X509_OBJECT_free_contents(&obj); dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; dc.dec_key = key; skey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX, KEYNOTE_PUBLIC_KEY); if (keynote_errno == ERROR_MEMORY) { log_error("x509_generate_kn: failed to get memory for public " "key"); free(ikey); RSA_free(key); LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer " "key")); return 0; } if (!skey) { free(ikey); RSA_free(key); LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer " "key")); return 0; } RSA_free(key); buf_len = strlen(fmt) + strlen(ikey) + strlen(skey) + 56; buf = calloc(buf_len, sizeof(char)); buf_len *= sizeof(char); if (!buf) { log_error("x509_generate_kn: " "failed to allocate memory for KeyNote credential"); free(ikey); free(skey); return 0; } if (((tm = X509_get_notBefore(cert)) == NULL) || (tm->type != V_ASN1_UTCTIME && tm->type != V_ASN1_GENERALIZEDTIME)) { tt = time(0); strftime(before, 14, "%Y%m%d%H%M%S", localtime(&tt)); timecomp = "LocalTimeOfDay"; } else { if (tm->data[tm->length - 1] == 'Z') { timecomp = "GMTTimeOfDay"; i = tm->length - 2; } else { timecomp = "LocalTimeOfDay"; i = tm->length - 1; } for (; i >= 0; i--) { if (tm->data[i] < '0' || tm->data[i] > '9') { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid data in " "NotValidBefore time field")); free(ikey); free(skey); free(buf); return 0; } } if (tm->type == V_ASN1_UTCTIME) { if ((tm->length < 10) || (tm->length > 13)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid length " "of NotValidBefore time field (%d)", tm->length)); free(ikey); free(skey); free(buf); return 0; } /* Validity checks. */ if ((tm->data[2] != '0' && tm->data[2] != '1') || (tm->data[2] == '0' && tm->data[3] == '0') || (tm->data[2] == '1' && tm->data[3] > '2') || (tm->data[4] > '3') || (tm->data[4] == '0' && tm->data[5] == '0') || (tm->data[4] == '3' && tm->data[5] > '1') || (tm->data[6] > '2') || (tm->data[6] == '2' && tm->data[7] > '3') || (tm->data[8] > '5')) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidBefore time field")); free(ikey); free(skey); free(buf); return 0; } /* Stupid UTC tricks. */ if (tm->data[0] < '5') snprintf(before, sizeof before, "20%s", tm->data); else snprintf(before, sizeof before, "19%s", tm->data); } else { /* V_ASN1_GENERICTIME */ if ((tm->length < 12) || (tm->length > 15)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidBefore time field (%d)", tm->length)); free(ikey); free(skey); free(buf); return 0; } /* Validity checks. */ if ((tm->data[4] != '0' && tm->data[4] != '1') || (tm->data[4] == '0' && tm->data[5] == '0') || (tm->data[4] == '1' && tm->data[5] > '2') || (tm->data[6] > '3') || (tm->data[6] == '0' && tm->data[7] == '0') || (tm->data[6] == '3' && tm->data[7] > '1') || (tm->data[8] > '2') || (tm->data[8] == '2' && tm->data[9] > '3') || (tm->data[10] > '5')) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidBefore time field")); free(ikey); free(skey); free(buf); return 0; } snprintf(before, sizeof before, "%s", tm->data); } /* Fix missing seconds. */ if (tm->length < 12) { before[12] = '0'; before[13] = '0'; } /* This will overwrite trailing 'Z'. */ before[14] = '\0'; } tm = X509_get_notAfter(cert); if (tm == NULL && (tm->type != V_ASN1_UTCTIME && tm->type != V_ASN1_GENERALIZEDTIME)) { tt = time(0); strftime(after, 14, "%Y%m%d%H%M%S", localtime(&tt)); timecomp2 = "LocalTimeOfDay"; } else { if (tm->data[tm->length - 1] == 'Z') { timecomp2 = "GMTTimeOfDay"; i = tm->length - 2; } else { timecomp2 = "LocalTimeOfDay"; i = tm->length - 1; } for (; i >= 0; i--) { if (tm->data[i] < '0' || tm->data[i] > '9') { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid data in " "NotValidAfter time field")); free(ikey); free(skey); free(buf); return 0; } } if (tm->type == V_ASN1_UTCTIME) { if ((tm->length < 10) || (tm->length > 13)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length)); free(ikey); free(skey); free(buf); return 0; } /* Validity checks. */ if ((tm->data[2] != '0' && tm->data[2] != '1') || (tm->data[2] == '0' && tm->data[3] == '0') || (tm->data[2] == '1' && tm->data[3] > '2') || (tm->data[4] > '3') || (tm->data[4] == '0' && tm->data[5] == '0') || (tm->data[4] == '3' && tm->data[5] > '1') || (tm->data[6] > '2') || (tm->data[6] == '2' && tm->data[7] > '3') || (tm->data[8] > '5')) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidAfter time field")); free(ikey); free(skey); free(buf); return 0; } /* Stupid UTC tricks. */ if (tm->data[0] < '5') snprintf(after, sizeof after, "20%s", tm->data); else snprintf(after, sizeof after, "19%s", tm->data); } else { /* V_ASN1_GENERICTIME */ if ((tm->length < 12) || (tm->length > 15)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length)); free(ikey); free(skey); free(buf); return 0; } /* Validity checks. */ if ((tm->data[4] != '0' && tm->data[4] != '1') || (tm->data[4] == '0' && tm->data[5] == '0') || (tm->data[4] == '1' && tm->data[5] > '2') || (tm->data[6] > '3') || (tm->data[6] == '0' && tm->data[7] == '0') || (tm->data[6] == '3' && tm->data[7] > '1') || (tm->data[8] > '2') || (tm->data[8] == '2' && tm->data[9] > '3') || (tm->data[10] > '5')) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidAfter time field")); free(ikey); free(skey); free(buf); return 0; } snprintf(after, sizeof after, "%s", tm->data); } /* Fix missing seconds. */ if (tm->length < 12) { after[12] = '0'; after[13] = '0'; } after[14] = '\0'; /* This will overwrite trailing 'Z' */ } snprintf(buf, buf_len, fmt, skey, ikey, timecomp, before, timecomp2, after); free(ikey); free(skey); if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential")); free(buf); return 0; } /* We could print the assertion here, but log_print() truncates... */ LOG_DBG((LOG_POLICY, 60, "x509_generate_kn: added credential")); free(buf); if (!X509_NAME_oneline(issuer, isname, 256)) { LOG_DBG((LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (issuer, ...) failed")); return 0; } if (!X509_NAME_oneline(subject, subname, 256)) { LOG_DBG((LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (subject, ...) failed")); return 0; } buf_len = strlen(fmt2) + strlen(isname) + strlen(subname) + 56; buf = malloc(buf_len); if (!buf) { log_error("x509_generate_kn: malloc (%d) failed", buf_len); return 0; } snprintf(buf, buf_len, fmt2, isname, subname, timecomp, before, timecomp2, after); if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential")); free(buf); return 0; } LOG_DBG((LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s", buf)); free(buf); return 1; } #endif /* USE_POLICY */ static u_int16_t x509_hash(u_int8_t *id, size_t len) { u_int16_t bucket = 0; size_t i; /* XXX We might resize if we are crossing a certain threshold. */ for (i = 4; i < (len & ~1); i += 2) { /* Doing it this way avoids alignment problems. */ bucket ^= (id[i] + 1) * (id[i + 1] + 257); } /* Hash in the last character of odd length IDs too. */ if (i < len) bucket ^= (id[i] + 1) * (id[i] + 257); bucket &= bucket_mask; return bucket; } static void x509_hash_init(void) { struct x509_hash *certh; int i; bucket_mask = (1 << INITIAL_BUCKET_BITS) - 1; /* If reinitializing, free existing entries. */ if (x509_tab) { for (i = 0; i <= bucket_mask; i++) for (certh = LIST_FIRST(&x509_tab[i]); certh; certh = LIST_FIRST(&x509_tab[i])) { LIST_REMOVE(certh, link); free(certh); } free(x509_tab); } x509_tab = malloc((bucket_mask + 1) * sizeof(struct x509_list)); if (!x509_tab) log_fatal("x509_hash_init: malloc (%lu) failed", (bucket_mask + 1) * (unsigned long)sizeof(struct x509_list)); for (i = 0; i <= bucket_mask; i++) { LIST_INIT(&x509_tab[i]); } } /* Lookup a certificate by an ID blob. */ static X509 * x509_hash_find(u_int8_t *id, size_t len) { struct x509_hash *cert; u_int8_t **cid; u_int32_t *clen; int n, i, id_found; for (cert = LIST_FIRST(&x509_tab[x509_hash(id, len)]); cert; cert = LIST_NEXT(cert, link)) { if (!x509_cert_get_subjects(cert->cert, &n, &cid, &clen)) continue; id_found = 0; for (i = 0; i < n; i++) { LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", id, len)); LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", cid[i], clen[i])); /* * XXX This identity predicate needs to be * understood. */ if (clen[i] == len && id[0] == cid[i][0] && memcmp(id + 4, cid[i] + 4, len - 4) == 0) { id_found++; break; } } cert_free_subjects(n, cid, clen); if (!id_found) continue; LOG_DBG((LOG_CRYPTO, 70, "x509_hash_find: return X509 %p", cert->cert)); return cert->cert; } LOG_DBG((LOG_CRYPTO, 70, "x509_hash_find: no certificate matched query")); return 0; } static int x509_hash_enter(X509 *cert) { u_int16_t bucket = 0; u_int8_t **id; u_int32_t *len; struct x509_hash *certh; int n, i; if (!x509_cert_get_subjects(cert, &n, &id, &len)) { log_print("x509_hash_enter: cannot retrieve subjects"); return 0; } for (i = 0; i < n; i++) { certh = calloc(1, sizeof *certh); if (!certh) { cert_free_subjects(n, id, len); log_error("x509_hash_enter: calloc (1, %lu) failed", (unsigned long)sizeof *certh); return 0; } certh->cert = cert; bucket = x509_hash(id[i], len[i]); LIST_INSERT_HEAD(&x509_tab[bucket], certh, link); LOG_DBG((LOG_CRYPTO, 70, "x509_hash_enter: cert %p added to bucket %d", cert, bucket)); } cert_free_subjects(n, id, len); return 1; } /* X509 Certificate Handling functions. */ int x509_read_from_dir(X509_STORE *ctx, char *name, int hash) { struct dirent *file; #if defined (USE_PRIVSEP) struct monitor_dirents *dir; #else DIR *dir; #endif FILE *certfp; X509 *cert; struct stat sb; char fullname[PATH_MAX]; int fd, off, size; if (strlen(name) >= sizeof fullname - 1) { log_print("x509_read_from_dir: directory name too long"); return 0; } LOG_DBG((LOG_CRYPTO, 40, "x509_read_from_dir: reading certs from %s", name)); dir = monitor_opendir(name); if (!dir) { LOG_DBG((LOG_CRYPTO, 10, "x509_read_from_dir: opendir (\"%s\") failed: %s", name, strerror(errno))); return 0; } strlcpy(fullname, name, sizeof fullname); off = strlen(fullname); size = sizeof fullname - off; while ((file = monitor_readdir(dir)) != NULL) { strlcpy(fullname + off, file->d_name, size); if (file->d_type != DT_UNKNOWN) { if (file->d_type != DT_REG && file->d_type != DT_LNK) continue; } LOG_DBG((LOG_CRYPTO, 60, "x509_read_from_dir: reading certificate %s", file->d_name)); if ((fd = monitor_open(fullname, O_RDONLY, 0)) == -1) { log_error("x509_read_from_dir: monitor_open" "(\"%s\", O_RDONLY, 0) failed", fullname); continue; } if (fstat(fd, &sb) == -1) { log_error("x509_read_from_dir: fstat failed"); close(fd); continue; } if (!(sb.st_mode & S_IFREG)) { close(fd); continue; } if ((certfp = fdopen(fd, "r")) == NULL) { log_error("x509_read_from_dir: fdopen failed"); close(fd); continue; } #if SSLEAY_VERSION_NUMBER >= 0x00904100L cert = PEM_read_X509(certfp, NULL, NULL, NULL); #else cert = PEM_read_X509(certfp, NULL, NULL); #endif fclose(certfp); if (cert == NULL) { log_print("x509_read_from_dir: PEM_read_bio_X509 " "failed for %s", file->d_name); continue; } if (!X509_STORE_add_cert(ctx, cert)) { /* * This is actually expected if we have several * certificates only differing in subjectAltName, * which is not an something that is strange. * Consider multi-homed machines. */ LOG_DBG((LOG_CRYPTO, 50, "x509_read_from_dir: X509_STORE_add_cert failed " "for %s", file->d_name)); } if (hash) if (!x509_hash_enter(cert)) log_print("x509_read_from_dir: " "x509_hash_enter (%s) failed", file->d_name); } monitor_closedir(dir); return 1; } /* XXX share code with x509_read_from_dir() ? */ int x509_read_crls_from_dir(X509_STORE *ctx, char *name) { #if OPENSSL_VERSION_NUMBER >= 0x00907000L struct dirent *file; #if defined (USE_PRIVSEP) struct monitor_dirents *dir; #else DIR *dir; #endif FILE *crlfp; X509_CRL *crl; struct stat sb; char fullname[PATH_MAX]; int fd, off, size; if (strlen(name) >= sizeof fullname - 1) { log_print("x509_read_crls_from_dir: directory name too long"); return 0; } LOG_DBG((LOG_CRYPTO, 40, "x509_read_crls_from_dir: reading CRLs " "from %s", name)); dir = monitor_opendir(name); if (!dir) { LOG_DBG((LOG_CRYPTO, 10, "x509_read_crls_from_dir: opendir " "(\"%s\") failed: %s", name, strerror(errno))); return 0; } strlcpy(fullname, name, sizeof fullname); off = strlen(fullname); size = sizeof fullname - off; while ((file = monitor_readdir(dir)) != NULL) { strlcpy(fullname + off, file->d_name, size); if (file->d_type != DT_UNKNOWN) { if (file->d_type != DT_REG && file->d_type != DT_LNK) continue; } LOG_DBG((LOG_CRYPTO, 60, "x509_read_crls_from_dir: reading " "CRL %s", file->d_name)); if ((fd = monitor_open(fullname, O_RDONLY, 0)) == -1) { log_error("x509_read_crls_from_dir: monitor_open" "(\"%s\", O_RDONLY, 0) failed", fullname); continue; } if (fstat(fd, &sb) == -1) { log_error("x509_read_crls_from_dir: fstat failed"); close(fd); continue; } if (!(sb.st_mode & S_IFREG)) { close(fd); continue; } if ((crlfp = fdopen(fd, "r")) == NULL) { log_error("x509_read_crls_from_dir: fdopen failed"); close(fd); continue; } crl = PEM_read_X509_CRL(crlfp, NULL, NULL, NULL); fclose(crlfp); if (crl == NULL) { log_print("x509_read_crls_from_dir: " "PEM_read_X509_CRL failed for %s", file->d_name); continue; } if (!X509_STORE_add_crl(ctx, crl)) { LOG_DBG((LOG_CRYPTO, 50, "x509_read_crls_from_dir: " "X509_STORE_add_crl failed for %s", file->d_name)); continue; } /* * XXX This is to make x509_cert_validate set this (and * XXX another) flag when validating certificates. Currently, * XXX OpenSSL defaults to reject an otherwise valid * XXX certificate (chain) if these flags are set but there * XXX are no CRLs to check. The current workaround is to only * XXX set the flags if we actually loaded some CRL data. */ X509_STORE_set_flags(ctx, X509_V_FLAG_CRL_CHECK); } monitor_closedir(dir); #endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L */ return 1; } /* Initialize our databases and load our own certificates. */ int x509_cert_init(void) { char *dirname; x509_hash_init(); /* Process CA certificates we will trust. */ dirname = conf_get_str("X509-certificates", "CA-directory"); if (!dirname) { log_print("x509_cert_init: no CA-directory"); return 0; } /* Free if already initialized. */ if (x509_cas) X509_STORE_free(x509_cas); x509_cas = X509_STORE_new(); if (!x509_cas) { log_print("x509_cert_init: creating new X509_STORE failed"); return 0; } if (!x509_read_from_dir(x509_cas, dirname, 0)) { log_print("x509_cert_init: x509_read_from_dir failed"); return 0; } /* Process client certificates we will accept. */ dirname = conf_get_str("X509-certificates", "Cert-directory"); if (!dirname) { log_print("x509_cert_init: no Cert-directory"); return 0; } /* Free if already initialized. */ if (x509_certs) X509_STORE_free(x509_certs); x509_certs = X509_STORE_new(); if (!x509_certs) { log_print("x509_cert_init: creating new X509_STORE failed"); return 0; } if (!x509_read_from_dir(x509_certs, dirname, 1)) { log_print("x509_cert_init: x509_read_from_dir failed"); return 0; } return 1; } int x509_crl_init(void) { /* * XXX I'm not sure if the method to use CRLs in certificate validation * is valid for OpenSSL versions prior to 0.9.7. For now, simply do not * support it. */ #if OPENSSL_VERSION_NUMBER >= 0x00907000L char *dirname; dirname = conf_get_str("X509-certificates", "CRL-directory"); if (!dirname) { log_print("x509_crl_init: no CRL-directory"); return 0; } if (!x509_read_crls_from_dir(x509_cas, dirname)) { LOG_DBG((LOG_MISC, 10, "x509_crl_init: x509_read_crls_from_dir failed")); return 0; } #else LOG_DBG((LOG_CRYPTO, 10, "x509_crl_init: CRL support only " "with OpenSSL v0.9.7 or later")); #endif return 1; } void * x509_cert_get(u_int8_t *asn, u_int32_t len) { return x509_from_asn(asn, len); } int x509_cert_validate(void *scert) { X509_STORE_CTX csc; X509_NAME *issuer, *subject; X509 *cert = (X509 *) scert; EVP_PKEY *key; int res, err; /* * Validate the peer certificate by checking with the CA certificates * we trust. */ X509_STORE_CTX_init(&csc, x509_cas, cert, NULL); #if OPENSSL_VERSION_NUMBER >= 0x00907000L /* XXX See comment in x509_read_crls_from_dir. */ if (x509_cas->flags & X509_V_FLAG_CRL_CHECK) { X509_STORE_CTX_set_flags(&csc, X509_V_FLAG_CRL_CHECK); X509_STORE_CTX_set_flags(&csc, X509_V_FLAG_CRL_CHECK_ALL); } #endif res = X509_verify_cert(&csc); err = csc.error; X509_STORE_CTX_cleanup(&csc); /* * Return if validation succeeded or self-signed certs are not * accepted. * * XXX X509_verify_cert seems to return -1 if the validation should be * retried somehow. We take this as an error and give up. */ if (res > 0) return 1; else if (res < 0 || (res == 0 && err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)) { if (err) log_print("x509_cert_validate: %.100s", X509_verify_cert_error_string(err)); return 0; } else if (!conf_get_str("X509-certificates", "Accept-self-signed")) { if (err) log_print("x509_cert_validate: %.100s", X509_verify_cert_error_string(err)); return 0; } issuer = X509_get_issuer_name(cert); subject = X509_get_subject_name(cert); if (!issuer || !subject || X509_name_cmp(issuer, subject)) return 0; key = X509_get_pubkey(cert); if (!key) { log_print("x509_cert_validate: could not get public key from " "self-signed cert"); return 0; } if (X509_verify(cert, key) == -1) { log_print("x509_cert_validate: self-signed cert is bad"); return 0; } return 1; } int x509_cert_insert(int id, void *scert) { X509 *cert; int res; cert = X509_dup((X509 *)scert); if (!cert) { log_print("x509_cert_insert: X509_dup failed"); return 0; } #ifdef USE_POLICY if (x509_generate_kn(id, cert) == 0) { LOG_DBG((LOG_POLICY, 50, "x509_cert_insert: x509_generate_kn failed")); X509_free(cert); return 0; } #endif /* USE_POLICY */ res = x509_hash_enter(cert); if (!res) X509_free(cert); return res; } static struct x509_hash * x509_hash_lookup(X509 *cert) { struct x509_hash *certh; int i; for (i = 0; i <= bucket_mask; i++) for (certh = LIST_FIRST(&x509_tab[i]); certh; certh = LIST_NEXT(certh, link)) if (certh->cert == cert) return certh; return 0; } void x509_cert_free(void *cert) { struct x509_hash *certh = x509_hash_lookup((X509 *) cert); if (certh) LIST_REMOVE(certh, link); X509_free((X509 *) cert); } /* Validate the BER Encoding of a RDNSequence in the CERT_REQ payload. */ int x509_certreq_validate(u_int8_t *asn, u_int32_t len) { int res = 1; #if 0 struct norm_type name = SEQOF("issuer", RDNSequence); if (!asn_template_clone(&name, 1) || (asn = asn_decode_sequence(asn, len, &name)) == 0) { log_print("x509_certreq_validate: can not decode 'acceptable " "CA' info"); res = 0; } asn_free(&name); #endif /* XXX - not supported directly in SSL - later. */ return res; } /* Decode the BER Encoding of a RDNSequence in the CERT_REQ payload. */ void * x509_certreq_decode(u_int8_t *asn, u_int32_t len) { #if 0 /* XXX This needs to be done later. */ struct norm_type aca = SEQOF("aca", RDNSequence); struct norm_type *tmp; struct x509_aca naca, *ret; if (!asn_template_clone(&aca, 1) || (asn = asn_decode_sequence(asn, len, &aca)) == 0) { log_print("x509_certreq_decode: can not decode 'acceptable " "CA' info"); goto fail; } memset(&naca, 0, sizeof(naca)); tmp = asn_decompose("aca.RelativeDistinguishedName." "AttributeValueAssertion", &aca); if (!tmp) goto fail; x509_get_attribval(tmp, &naca.name1); tmp = asn_decompose("aca.RelativeDistinguishedName[1]" ".AttributeValueAssertion", &aca); if (tmp) x509_get_attribval(tmp, &naca.name2); asn_free(&aca); ret = malloc(sizeof(struct x509_aca)); if (ret) memcpy(ret, &naca, sizeof(struct x509_aca)); else { log_error("x509_certreq_decode: malloc (%lu) failed", (unsigned long) sizeof(struct x509_aca)); x509_free_aca(&aca); } return ret; fail: asn_free(&aca); #endif return 0; } void x509_free_aca(void *blob) { struct x509_aca *aca = blob; if (aca->name1.type) free(aca->name1.type); if (aca->name1.val) free(aca->name1.val); if (aca->name2.type) free(aca->name2.type); if (aca->name2.val) free(aca->name2.val); } X509 * x509_from_asn(u_char *asn, u_int len) { BIO *certh; X509 *scert = 0; certh = BIO_new(BIO_s_mem()); if (!certh) { log_error("x509_from_asn: BIO_new (BIO_s_mem ()) failed"); return 0; } if (BIO_write(certh, asn, len) == -1) { log_error("x509_from_asn: BIO_write failed\n"); goto end; } scert = d2i_X509_bio(certh, NULL); if (!scert) { log_print("x509_from_asn: d2i_X509_bio failed\n"); goto end; } end: BIO_free(certh); return scert; } /* * Obtain a certificate from an acceptable CA. * XXX We don't check if the certificate we find is from an accepted CA. */ int x509_cert_obtain(u_int8_t *id, size_t id_len, void *data, u_int8_t **cert, u_int32_t *certlen) { struct x509_aca *aca = data; X509 *scert; if (aca) LOG_DBG((LOG_CRYPTO, 60, "x509_cert_obtain: " "acceptable certificate authorities here")); /* We need our ID to find a certificate. */ if (!id) { log_print("x509_cert_obtain: ID is missing"); return 0; } scert = x509_hash_find(id, id_len); if (!scert) return 0; x509_serialize(scert, cert, certlen); if (!*cert) return 0; return 1; } /* Returns a pointer to the subjectAltName information of X509 certificate. */ int x509_cert_subjectaltname(X509 *scert, u_int8_t **altname, u_int32_t *len) { X509_EXTENSION *subjectaltname; u_int8_t *sandata; int extpos, santype, sanlen; extpos = X509_get_ext_by_NID(scert, NID_subject_alt_name, -1); if (extpos == -1) { log_print("x509_cert_subjectaltname: " "certificate does not contain subjectAltName"); return 0; } subjectaltname = X509_get_ext(scert, extpos); if (!subjectaltname || !subjectaltname->value || !subjectaltname->value->data || subjectaltname->value->length < 4) { log_print("x509_cert_subjectaltname: invalid " "subjectaltname extension"); return 0; } /* SSL does not handle unknown ASN stuff well, do it by hand. */ sandata = subjectaltname->value->data; santype = sandata[2] & 0x3f; sanlen = sandata[3]; sandata += 4; if (sanlen + 4 != subjectaltname->value->length) { log_print("x509_cert_subjectaltname: subjectaltname invalid " "length"); return 0; } *len = sanlen; *altname = sandata; return santype; } int x509_cert_get_subjects(void *scert, int *cnt, u_int8_t ***id, u_int32_t **id_len) { X509 *cert = scert; X509_NAME *subject; int type; u_int8_t *altname; u_int32_t altlen; u_int8_t *buf = 0; unsigned char *ubuf; int i; *id = 0; *id_len = 0; /* * XXX There can be a collection of subjectAltNames, but for now I * only return the subjectName and a single subjectAltName, if * present. */ type = x509_cert_subjectaltname(cert, &altname, &altlen); if (!type) { *cnt = 1; altlen = 0; } else *cnt = 2; *id = calloc(*cnt, sizeof **id); if (!*id) { log_print("x509_cert_get_subject: malloc (%lu) failed", *cnt * (unsigned long)sizeof **id); goto fail; } *id_len = malloc(*cnt * sizeof **id_len); if (!*id_len) { log_print("x509_cert_get_subject: malloc (%lu) failed", *cnt * (unsigned long)sizeof **id_len); goto fail; } /* Stash the subjectName into the first slot. */ subject = X509_get_subject_name(cert); if (!subject) goto fail; (*id_len)[0] = ISAKMP_ID_DATA_OFF + i2d_X509_NAME(subject, NULL) - ISAKMP_GEN_SZ; (*id)[0] = malloc((*id_len)[0]); if (!(*id)[0]) { log_print("x509_cert_get_subject: malloc (%d) failed", (*id_len)[0]); goto fail; } SET_ISAKMP_ID_TYPE((*id)[0] - ISAKMP_GEN_SZ, IPSEC_ID_DER_ASN1_DN); ubuf = (*id)[0] + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ; i2d_X509_NAME(subject, &ubuf); if (altlen) { /* Stash the subjectAltName into the second slot. */ buf = malloc(altlen + ISAKMP_ID_DATA_OFF); if (!buf) { log_print("x509_cert_get_subject: malloc (%d) failed", altlen + ISAKMP_ID_DATA_OFF); goto fail; } switch (type) { case X509v3_DNS_NAME: SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_FQDN); break; case X509v3_RFC_NAME: SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_USER_FQDN); break; case X509v3_IP_ADDR: /* * XXX I dislike the numeric constants, but I don't * know what we should use otherwise. */ switch (altlen) { case 4: SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR); break; case 16: SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR); break; default: log_print("x509_cert_get_subject: invalid " "subjectAltName IPaddress length %d ", altlen); goto fail; } break; } SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0); SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0); memcpy(buf + ISAKMP_ID_DATA_OFF, altname, altlen); (*id_len)[1] = ISAKMP_ID_DATA_OFF + altlen - ISAKMP_GEN_SZ; (*id)[1] = malloc((*id_len)[1]); if (!(*id)[1]) { log_print("x509_cert_get_subject: malloc (%d) failed", (*id_len)[1]); goto fail; } memcpy((*id)[1], buf + ISAKMP_GEN_SZ, (*id_len)[1]); free(buf); buf = 0; } return 1; fail: for (i = 0; i < *cnt; i++) if ((*id)[i]) free((*id)[i]); if (*id) free(*id); if (*id_len) free(*id_len); if (buf) free(buf); return 0; } int x509_cert_get_key(void *scert, void *keyp) { X509 *cert = scert; EVP_PKEY *key; key = X509_get_pubkey(cert); /* Check if we got the right key type. */ if (key->type != EVP_PKEY_RSA) { log_print("x509_cert_get_key: public key is not a RSA key"); X509_free(cert); return 0; } *(RSA **)keyp = RSAPublicKey_dup(key->pkey.rsa); return *(RSA **)keyp == NULL ? 0 : 1; } void * x509_cert_dup(void *scert) { return X509_dup(scert); } void x509_serialize(void *scert, u_int8_t **data, u_int32_t *datalen) { u_int8_t *p; *datalen = i2d_X509((X509 *)scert, NULL); *data = p = malloc(*datalen); if (!p) { log_error("x509_serialize: malloc (%d) failed", *datalen); return; } *datalen = i2d_X509((X509 *)scert, &p); } /* From cert to printable */ char * x509_printable(void *cert) { char *s; u_int8_t *data; u_int32_t datalen, i; x509_serialize(cert, &data, &datalen); if (!data) return 0; s = malloc(datalen * 2 + 1); if (!s) { free(data); log_error("x509_printable: malloc (%d) failed", datalen * 2 + 1); return 0; } for (i = 0; i < datalen; i++) snprintf(s + (2 * i), 2 * (datalen - i) + 1, "%02x", data[i]); free(data); return s; } /* From printable to cert */ void * x509_from_printable(char *cert) { u_int8_t *buf; int plen, ret; void *foo; plen = (strlen(cert) + 1) / 2; buf = malloc(plen); if (!buf) { log_error("x509_from_printable: malloc (%d) failed", plen); return 0; } ret = hex2raw(cert, buf, plen); if (ret == -1) { free(buf); log_print("x509_from_printable: badly formatted cert"); return 0; } foo = x509_cert_get(buf, plen); free(buf); if (!foo) log_print("x509_from_printable: " "could not retrieve certificate"); return foo; } char * x509_DN_string(u_int8_t *asn1, size_t sz) { X509_NAME *name; u_int8_t *p = asn1; char buf[256]; /* XXX Just a guess at a maximum length. */ name = d2i_X509_NAME(NULL, &p, sz); if (!name) { log_print("x509_DN_string: d2i_X509_NAME failed"); return 0; } if (!X509_NAME_oneline(name, buf, sizeof buf - 1)) { log_print("x509_DN_string: X509_NAME_oneline failed"); X509_NAME_free(name); return 0; } X509_NAME_free(name); buf[sizeof buf - 1] = '\0'; return strdup(buf); } #endif /* USE_X509 */ isakmpd-20041012.orig/key.h0000644000175000017500000000277210133045740015526 0ustar jdivejdive00000000000000/* $OpenBSD: key.h,v 1.7 2004/04/15 18:39:26 deraadt Exp $ */ /* * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) * * Copyright (c) 2000-2001 Angelos D. Keromytis. * * Permission to use, copy, and modify this software with or without fee * is hereby granted, provided that this entire notice is included in * all copies of any software which is or includes a copy or * modification of this software. * You may use this code under the GNU public license if you so wish. Please * contribute changes back to the authors under this freer than GPL license * so that we may further the use of strong encryption without limitations to * all. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR * PURPOSE. */ #ifndef _KEY_H_ #define _KEY_H_ #define ISAKMP_KEY_NONE 0 #define ISAKMP_KEY_PASSPHRASE 1 #define ISAKMP_KEY_RSA 2 #define ISAKMP_KEY_DSA 3 #define ISAKMP_KEYTYPE_PUBLIC 0 #define ISAKMP_KEYTYPE_PRIVATE 1 void key_free(int, int, void *); void key_serialize(int, int, void *, u_int8_t **, size_t *); char *key_printable(int, int, u_int8_t *, int); void key_from_printable(int, int, char *, u_int8_t **, u_int32_t *); void *key_internalize(int, int, u_int8_t *, int); #endif /* _KEY_H_ */ isakmpd-20041012.orig/udp.c0000644000175000017500000003464210133045740015522 0ustar jdivejdive00000000000000/* $OpenBSD: udp.c,v 1.79 2004/08/08 19:11:06 deraadt Exp $ */ /* $EOM: udp.c,v 1.57 2001/01/26 10:09:57 niklas Exp $ */ /* * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. * Copyright (c) 2000 Angelos D. Keromytis. All rights reserved. * Copyright (c) 2003, 2004 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #ifndef linux #include #endif #include #include #include #include #include #include #include #include #include #include #include "sysdep.h" #include "conf.h" #include "if.h" #include "isakmp.h" #include "log.h" #include "message.h" #include "monitor.h" #include "sysdep.h" #include "transport.h" #include "udp.h" #include "util.h" #include "virtual.h" #define UDP_SIZE 65536 /* If a system doesn't have SO_REUSEPORT, SO_REUSEADDR will have to do. */ #ifndef SO_REUSEPORT #define SO_REUSEPORT SO_REUSEADDR #endif /* These are reused by udp_encap.c, thus not 'static' here. */ struct transport *udp_clone(struct transport *, struct sockaddr *); int udp_fd_set(struct transport *, fd_set *, int); int udp_fd_isset(struct transport *, fd_set *); void udp_get_dst(struct transport *, struct sockaddr **); void udp_get_src(struct transport *, struct sockaddr **); char *udp_decode_ids(struct transport *); void udp_remove(struct transport *); static struct transport *udp_create(char *); static void udp_report(struct transport *); static void udp_handle_message(struct transport *); static struct transport *udp_make(struct sockaddr *); static int udp_send_message(struct message *, struct transport *); #if 0 static in_port_t udp_decode_port(char *); #endif static struct transport_vtbl udp_transport_vtbl = { {0}, "udp_physical", udp_create, 0, udp_remove, udp_report, udp_fd_set, udp_fd_isset, udp_handle_message, udp_send_message, udp_get_dst, udp_get_src, udp_decode_ids, udp_clone, 0 }; char *udp_default_port = 0; char *udp_bind_port = 0; int bind_family = 0; void udp_init(void) { transport_method_add(&udp_transport_vtbl); } /* Create a UDP transport structure bound to LADDR just for listening. */ static struct transport * udp_make(struct sockaddr *laddr) { struct udp_transport *t = 0; int s, on, wildcardaddress = 0; char *tstr; t = calloc(1, sizeof *t); if (!t) { log_print("udp_make: calloc (1, %lu) failed", (unsigned long)sizeof *t); free(laddr); return 0; } t->src = laddr; s = socket(laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP); if (s == -1) { log_error("udp_make: socket (%d, %d, %d)", laddr->sa_family, SOCK_DGRAM, IPPROTO_UDP); goto err; } /* Make sure we don't get our traffic encrypted. */ if (sysdep_cleartext(s, laddr->sa_family) == -1) goto err; /* Wildcard address ? */ switch (laddr->sa_family) { case AF_INET: if (((struct sockaddr_in *)laddr)->sin_addr.s_addr == INADDR_ANY) wildcardaddress = 1; break; case AF_INET6: if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)laddr)->sin6_addr)) wildcardaddress = 1; break; } /* * In order to have several bound specific address-port combinations * with the same port SO_REUSEADDR is needed. If this is a wildcard * socket and we are not listening there, but only sending from it * make sure it is entirely reuseable with SO_REUSEPORT. */ on = 1; if (setsockopt(s, SOL_SOCKET, wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR, (void *)&on, sizeof on) == -1) { log_error("udp_make: setsockopt (%d, %d, %d, %p, %lu)", s, SOL_SOCKET, wildcardaddress ? SO_REUSEPORT : SO_REUSEADDR, &on, (unsigned long)sizeof on); goto err; } t->transport.vtbl = &udp_transport_vtbl; if (monitor_bind(s, t->src, sysdep_sa_len(t->src))) { if (sockaddr2text(t->src, &tstr, 0)) log_error("udp_make: bind (%d, %p, %lu)", s, &t->src, (unsigned long)sizeof t->src); else { log_error("udp_make: bind (%d, %s, %lu)", s, tstr, (unsigned long)sizeof t->src); free(tstr); } goto err; } t->s = s; if (sockaddr2text(t->src, &tstr, 0)) LOG_DBG((LOG_MISC, 20, "udp_make: " "transport %p socket %d family %d", t, s, t->src->sa_family == AF_INET ? 4 : 6)); else { LOG_DBG((LOG_MISC, 20, "udp_make: " "transport %p socket %d ip %s port %d", t, s, tstr, ntohs(sockaddr_port(t->src)))); free (tstr); } transport_setup(&t->transport, 0); t->transport.flags |= TRANSPORT_LISTEN; return &t->transport; err: if (s >= 0) close(s); if (t) { /* Already closed. */ t->s = -1; udp_remove(&t->transport); } return 0; } /* Clone a listen transport U, record a destination RADDR for outbound use. */ struct transport * udp_clone(struct transport *ut, struct sockaddr *raddr) { struct udp_transport *u = (struct udp_transport *)ut; struct udp_transport *u2; struct transport *t; t = malloc(sizeof *u); if (!t) { log_error("udp_clone: malloc (%lu) failed", (unsigned long)sizeof *u); return 0; } u2 = (struct udp_transport *)t; memcpy(u2, u, sizeof *u); u2->src = malloc(sysdep_sa_len(u->src)); if (!u2->src) { log_error("udp_clone: malloc (%d) failed", sysdep_sa_len(u->src)); free(t); return 0; } memcpy(u2->src, u->src, sysdep_sa_len(u->src)); u2->dst = malloc(sysdep_sa_len(raddr)); if (!u2->dst) { log_error("udp_clone: malloc (%d) failed", sysdep_sa_len(raddr)); free(u2->src); free(t); return 0; } memcpy(u2->dst, raddr, sysdep_sa_len(raddr)); t->flags &= ~TRANSPORT_LISTEN; transport_setup(t, 0); return t; } /* * Initialize an object of the UDP transport class. Fill in the local * IP address and port information and create a server socket bound to * that specific port. Add the polymorphic transport structure to the * system-wide pools of known ISAKMP transports. */ struct transport * udp_bind(const struct sockaddr *addr) { struct sockaddr *src; src = malloc(sysdep_sa_len((struct sockaddr *)addr)); if (!src) return 0; memcpy(src, addr, sysdep_sa_len((struct sockaddr *)addr)); return udp_make(src); } /* * NAME is a section name found in the config database. Setup and return * a transport useable to talk to the peer specified by that name. */ static struct transport * udp_create(char *name) { struct virtual_transport *v; struct udp_transport *u; struct transport *rv, *t; struct sockaddr *dst, *addr; char *addr_str, *port_str; struct conf_list *addr_list = 0; struct conf_list_node *addr_node; port_str = conf_get_str(name, "Port"); if (!port_str) port_str = udp_default_port; if (!port_str) port_str = UDP_DEFAULT_PORT_STR; addr_str = conf_get_str(name, "Address"); if (!addr_str) { log_print("udp_create: no address configured for \"%s\"", name); return 0; } if (text2sockaddr(addr_str, port_str, &dst)) { log_print("udp_create: address \"%s\" not understood", addr_str); return 0; } addr_str = conf_get_str(name, "Local-address"); if (!addr_str) addr_list = conf_get_list("General", "Listen-on"); if (!addr_str && !addr_list) { v = virtual_get_default(dst->sa_family); u = (struct udp_transport *)v->main; if (!u) { log_print("udp_create: no default transport"); rv = 0; goto ret; } else { rv = udp_clone((struct transport *)u, dst); if (rv) rv->vtbl = &udp_transport_vtbl; goto ret; } } if (addr_list) { for (addr_node = TAILQ_FIRST(&addr_list->fields); addr_node; addr_node = TAILQ_NEXT(addr_node, link)) if (text2sockaddr(addr_node->field, port_str, &addr) == 0) { v = virtual_listen_lookup(addr); free(addr); if (v) { addr_str = addr_node->field; break; } } if (!addr_str) { log_print("udp_create: no matching listener found"); rv = 0; goto ret; } } if (text2sockaddr(addr_str, port_str, &addr)) { log_print("udp_create: address \"%s\" not understood", addr_str); rv = 0; goto ret; } v = virtual_listen_lookup(addr); free(addr); if (!v) { log_print("udp_create: %s:%s must exist as a listener too", addr_str, port_str); rv = 0; goto ret; } t = (struct transport *)v; rv = udp_clone(v->main, dst); if (rv) rv->vtbl = &udp_transport_vtbl; ret: if (addr_list) conf_free_list(addr_list); free(dst); return rv; } void udp_remove(struct transport *t) { struct udp_transport *u = (struct udp_transport *)t; if (u->src) free(u->src); if (u->dst) free(u->dst); if ((t->flags & TRANSPORT_LISTEN) && u->s >= 0) close(u->s); if (t->link.le_prev) LIST_REMOVE(t, link); LOG_DBG((LOG_TRANSPORT, 90, "udp_remove: removed transport %p", t)); free(t); } /* Report transport-method specifics of the T transport. */ void udp_report(struct transport *t) { struct udp_transport *u = (struct udp_transport *)t; char *src = NULL, *dst = NULL; in_port_t sport, dport; if (sockaddr2text(u->src, &src, 0)) goto ret; sport = sockaddr_port(u->src); if (!u->dst || sockaddr2text(u->dst, &dst, 0)) dst = 0; dport = dst ? sockaddr_port(u->dst) : 0; LOG_DBG((LOG_REPORT, 0, "udp_report: fd %d src %s:%u dst %s:%u", u->s, src, ntohs(sport), dst ? dst : "", ntohs(dport))); ret: if (dst) free(dst); if (src) free(src); } /* * A message has arrived on transport T's socket. If T is single-ended, * clone it into a double-ended transport which we will use from now on. * Package the message as we want it and continue processing in the message * module. */ static void udp_handle_message(struct transport *t) { struct udp_transport *u = (struct udp_transport *)t; u_int8_t buf[UDP_SIZE]; struct sockaddr_storage from; u_int32_t len = sizeof from; ssize_t n; struct message *msg; n = recvfrom(u->s, buf, UDP_SIZE, 0, (struct sockaddr *)&from, &len); if (n == -1) { log_error("recvfrom (%d, %p, %d, %d, %p, %p)", u->s, buf, UDP_SIZE, 0, &from, &len); return; } /* * Make a specialized UDP transport structure out of the incoming * transport and the address information we got from recvfrom(2). */ t = t->virtual->vtbl->clone(t->virtual, (struct sockaddr *)&from); if (!t) return; msg = message_alloc(t, buf, n); if (!msg) { log_error("failed to allocate message structure, dropping " "packet received on transport %p", u); t->vtbl->remove(t); return; } message_recv(msg); } /* Physically send the message MSG over its associated transport. */ static int udp_send_message(struct message *msg, struct transport *t) { struct udp_transport *u = (struct udp_transport *)t; ssize_t n; struct msghdr m; /* * Sending on connected sockets requires that no destination address is * given, or else EISCONN will occur. */ m.msg_name = (caddr_t) u->dst; m.msg_namelen = sysdep_sa_len(u->dst); m.msg_iov = msg->iov; m.msg_iovlen = msg->iovlen; m.msg_control = 0; m.msg_controllen = 0; m.msg_flags = 0; n = sendmsg(u->s, &m, 0); if (n == -1) { /* XXX We should check whether the address has gone away */ log_error("sendmsg (%d, %p, %d)", u->s, &m, 0); return -1; } return 0; } int udp_fd_set(struct transport *t, fd_set *fds, int bit) { struct udp_transport *u = (struct udp_transport *)t; if (bit) FD_SET(u->s, fds); else FD_CLR(u->s, fds); return u->s + 1; } int udp_fd_isset(struct transport *t, fd_set *fds) { struct udp_transport *u = (struct udp_transport *)t; return FD_ISSET(u->s, fds); } /* * Get transport T's peer address and stuff it into the sockaddr pointed * to by DST. */ void udp_get_dst(struct transport *t, struct sockaddr **dst) { *dst = ((struct udp_transport *)t)->dst; } /* * Get transport T's local address and stuff it into the sockaddr pointed * to by SRC. Put its length into SRC_LEN. */ void udp_get_src(struct transport *t, struct sockaddr **src) { *src = ((struct udp_transport *)t)->src; } char * udp_decode_ids(struct transport *t) { struct sockaddr *src, *dst; static char result[1024]; char idsrc[256], iddst[256]; t->vtbl->get_src(t, &src); t->vtbl->get_dst(t, &dst); if (getnameinfo(src, sysdep_sa_len(src), idsrc, sizeof idsrc, NULL, 0, NI_NUMERICHOST) != 0) { log_print("udp_decode_ids: getnameinfo () failed for 'src'"); strlcpy(idsrc, "", 256); } if (getnameinfo(dst, sysdep_sa_len(dst), iddst, sizeof iddst, NULL, 0, NI_NUMERICHOST) != 0) { log_print("udp_decode_ids: getnameinfo () failed for 'dst'"); strlcpy(iddst, "", 256); } snprintf(result, sizeof result, "src: %s dst: %s", idsrc, iddst); return result; } #if 0 /* * Take a string containing an ext representation of port and return a * binary port number in host byte order. Return zero if anything goes wrong. * XXX Currently unused. */ static in_port_t udp_decode_port(char *port_str) { char *port_str_end; long port_long; struct servent *service; port_long = ntohl(strtol(port_str, &port_str_end, 0)); if (port_str == port_str_end) { service = getservbyname(port_str, "udp"); if (!service) { log_print("udp_decode_port: service \"%s\" unknown", port_str); return 0; } return ntohs(service->s_port); } else if (port_long < 1 || port_long > 65535) { log_print("udp_decode_port: port %ld out of range", port_long); return 0; } return port_long; } #endif isakmpd-20041012.orig/cert.h0000644000175000017500000000711110133045740015663 0ustar jdivejdive00000000000000/* $OpenBSD: cert.h,v 1.14 2004/05/14 08:42:56 hshoexer Exp $ */ /* $EOM: cert.h,v 1.8 2000/09/28 12:53:27 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niels Provos. All rights reserved. * Copyright (c) 2000, 2001 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _CERT_H_ #define _CERT_H_ #include #include #include /* * CERT handler for each kind of certificate: * * cert_init - initialize CERT handler. * crl_init - initialize CRLs, if applicable. * cert_get - get a certificate in internal representation from raw data. * cert_validate - validated a certificate, if it returns != 0 we can use it. * cert_insert - inserts cert into memory storage, we can retrieve with * cert_obtain. * cert_dup - duplicate a certificate * cert_serialize - convert to a "serialized" form; KeyNote stays the same, * X509 is converted to the ASN1 notation. * cert_printable - for X509, the hex representation of the serialized form; * for KeyNote, itself. * cert_from_printable - the reverse of cert_printable */ struct cert_handler { u_int16_t id; /* ISAKMP Cert Encoding ID */ int (*cert_init)(void); int (*crl_init)(void); void *(*cert_get)(u_int8_t *, u_int32_t); int (*cert_validate)(void *); int (*cert_insert)(int, void *); void (*cert_free)(void *); int (*certreq_validate)(u_int8_t *, u_int32_t); void *(*certreq_decode)(u_int8_t *, u_int32_t); void (*free_aca)(void *); int (*cert_obtain)(u_int8_t *, size_t, void *, u_int8_t **, u_int32_t *); int (*cert_get_key) (void *, void *); int (*cert_get_subjects) (void *, int *, u_int8_t ***, u_int32_t **); void *(*cert_dup) (void *); void (*cert_serialize) (void *, u_int8_t **, u_int32_t *); char *(*cert_printable) (void *); void *(*cert_from_printable) (char *); }; /* The acceptable authority of cert request. */ struct certreq_aca { TAILQ_ENTRY(certreq_aca) link; u_int16_t id; struct cert_handler *handler; /* If data is a null pointer, everything is acceptable. */ void *data; }; struct certreq_aca *certreq_decode(u_int16_t, u_int8_t *, u_int32_t); void cert_free_subjects(int, u_int8_t **, u_int32_t *); struct cert_handler *cert_get(u_int16_t); int cert_init(void); int crl_init(void); #endif /* _CERT_H_ */ isakmpd-20041012.orig/sysdep/0000755000175000017500000000000010133045740016064 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/linux/0000755000175000017500000000000010133045740017223 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/linux/bitstring.h0000644000175000017500000001033110133045740021377 0ustar jdivejdive00000000000000/* $OpenBSD: bitstring.h,v 1.1 2003/09/02 18:11:15 ho Exp $ */ /* $NetBSD: bitstring.h,v 1.5 1997/05/14 15:49:55 pk Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Paul Vixie. * * 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. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. * * @(#)bitstring.h 8.1 (Berkeley) 7/19/93 */ #ifndef _BITSTRING_H_ #define _BITSTRING_H_ /* modified for SV/AT and bitstring bugfix by M.R.Murphy, 11oct91 * bitstr_size changed gratuitously, but shorter * bit_alloc spelling error fixed * the following were efficient, but didn't work, they've been made to * work, but are no longer as efficient :-) * bit_nclear, bit_nset, bit_ffc, bit_ffs */ typedef unsigned char bitstr_t; /* internal macros */ /* byte of the bitstring bit is in */ #define _bit_byte(bit) \ ((bit) >> 3) /* mask for the bit within its byte */ #define _bit_mask(bit) \ (1 << ((bit)&0x7)) /* external macros */ /* bytes in a bitstring of nbits bits */ #define bitstr_size(nbits) \ (((nbits) + 7) >> 3) /* allocate a bitstring */ #define bit_alloc(nbits) \ (bitstr_t *)calloc((size_t)bitstr_size(nbits), sizeof(bitstr_t)) /* allocate a bitstring on the stack */ #define bit_decl(name, nbits) \ ((name)[bitstr_size(nbits)]) /* is bit N of bitstring name set? */ #define bit_test(name, bit) \ ((name)[_bit_byte(bit)] & _bit_mask(bit)) /* set bit N of bitstring name */ #define bit_set(name, bit) \ ((name)[_bit_byte(bit)] |= _bit_mask(bit)) /* clear bit N of bitstring name */ #define bit_clear(name, bit) \ ((name)[_bit_byte(bit)] &= ~_bit_mask(bit)) /* clear bits start ... stop in bitstring */ #define bit_nclear(name, start, stop) do { \ register bitstr_t *_name = name; \ register int _start = start, _stop = stop; \ while (_start <= _stop) { \ bit_clear(_name, _start); \ _start++; \ } \ } while(0) /* set bits start ... stop in bitstring */ #define bit_nset(name, start, stop) do { \ register bitstr_t *_name = name; \ register int _start = start, _stop = stop; \ while (_start <= _stop) { \ bit_set(_name, _start); \ _start++; \ } \ } while(0) /* find first bit clear in name */ #define bit_ffc(name, nbits, value) do { \ register bitstr_t *_name = name; \ register int _bit, _nbits = nbits, _value = -1; \ for (_bit = 0; _bit < _nbits; ++_bit) \ if (!bit_test(_name, _bit)) { \ _value = _bit; \ break; \ } \ *(value) = _value; \ } while(0) /* find first bit set in name */ #define bit_ffs(name, nbits, value) do { \ register bitstr_t *_name = name; \ register int _bit, _nbits = nbits, _value = -1; \ for (_bit = 0; _bit < _nbits; ++_bit) \ if (bit_test(_name, _bit)) { \ _value = _bit; \ break; \ } \ *(value) = _value; \ } while(0) #endif /* !_BITSTRING_H_ */ isakmpd-20041012.orig/sysdep/linux/sysdep.c0000644000175000017500000001326510133045740020705 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep.c,v 1.16 2004/08/10 15:59:10 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. * Copyright (c) 2003 Thomas Walpuski. 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. * * 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 #include #include #include #include #include #include "sysdep.h" #include "util.h" #ifdef NEED_SYSDEP_APP #include "app.h" #include "conf.h" #include "ipsec.h" #include #include #ifdef USE_PF_KEY_V2 #include "pf_key_v2.h" #define KEY_API(x) pf_key_v2_##x #endif #endif /* NEED_SYSDEP_APP */ #include "log.h" extern char *__progname; /* * An as strong as possible random number generator, reverting to a * deterministic pseudo-random one if regrand is set. */ u_int32_t sysdep_random () { return arc4random(); } /* Return the basename of the command used to invoke us. */ char * sysdep_progname () { return __progname; } /* Return the length of the sockaddr struct. */ u_int8_t sysdep_sa_len (struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET: return sizeof (struct sockaddr_in); case AF_INET6: return sizeof (struct sockaddr_in6); default: log_print ("sysdep_sa_len: unknown sa family %d", sa->sa_family); } return sizeof (struct sockaddr_in); } /* As regress/ use this file I protect the sysdep_app_* stuff like this. */ #ifdef NEED_SYSDEP_APP /* * Prepare the application we negotiate SAs for (i.e. the IPsec stack) * for communication. We return a file descriptor useable to select(2) on. */ int sysdep_app_open () { return KEY_API(open) (); } /* * When select(2) has noticed our application needs attendance, this is what * gets called. FD is the file descriptor causing the alarm. */ void sysdep_app_handler (int fd) { KEY_API (handler) (fd); } /* Check that the connection named NAME is active, or else make it active. */ void sysdep_connection_check (char *name) { KEY_API (connection_check) (name); } /* * Generate a SPI for protocol PROTO and the source/destination pair given by * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. */ u_int8_t * sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, struct sockaddr *dst, u_int32_t seq) { if (app_none) { *sz = IPSEC_SPI_SIZE; /* XXX should be random instead I think. */ return strdup ("\x12\x34\x56\x78"); } return KEY_API (get_spi) (sz, proto, src, dst, seq); } struct sa_kinfo * sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, struct sockaddr *dst) { if (app_none) return 0; /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ return 0; } /* Force communication on socket FD to go in the clear. */ int sysdep_cleartext (int fd, int af) { struct sadb_x_policy pol_in = { SADB_UPDATE, SADB_EXT_SENSITIVITY, IPSEC_POLICY_BYPASS, IPSEC_DIR_INBOUND, 0, 0, 0 }; struct sadb_x_policy pol_out = { SADB_UPDATE, SADB_EXT_SENSITIVITY, IPSEC_POLICY_BYPASS, IPSEC_DIR_OUTBOUND, 0, 0, 0 }; if (app_none) return 0; if (!(af == AF_INET || af == AF_INET6)) { log_print ("sysdep_cleartext: unsupported protocol family %d", af); return -1; } if (setsockopt (fd, af == AF_INET ? IPPROTO_IP : IPPROTO_IPV6, af == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY, &pol_in, sizeof pol_in) < 0 || setsockopt (fd, af == AF_INET ? IPPROTO_IP : IPPROTO_IPV6, af == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY, &pol_out, sizeof pol_out) < 0) { log_error ("sysdep_cleartext: " "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) " "failed", fd, af == AF_INET ? "" : "V6", af == AF_INET ? "" : "V6"); return -1; } return 0; } int sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) { if (app_none) return 0; return KEY_API (delete_spi) (sa, proto, incoming); } int sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API (enable_sa) (sa, isakmp_sa); } int sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2, int incoming) { if (app_none) return 0; return KEY_API (group_spis) (sa, proto1, proto2, incoming); } int sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa); } #endif isakmpd-20041012.orig/sysdep/linux/sys/0000755000175000017500000000000010133045740020041 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/linux/sys/queue.h0000644000175000017500000004124610133045740021345 0ustar jdivejdive00000000000000/* $OpenBSD: queue.h,v 1.7 2004/04/08 16:08:21 henning Exp $ */ /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues, and circular queues. * * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at * the expense of O(n) removal for arbitrary elements. New elements can be * added to the list after an existing element or at the head of the list. * Elements being removed from the head of the list should use the explicit * macro for this purpose for optimum efficiency. A singly-linked list may * only be traversed in the forward direction. Singly-linked lists are ideal * for applications with large datasets and few or no removals or for * implementing a LIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A simple queue is headed by a pair of pointers, one the head of the * list and the other to the tail of the list. The elements are singly * linked to save space, so elements can only be removed from the * head of the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the * list. A simple queue may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * A circle queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the list. * A circle queue may be traversed in either direction, but has a more * complex end of list detection. * * For details on the use of these macros, see the queue(3) manual page. */ /* * Singly-linked List definitions. */ #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_HEAD_INITIALIZER(head) \ { NULL } #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List access methods. */ #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_END(head) NULL #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_FOREACH(var, head, field) \ for((var) = SLIST_FIRST(head); \ (var) != SLIST_END(head); \ (var) = SLIST_NEXT(var, field)) /* * Singly-linked List functions. */ #define SLIST_INIT(head) { \ SLIST_FIRST(head) = SLIST_END(head); \ } #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (0) #define SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (0) #define SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } \ else { \ struct type *curelm = (head)->slh_first; \ while( curelm->field.sle_next != (elm) ) \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ } \ } while (0) /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List access methods */ #define LIST_FIRST(head) ((head)->lh_first) #define LIST_END(head) NULL #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_FOREACH(var, head, field) \ for((var) = LIST_FIRST(head); \ (var)!= LIST_END(head); \ (var) = LIST_NEXT(var, field)) /* * List functions. */ #define LIST_INIT(head) do { \ LIST_FIRST(head) = LIST_END(head); \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (0) #define LIST_REMOVE(elm, field) do { \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ } while (0) #define LIST_REPLACE(elm, elm2, field) do { \ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ (elm2)->field.le_next->field.le_prev = \ &(elm2)->field.le_next; \ (elm2)->field.le_prev = (elm)->field.le_prev; \ *(elm2)->field.le_prev = (elm2); \ } while (0) /* * Simple queue definitions. */ #define SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } #define SIMPLEQ_HEAD_INITIALIZER(head) \ { NULL, &(head).sqh_first } #define SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } /* * Simple queue access methods. */ #define SIMPLEQ_FIRST(head) ((head)->sqh_first) #define SIMPLEQ_END(head) NULL #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) #define SIMPLEQ_FOREACH(var, head, field) \ for((var) = SIMPLEQ_FIRST(head); \ (var) != SIMPLEQ_END(head); \ (var) = SIMPLEQ_NEXT(var, field)) /* * Simple queue functions. */ #define SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (0) #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (0) #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (0) #define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \ if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) /* * Tail queue definitions. */ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } /* * tail queue access methods */ #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_END(head) NULL #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) /* XXX */ #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_EMPTY(head) \ (TAILQ_FIRST(head) == TAILQ_END(head)) #define TAILQ_FOREACH(var, head, field) \ for((var) = TAILQ_FIRST(head); \ (var) != TAILQ_END(head); \ (var) = TAILQ_NEXT(var, field)) #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for((var) = TAILQ_LAST(head, headname); \ (var) != TAILQ_END(head); \ (var) = TAILQ_PREV(var, headname, field)) /* * Tail queue functions. */ #define TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_REMOVE(head, elm, field) do { \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ } while (0) #define TAILQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ (elm2)->field.tqe_next->field.tqe_prev = \ &(elm2)->field.tqe_next; \ else \ (head)->tqh_last = &(elm2)->field.tqe_next; \ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ *(elm2)->field.tqe_prev = (elm2); \ } while (0) /* * Circular queue definitions. */ #define CIRCLEQ_HEAD(name, type) \ struct name { \ struct type *cqh_first; /* first element */ \ struct type *cqh_last; /* last element */ \ } #define CIRCLEQ_HEAD_INITIALIZER(head) \ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } #define CIRCLEQ_ENTRY(type) \ struct { \ struct type *cqe_next; /* next element */ \ struct type *cqe_prev; /* previous element */ \ } /* * Circular queue access methods */ #define CIRCLEQ_FIRST(head) ((head)->cqh_first) #define CIRCLEQ_LAST(head) ((head)->cqh_last) #define CIRCLEQ_END(head) ((void *)(head)) #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) #define CIRCLEQ_EMPTY(head) \ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) #define CIRCLEQ_FOREACH(var, head, field) \ for((var) = CIRCLEQ_FIRST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_NEXT(var, field)) #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ for((var) = CIRCLEQ_LAST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_PREV(var, field)) /* * Circular queue functions. */ #define CIRCLEQ_INIT(head) do { \ (head)->cqh_first = CIRCLEQ_END(head); \ (head)->cqh_last = CIRCLEQ_END(head); \ } while (0) #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ (elm)->field.cqe_prev = (listelm); \ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ (listelm)->field.cqe_next = (elm); \ } while (0) #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm); \ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ (listelm)->field.cqe_prev = (elm); \ } while (0) #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.cqe_next = (head)->cqh_first; \ (elm)->field.cqe_prev = CIRCLEQ_END(head); \ if ((head)->cqh_last == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (head)->cqh_first->field.cqe_prev = (elm); \ (head)->cqh_first = (elm); \ } while (0) #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.cqe_next = CIRCLEQ_END(head); \ (elm)->field.cqe_prev = (head)->cqh_last; \ if ((head)->cqh_first == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (head)->cqh_last->field.cqe_next = (elm); \ (head)->cqh_last = (elm); \ } while (0) #define CIRCLEQ_REMOVE(head, elm, field) do { \ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm)->field.cqe_prev; \ else \ (elm)->field.cqe_next->field.cqe_prev = \ (elm)->field.cqe_prev; \ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm)->field.cqe_next; \ else \ (elm)->field.cqe_prev->field.cqe_next = \ (elm)->field.cqe_next; \ } while (0) #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ CIRCLEQ_END(head)) \ (head).cqh_last = (elm2); \ else \ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ CIRCLEQ_END(head)) \ (head).cqh_first = (elm2); \ else \ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ } while (0) #endif /* !_SYS_QUEUE_H_ */ isakmpd-20041012.orig/sysdep/linux/sys/CVS/0000755000175000017500000000000010133045751020476 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/linux/GNUmakefile.sysdep0000644000175000017500000000444710133045740022614 0ustar jdivejdive00000000000000# $OpenBSD: GNUmakefile.sysdep,v 1.9 2004/08/10 09:49:51 ho Exp $ # # Copyright (c) 1999 Niklas Hallqvist. All rights reserved. # Copyright (c) 2003 Thomas Walpuski. 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. # # 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. # LIBGMP:= /usr/lib/libgmp.a LIBCRYPTO:= /usr/lib/libcrypto.a LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a LDADD+= -lgmp ${LIBSYSDEP} ${LIBCRYPTO} DPADD+= ${LIBGMP} ${LIBSYSDEP} CFLAGS+= -DUSE_OLD_SOCKADDR -DHAVE_PCAP \ -DNEED_SYSDEP_APP -DMP_FLAVOUR=MP_FLAVOUR_GMP \ -I/usr/src/linux/include -I${.CURDIR}/sysdep/common \ -I/usr/include/openssl FEATURES= debug tripledes blowfish cast ec aggressive x509 policy FEATURES+= des aes IPSEC_SRCS= pf_key_v2.c IPSEC_CFLAGS= -DUSE_PF_KEY_V2 USE_LIBCRYPO= defined HAVE_DLOPEN= defined USE_KEYNOTE= defined # hack libsysdep.a dependenc ${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}: cd ${LIBSYSDEPDIR} && \ ${MAKE} --no-print-directory ${MAKEFLAGS} \ CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS} ifeq ($(findstring clean,$(MAKECMDGOALS)),clean) SUBDIR+= sysdep/common/libsysdep MAKEFLAGS+= --no-print-directory endif isakmpd-20041012.orig/sysdep/linux/sysdep-os.h0000644000175000017500000000424710133045740021331 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep-os.h,v 1.8 2003/06/03 15:20:41 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. * Copyright (c) 2003 Thomas Walpuski. 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. * * 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. */ #ifndef _SYSDEP_OS_H_ #define _SYSDEP_OS_H_ #include #include #include #include #define KAME #define LINUX_IPSEC #define uh_sport source #define uh_dport dest #define uh_ulen len #define uh_sum check #ifndef CPI_RESERVED_MAX #define CPI_RESERVED_MIN 1 #define CPI_RESERVED_MAX 255 #define CPI_PRIVATE_MIN 61440 #define CPI_PRIVATE_MAX 65536 #endif #define SADB_X_EALG_AES SADB_X_EALG_AESCBC #define SADB_X_EALG_CAST SADB_X_EALG_CASTCBC #define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC #define IP_IPSEC_POLICY 16 #define IPV6_IPSEC_POLICY 34 #define IPV6_VERSION 0x1 size_t strlcat(char *dst, const char *src, size_t siz); size_t strlcpy(char *dst, const char *src, size_t siz); #endif isakmpd-20041012.orig/sysdep/linux/CVS/0000755000175000017500000000000010133045751017660 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/freebsd/0000755000175000017500000000000010133045740017476 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/freebsd/Makefile.sysdep0000644000175000017500000000520110133045740022442 0ustar jdivejdive00000000000000# $OpenBSD: Makefile.sysdep,v 1.10 2004/06/26 03:40:57 mcbride Exp $ # # Copyright (c) 1999 Niklas Hallqvist. 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. # # 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 INN 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. # # # This code was written under funding by Ericsson Radio Systems. # # Override default features FEATURES= tripledes des blowfish cast x509 ec aggressive debug FEATURES+= rawkey # Not yet #FEATURES+= policy isakmp_cfg .if defined(TOPDIR) LIBSYSDEPDIR= ${TOPDIR}/sysdep/common/libsysdep .else LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep .endif LDADD+= -lgmp ${LIBSYSDEPDIR}/libsysdep.a -lipsec -L/usr/local/lib DPADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a CFLAGS+= -DHAVE_GETIFADDRS \ -I${.CURDIR}/sysdep/common -I/usr/include \ -I/usr/local/include -I/usr/local/include/openssl IPSEC_SRCS= pf_key_v2.c IPSEC_CFLAGS= -DUSE_PF_KEY_V2 USE_LIBCRYPTO= defined # This is a hack in order to make sure libsysdep is built before the # linkstage of isakmpd. As a side effect the link is always done even if # not necessary. Well, I just don't care. GENERATED+= sysdep-target sysdep-target: cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS} # Kludge around much strange behaviour in /usr/share/mk/bsd.*/mk, don't build certpatch SUBDIR= .if make(clean) SUBDIR+= sysdep/common/libsysdep .endif # Kludge around bug in /usr/share/mk/bsd.subdir.mk NO_REGRESS= defined # Kludge around bug/feature in /usr/share/mk/bsd.man.mk MAN8= isakmpd.8 MAN5= isakmpd.conf.5 isakmpd.policy.5 obj: mkdir obj isakmpd-20041012.orig/sysdep/freebsd/sysdep.c0000644000175000017500000001271510133045740021157 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep.c,v 1.13 2004/08/10 15:59:10 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include "sysdep.h" #include "util.h" #ifdef NEED_SYSDEP_APP #include "app.h" #include "conf.h" #include "ipsec.h" #ifdef USE_PF_KEY_V2 #include "pf_key_v2.h" #define KEY_API(x) pf_key_v2_##x #endif #endif /* NEED_SYSDEP_APP */ #include "log.h" extern char *__progname; /* * An as strong as possible random number generator, reverting to a * deterministic pseudo-random one if regrand is set. */ u_int32_t sysdep_random () { return random(); } /* Return the basename of the command used to invoke us. */ char * sysdep_progname () { return __progname; } /* Return the length of the sockaddr struct. */ u_int8_t sysdep_sa_len (struct sockaddr *sa) { return sa->sa_len; } /* As regress/ use this file I protect the sysdep_app_* stuff like this. */ #ifdef NEED_SYSDEP_APP /* * Prepare the application we negotiate SAs for (i.e. the IPsec stack) * for communication. We return a file descriptor useable to select(2) on. */ int sysdep_app_open () { return KEY_API(open) (); } /* * When select(2) has noticed our application needs attendance, this is what * gets called. FD is the file descriptor causing the alarm. */ void sysdep_app_handler (int fd) { KEY_API (handler) (fd); } /* Check that the connection named NAME is active, or else make it active. */ void sysdep_connection_check (char *name) { KEY_API (connection_check) (name); } /* * Generate a SPI for protocol PROTO and the source/destination pair given by * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. */ u_int8_t * sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, struct sockaddr *dst, u_int32_t seq) { if (app_none) { *sz = IPSEC_SPI_SIZE; /* XXX should be random instead I think. */ return strdup ("\x12\x34\x56\x78"); } return KEY_API (get_spi) (sz, proto, src, dst, seq); } struct sa_kinfo * sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, struct sockaddr *dst) { if (app_none) return 0; /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ return 0; } /* Force communication on socket FD to go in the clear. */ int sysdep_cleartext (int fd, int af) { char *buf; char *policy[] = { "in bypass", "out bypass", NULL }; char **p; int ipp; int opt; char *msgstr; if (app_none) return 0; switch (af) { case AF_INET: ipp = IPPROTO_IP; opt = IP_IPSEC_POLICY; msgstr = ""; break; case AF_INET6: ipp = IPPROTO_IPV6; opt = IPV6_IPSEC_POLICY; msgstr = "V6"; break; default: log_print ("sysdep_cleartext: unsupported protocol family %d", af); return -1; } /* * Need to bypass system security policy, so I can send and * receive key management datagrams in the clear. */ for (p = policy; p && *p; p++) { buf = ipsec_set_policy (*p, strlen(*p)); if (buf == NULL) { log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror()); return -1; } if (setsockopt(fd, ipp, opt, buf, ipsec_get_policylen(buf)) < 0) { log_error ("sysdep_cleartext: " "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) " "failed", fd, msgstr, msgstr); return -1; } free(buf); } return 0; } int sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) { if (app_none) return 0; return KEY_API (delete_spi) (sa, proto, incoming); } int sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API (enable_sa) (sa, isakmp_sa); } int sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2, int incoming) { if (app_none) return 0; return KEY_API (group_spis) (sa, proto1, proto2, incoming); } int sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa); } #endif isakmpd-20041012.orig/sysdep/freebsd/GNUmakefile.sysdep0000644000175000017500000000427310133045740023064 0ustar jdivejdive00000000000000# $OpenBSD: GNUmakefile.sysdep,v 1.6 2004/06/26 03:40:57 mcbride Exp $ # # Copyright (c) 1999 Håkan Olsson. All rights reserved. # Copyright (c) 1999 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # LIBGMP:= /usr/lib/libgmp.a LIBCRYPTO:= /usr/lib/libcrypto.a LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a LDADD+= -lgmp ${LIBSYSDEP} DPADD+= ${LIBGMP} ${LIBSYSDEP} FEATURES= debug tripledes des blowdish cast ec aggressive # Not yet #FEATURES+= policy x509 IPSEC_SRCS= pf_key_v2.c IPSEC_CFLAGS= -DUSE_PF_KEY_V2 USE_LIBCRYPTO= defined # hack libsysdep.a dependency ${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}: cd ${LIBSYSDEPDIR} && ${MAKE} --no-print-directory ${MAKEFLAGS} \ CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS} depend: ${LIBSYSDEPDIR}/.depend ifeq ($(findstring clean, $(MAKECMDGOALS)), clean) SUBDIR+= sysdep/common/libsysdep MAKEFLAGS+= --no-print-directory endif isakmpd-20041012.orig/sysdep/freebsd/sysdep-os.h0000644000175000017500000000511710133045740021601 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep-os.h,v 1.5 2003/06/03 14:53:11 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _SYSDEP_OS_H_ #define _SYSDEP_OS_H_ #define KAME #include #if ( __FreeBSD_cc_version < 440000 ) /* We need in_addr_t & in_port_t */ typedef u_int32_t in_addr_t; typedef u_int16_t in_port_t; #endif #if ( __FreeBSD__ < 4 ) /* We need socklen_t too. */ typedef u_int32_t socklen_t; #endif /* Map extensions to values from /usr/include/net/pfkeyv2.h */ #if ( SADB_EALG_MAX == 7 ) /* FreeBSD 4.2 */ #define SADB_X_EALG_BLF SADB_EALG_BLOWFISHCBC #define SADB_X_EALG_CAST SADB_EALG_CAST128CBC #else if ( SADB_EALG_MAX == 12 ) /* FreeBSD 4.4 */ #define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC #define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC #endif #if 0 /* OpenSSL differs from OpenBSD very slightly... */ #define SHA1Init SHA1_Init #define SHA1Update SHA1_Update #define SHA1Final SHA1_Final #define cast_key CAST_KEY #define cast_setkey(k, d, l) CAST_set_key ((k), (l), (d)) #define cast_encrypt(k, i, o) do { \ memcpy ((o), (i), BLOCKSIZE); \ CAST_encrypt ((CAST_LONG *)(o), (k)); \ } #define cast_decrypt(k, i, o) do { \ memcpy ((o), (i), BLOCKSIZE); \ CAST_decrypt ((CAST_LONG *)(o), (k)); \ } #endif #endif /* _SYSDEP_OS_H_ */ isakmpd-20041012.orig/sysdep/freebsd/CVS/0000755000175000017500000000000010133045751020133 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/bsdi/0000755000175000017500000000000010133045740017005 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/bsdi/Makefile.sysdep0000644000175000017500000000533210133045740021756 0ustar jdivejdive00000000000000# $OpenBSD: Makefile.sysdep,v 1.6 2004/06/26 03:40:57 mcbride Exp $ # # Copyright (c) 1999 Niklas Hallqvist. All rights reserved. # Copyright (c) 2000 H\xe5kan Olsson. All rights reserved. # Copyright (c) 2001 Markus Friedl. 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. # # 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 INN 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. # # Override default features FEATURES= tripledes des blowfish cast ec aggressive debug x509 FEATURES+= rawkey # Not yet #FEATURES+= policy isakmp_cfg LIBCRYPTO= /usr/contrib/lib/libcrypto.a LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep CFLAGS+= -DHAVE_PCAP LDADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a -lipsec DPADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a ${LIBIPSEC} SYSSRC=/usr/build/kame/bsdi4/sys .if exists(${SYSSRC}/net/pfkeyv2.h) CFLAGS+= -I${SYSSRC} .endif .if exists(/usr/build/keynote/keynote.h) CFLAGS+= -I/usr/build/keynote LDFLAGS+= -L/usr/build/keynote .endif CFLAGS+= -DNO_IDEA -DNO_RC5 -DHAVE_GETIFADDRS \ -I${.CURDIR}/sysdep/common CFLAGS+= -I/usr/include -I/usr/contrib/include LDADD+= -L/usr/contrib/lib IPSEC_SRCS= pf_key_v2.c IPSEC_CFLAGS= -DUSE_PF_KEY_V2 USE_LIBCRYPTO= defined USE_GMP= defined USE_KEYNOTE= defined # This is a hack in order to make sure libsysdep is built before the # linkstage of isakmpd. As a side effect the link is always done even if # not necessary. Well, I just don't care. GENERATED+= sysdep-target sysdep-target: cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS} .if make(clean) || make(cleandir) SUBDIR+= sysdep/common/libsysdep .endif # Kludge around bug in /usr/share/mk/bsd.subdir.mk NO_REGRESS= defined isakmpd-20041012.orig/sysdep/bsdi/sysdep.c0000644000175000017500000001270010133045740020460 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep.c,v 1.12 2004/08/10 15:59:10 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. * Copyright (c) 2000 H\xe5kan 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. * * 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 #include #include #include #include #include #include "sysdep.h" #include "util.h" #ifdef NEED_SYSDEP_APP #include "app.h" #include "conf.h" #include "ipsec.h" #ifdef USE_PF_KEY_V2 #include "pf_key_v2.h" #define KEY_API(x) pf_key_v2_##x #endif #endif /* NEED_SYSDEP_APP */ #include "log.h" extern char *__progname; /* * An as strong as possible random number generator, reverting to a * deterministic pseudo-random one if regrand is set. */ u_int32_t sysdep_random () { return random(); } /* Return the basename of the command used to invoke us. */ char * sysdep_progname () { return __progname; } /* Return the length of the sockaddr struct. */ u_int8_t sysdep_sa_len (struct sockaddr *sa) { return sa->sa_len; } /* As regress/ use this file I protect the sysdep_app_* stuff like this. */ #ifdef NEED_SYSDEP_APP /* * Prepare the application we negotiate SAs for (i.e. the IPsec stack) * for communication. We return a file descriptor useable to select(2) on. */ int sysdep_app_open () { return KEY_API(open) (); } /* * When select(2) has noticed our application needs attendance, this is what * gets called. FD is the file descriptor causing the alarm. */ void sysdep_app_handler (int fd) { KEY_API (handler) (fd); } /* Check that the connection named NAME is active, or else make it active. */ void sysdep_connection_check (char *name) { KEY_API (connection_check) (name); } /* * Generate a SPI for protocol PROTO and the source/destination pair given by * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. */ u_int8_t * sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, struct sockaddr *dst, u_int32_t seq) { if (app_none) { *sz = IPSEC_SPI_SIZE; /* XXX should be random instead I think. */ return strdup ("\x12\x34\x56\x78"); } return KEY_API (get_spi) (sz, proto, src, dst, seq); } struct sa_kinfo * sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, struct sockaddr *dst) { if (app_none) return 0; /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ return 0; } /* Force communication on socket FD to go in the clear. */ int sysdep_cleartext (int fd, int af) { char *buf; char *policy[] = { "in bypass", "out bypass", NULL }; char **p; int ipp; int opt; char *msgstr; if (app_none) return 0; switch (af) { case AF_INET: ipp = IPPROTO_IP; opt = IP_IPSEC_POLICY; msgstr = ""; break; case AF_INET6: ipp = IPPROTO_IPV6; opt = IPV6_IPSEC_POLICY; msgstr = "V6"; break; default: log_print ("sysdep_cleartext: unsupported protocol family %d", af); return -1; } /* * Need to bypass system security policy, so I can send and * receive key management datagrams in the clear. */ for (p = policy; p && *p; p++) { buf = ipsec_set_policy (*p, strlen(*p)); if (buf == NULL) { log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror()); return -1; } if (setsockopt(fd, ipp, opt, buf, ipsec_get_policylen(buf)) < 0) { log_error ("sysdep_cleartext: " "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) " "failed", fd, msgstr, msgstr); return -1; } free(buf); } return 0; } int sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) { if (app_none) return 0; return KEY_API (delete_spi) (sa, proto, incoming); } int sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API (enable_sa) (sa, isakmp_sa); } int sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2, int incoming) { if (app_none) return 0; return KEY_API (group_spis) (sa, proto1, proto2, incoming); } int sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa); } #endif isakmpd-20041012.orig/sysdep/bsdi/GNUmakefile.sysdep0000644000175000017500000000433410133045740022371 0ustar jdivejdive00000000000000# $OpenBSD: GNUmakefile.sysdep,v 1.3 2003/06/03 14:53:11 ho Exp $ # # XXX UNTESTED # # Copyright (c) 1999 Niklas Hallqvist. 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 # 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. # # 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. # LIBGMP:= LIBCRYPTO:= /usr/contrib/lib/libcrypto.a LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a LDADD+= ${LIBGMP} ${LIBSYSDEP} DPADD+= ${LIBGMP} ${LIBSYSDEP} FEATURES= debug tripledes blowfish cast ec aggressive # Not yet #FEATURES+= policy x509 CFLAGS+= -DNO_RSA -DNO_RC5 -DNO_IDEA \ -I${.CURDIR}/sysdep/common -I/usr/contrib/include \ IPSEC_SRCS= pf_key_v2.c IPSEC_CFLAGS= -DUSE_PF_KEY_V2 USE_LIBCRYPTO= defined # # hack libsysdep.a dependency # ${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}: @cd ${LIBSYSDEPDIR} && \ ${MAKE} --no-print-directory ${MAKEFLAGS} \ CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS} depend: ${LIBSYSDEPDIR}/.depend ifeq ($(findstring clean, $(MAKECMDGOALS)), clean) SUBDIR+= sysdep/common/libsysdep MAKEFLAGS+= --no-print-directory endif isakmpd-20041012.orig/sysdep/bsdi/sysdep-os.h0000644000175000017500000000453710133045740021115 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep-os.h,v 1.5 2003/08/06 11:20:00 markus Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. * Copyright (c) 2000 H\xe5kan Olsson. All rights reserved. * Copyright (c) 2001 Markus Friedl. 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. * * 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. */ #ifndef _SYSDEP_OS_H_ #define _SYSDEP_OS_H_ #define KAME #include /* in_port_t */ #include #define timersub(tvp, uvp, vvp) \ do { \ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ if ((vvp)->tv_usec < 0) { \ (vvp)->tv_sec--; \ (vvp)->tv_usec += 1000000; \ } \ } while (0) #ifndef CPI_RESERVED_MIN /* Reserved CPI numbers */ #define CPI_RESERVED_MIN 1 #define CPI_RESERVED_MAX 255 #define CPI_PRIVATE_MIN 61440 #define CPI_PRIVATE_MAX 65535 #endif #if !defined(SADB_X_EALG_CAST) && defined(SADB_X_EALG_CAST128CBC) #define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC #endif #if !defined(SADB_X_EALG_BLF) && defined(SADB_X_EALG_BLOWFISHCBC) #define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC #endif #endif /* _SYSDEP_OS_H_ */ isakmpd-20041012.orig/sysdep/bsdi/CVS/0000755000175000017500000000000010133045751017442 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/openbsd/0000755000175000017500000000000010133045740017516 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/openbsd/Makefile.sysdep0000644000175000017500000000361410133045740022470 0ustar jdivejdive00000000000000# $OpenBSD: Makefile.sysdep,v 1.24 2004/06/26 03:40:57 mcbride Exp $ # $EOM: Makefile.sysdep,v 1.18 2001/01/26 10:55:22 niklas Exp $ # # Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. 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. # # 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 INN 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. # # # This code was written under funding by Ericsson Radio Systems. # IPSEC_SRCS= pf_key_v2.c IPSEC_CFLAGS= -DUSE_PF_KEY_V2 CFLAGS+= -DHAVE_GETIFADDRS -DHAVE_PCAP CFLAGS+= -DHAVE_CLOSEFROM USE_LIBCRYPTO= defined .ifdef FEATURES .if ${FEATURES:Mpolicy} == "policy" .if ${MACHINE_ARCH} != "alpha" && ${MACHINE_ARCH} != "vax" && ${MACHINE_ARCH} != "m88k" POLICY+= keynote_compat.c .endif USE_KEYNOTE= defined .endif .endif .ifndef USE_LIBCRYPTO DESLIB= -ldes DESLIBDEP= ${LIBDES} .endif isakmpd-20041012.orig/sysdep/openbsd/sysdep.c0000644000175000017500000001477210133045740021204 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep.c,v 1.28 2004/08/10 15:59:11 ho Exp $ */ /* $EOM: sysdep.c,v 1.9 2000/12/04 04:46:35 angelos Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include #include "sysdep.h" #include "monitor.h" #include "util.h" #ifdef NEED_SYSDEP_APP #include "app.h" #include "conf.h" #include "ipsec.h" #ifdef USE_PF_KEY_V2 #include "pf_key_v2.h" #define KEY_API(x) pf_key_v2_##x #endif #endif /* NEED_SYSDEP_APP */ #include "log.h" extern char *__progname; /* * An as strong as possible random number generator, reverting to a * deterministic pseudo-random one if regrand is set. */ u_int32_t sysdep_random() { if (!regrand) return arc4random(); else return random(); } /* Return the basename of the command used to invoke us. */ char * sysdep_progname() { return __progname; } /* Return the length of the sockaddr struct. */ u_int8_t sysdep_sa_len(struct sockaddr *sa) { return sa->sa_len; } /* As regress/ use this file I protect the sysdep_app_* stuff like this. */ #ifdef NEED_SYSDEP_APP /* * Prepare the application we negotiate SAs for (i.e. the IPsec stack) * for communication. We return a file descriptor useable to select(2) on. */ int sysdep_app_open() { #ifdef USE_PRIVSEP return monitor_pf_key_v2_open(); #else return KEY_API(open)(); #endif } /* * When select(2) has noticed our application needs attendance, this is what * gets called. FD is the file descriptor causing the alarm. */ void sysdep_app_handler(int fd) { KEY_API(handler)(fd); } /* Check that the connection named NAME is active, or else make it active. */ void sysdep_connection_check(char *name) { KEY_API(connection_check)(name); } /* * Generate a SPI for protocol PROTO and the source/destination pair given by * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. */ u_int8_t * sysdep_ipsec_get_spi(size_t *sz, u_int8_t proto, struct sockaddr *src, struct sockaddr *dst, u_int32_t seq) { if (app_none) { *sz = IPSEC_SPI_SIZE; /* XXX should be random instead I think. */ return (u_int8_t *)strdup("\x12\x34\x56\x78"); } return KEY_API(get_spi)(sz, proto, src, dst, seq); } struct sa_kinfo * sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, struct sockaddr *dst) { if (app_none) return 0; return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); } /* Force communication on socket FD to go in the clear. */ int sysdep_cleartext(int fd, int af) { int level, sw; struct { int ip_proto; /* IP protocol */ int auth_level; int esp_trans_level; int esp_network_level; int ipcomp_level; } optsw[] = { { IPPROTO_IP, IP_AUTH_LEVEL, IP_ESP_TRANS_LEVEL, IP_ESP_NETWORK_LEVEL, #ifdef IP_IPCOMP_LEVEL IP_IPCOMP_LEVEL #else 0 #endif }, { IPPROTO_IPV6, IPV6_AUTH_LEVEL, IPV6_ESP_TRANS_LEVEL, IPV6_ESP_NETWORK_LEVEL, #ifdef IPV6_IPCOMP_LEVEL IPV6_IPCOMP_LEVEL #else 0 #endif }, }; if (app_none) return 0; switch (af) { case AF_INET: sw = 0; break; case AF_INET6: sw = 1; break; default: log_print("sysdep_cleartext: unsupported protocol family %d", af); return -1; } /* * Need to bypass system security policy, so I can send and * receive key management datagrams in the clear. */ level = IPSEC_LEVEL_BYPASS; if (monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].auth_level, (char *) &level, sizeof level) == -1) { log_error("sysdep_cleartext: " "setsockopt (%d, %d, IP_AUTH_LEVEL, ...) failed", fd, optsw[sw].ip_proto); return -1; } if (monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].esp_trans_level, (char *) &level, sizeof level) == -1) { log_error("sysdep_cleartext: " "setsockopt (%d, %d, IP_ESP_TRANS_LEVEL, ...) failed", fd, optsw[sw].ip_proto); return -1; } if (monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].esp_network_level, (char *) &level, sizeof level) == -1) { log_error("sysdep_cleartext: " "setsockopt (%d, %d, IP_ESP_NETWORK_LEVEL, ...) failed", fd, optsw[sw].ip_proto); return -1; } if (optsw[sw].ipcomp_level && monitor_setsockopt(fd, optsw[sw].ip_proto, optsw[sw].ipcomp_level, (char *) &level, sizeof level) == -1 && errno != ENOPROTOOPT) { log_error("sysdep_cleartext: " "setsockopt (%d, %d, IP_IPCOMP_LEVEL, ...) failed,", fd, optsw[sw].ip_proto); return -1; } return 0; } int sysdep_ipsec_delete_spi(struct sa *sa, struct proto *proto, int incoming) { if (app_none) return 0; return KEY_API(delete_spi)(sa, proto, incoming); } int sysdep_ipsec_enable_sa(struct sa *sa, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API(enable_sa)(sa, isakmp_sa); } int sysdep_ipsec_group_spis(struct sa *sa, struct proto *proto1, struct proto *proto2, int incoming) { if (app_none) return 0; return KEY_API(group_spis)(sa, proto1, proto2, incoming); } int sysdep_ipsec_set_spi(struct sa *sa, struct proto *proto, int incoming, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API(set_spi) (sa,proto, incoming, isakmp_sa); } #endif isakmpd-20041012.orig/sysdep/openbsd/GNUmakefile.sysdep0000644000175000017500000000350010133045740023074 0ustar jdivejdive00000000000000# $OpenBSD: GNUmakefile.sysdep,v 1.5 2004/06/26 03:40:57 mcbride Exp $ # # Copyright (c) 1999 Håkan Olsson. All rights reserved. # Copyright (c) 1999, 2000 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # LIBGMP:= /usr/lib/libgmp.a LIBCRYPTO:= /usr/lib/libcrypto.a IPSEC_SRCS= pf_key_v2.c IPSEC_CFLAGS= -DUSE_PF_KEY_V2 USE_LIBCRYPTO= defined ifneq (${MACHINE_ARCH},alpha) ifneq (${MACHINE_ARCH},vax) ifneq (${MACHINE_ARCH},m88k) SRCS+= keynote_compat.c endif endif endif USE_KEYNOTE= defined ifndef USE_LIBCRYPTO DESLIB= -ldes DESLIBDEP= ${LIBDES} endif isakmpd-20041012.orig/sysdep/openbsd/sysdep-os.h0000644000175000017500000000670710133045740021627 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep-os.h,v 1.6 2003/06/03 14:53:11 ho Exp $ */ /* $EOM: sysdep-os.h,v 1.3 1999/07/08 16:48:40 niklas Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _SYSDEP_OS_H_ #define _SYSDEP_OS_H_ /* * OpenBSD has at various times had non-conformant PF_KEYv2 definitions. * Here we transform them into being conformant. */ #ifdef SADB_EXT_X_SRC_MASK #define SADB_X_EXT_SRC_MASK SADB_EXT_X_SRC_MASK #define SADB_X_EXT_DST_MASK SADB_EXT_X_DST_MASK #define SADB_X_EXT_PROTOCOL SADB_EXT_X_PROTOCOL #define SADB_X_EXT_SA2 SADB_EXT_X_SA2 #define SADB_X_EXT_SRC_FLOW SADB_EXT_X_SRC_FLOW #define SADB_X_EXT_DST_FLOW SADB_EXT_X_DST_FLOW #define SADB_X_EXT_DST2 SADB_EXT_X_DST2 #define SADB_X_SATYPE_AH_OLD SADB_SATYPE_X_AH_OLD #define SADB_X_SATYPE_ESP_OLD SADB_SATYPE_X_ESP_OLD #define SADB_X_SATYPE_IPIP SADB_SATYPE_X_IPIP #define SADB_X_AALG_RIPEMD160HMAC96 SADB_AALG_X_RIPEMD160HMAC96 #define SADB_X_AALG_MD5 SADB_AALG_X_MD5 #define SADB_X_AALG_SHA1 SADB_AALG_X_SHA1 #define SADB_X_EALG_BLF SADB_EALG_X_BLF #define SADB_X_EALG_CAST SADB_EALG_X_CAST #define SADB_X_EALG_SKIPJACK SADB_EALG_X_SKIPJACK #define SADB_X_SAFLAGS_HALFIV SADB_SAFLAGS_X_HALFIV #define SADB_X_SAFLAGS_TUNNEL SADB_SAFLAGS_X_TUNNEL #define SADB_X_SAFLAGS_CHAINDEL SADB_SAFLAGS_X_CHAINDEL #define SADB_X_SAFLAGS_LOCALFLOW SADB_SAFLAGS_X_LOCALFLOW #define SADB_X_SAFLAGS_REPLACEFLOW SADB_SAFLAGS_X_REPLACEFLOW #endif /* SADB_EXT_X_SRC_MASK */ #if defined (SADB_IDENTTYPE_MBOX) && !defined (SADB_IDENTTYPE_USERFQDN) #define SADB_IDENTTYPE_USERFQDN SADB_IDENTTYPE_MBOX #endif #ifdef FLOW_X_TYPE_USE #define SADB_X_FLOW_TYPE_USE FLOW_X_TYPE_USE #define SADB_X_FLOW_TYPE_ACQUIRE FLOW_X_TYPE_ACQUIRE #define SADB_X_FLOW_TYPE_REQUIRE FLOW_X_TYPE_REQUIRE #define SADB_X_FLOW_TYPE_BYPASS FLOW_X_TYPE_BYPASS #define SADB_X_FLOW_TYPE_DENY FLOW_X_TYPE_DENY #define SADB_X_FLOW_TYPE_DONTACQ FLOW_X_TYPE_DONTACQ #endif #if OPENBSD_IPSEC_API_VERSION == 1 #define sadb_x_policy sadb_policy #define sadb_x_policy_len sadb_policy_len #define sadb_x_policy_exttype sadb_policy_exttype #define sadb_x_policy_seq sadb_policy_seq #endif #endif /* _SYSDEP_OS_H_ */ isakmpd-20041012.orig/sysdep/openbsd/CVS/0000755000175000017500000000000010133045751020153 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/openbsd/keynote_compat.c0000644000175000017500000000560610133045740022712 0ustar jdivejdive00000000000000/* $OpenBSD: keynote_compat.c,v 1.6 2004/04/15 18:39:30 deraadt Exp $ */ /* $EOM: keynote_compat.c,v 1.1 2000/10/15 19:18:26 niklas Exp $ */ /* * Copyright (c) 2000 Niklas Hallqvist. 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. * * 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. */ /* * By mistake these functions were introduced into libkeynote without * updating some kind of version preprocessor symbol we can test. * Provide weak functions that can be used if the libkeynote version * we link against miss them. */ #pragma weak kn_get_string=_kn_get_string #pragma weak kn_free_key=_kn_free_key /* * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu) * * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA, * in April-May 1998 * * Copyright (C) 1998, 1999 by Angelos D. Keromytis. * * Permission to use, copy, and modify this software without fee * is hereby granted, provided that this entire notice is included in * all copies of any software which is or includes a copy or * modification of this software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR * PURPOSE. */ #include #include #include extern void keynote_free_key(void *, int); extern char *keynote_get_private_key(char *); /* * Exportable front-end to keynote_get_private_key(). */ char * _kn_get_string(char *buf) { return keynote_get_private_key(buf); } /* * Free a key. */ void _kn_free_key(struct keynote_deckey *dc) { if (dc) keynote_free_key(dc->dec_key, dc->dec_algorithm); } isakmpd-20041012.orig/sysdep/darwin/0000755000175000017500000000000010133045740017350 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/darwin/Makefile.sysdep0000644000175000017500000000330210133045740022314 0ustar jdivejdive00000000000000# $OpenBSD: Makefile.sysdep,v 1.3 2004/06/26 03:40:57 mcbride Exp $ # # Copyright (c) 1999 Niklas Hallqvist. 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. # # 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 INN 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. # # # This code was written under funding by Ericsson Radio Systems. # # Override default features FEATURES= tripledes des blowfish cast x509 ec aggressive debug FEATURES+= rawkey isakmp_cfg LDADD+= -lipsec CFLAGS+= -DHAVE_GETIFADDRS -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL IPSEC_SRCS= pf_key_v2.c IPSEC_CFLAGS= -DUSE_PF_KEY_V2 USE_LIBCRYPTO= defined obj: mkdir obj isakmpd-20041012.orig/sysdep/darwin/sysdep.c0000644000175000017500000001251110133045740021023 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep.c,v 1.3 2004/08/10 15:59:10 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include "sysdep.h" #include "util.h" #ifdef NEED_SYSDEP_APP #include "app.h" #include "conf.h" #include "ipsec.h" #ifdef USE_PF_KEY_V2 #include "pf_key_v2.h" #define KEY_API(x) pf_key_v2_##x #endif #endif /* NEED_SYSDEP_APP */ #include "log.h" extern char *__progname; /* * An as strong as possible random number generator, reverting to a * deterministic pseudo-random one if regrand is set. */ u_int32_t sysdep_random () { return random(); } /* Return the basename of the command used to invoke us. */ char * sysdep_progname () { return __progname; } /* Return the length of the sockaddr struct. */ u_int8_t sysdep_sa_len (struct sockaddr *sa) { return sa->sa_len; } /* As regress/ use this file I protect the sysdep_app_* stuff like this. */ #ifdef NEED_SYSDEP_APP /* * Prepare the application we negotiate SAs for (i.e. the IPsec stack) * for communication. We return a file descriptor useable to select(2) on. */ int sysdep_app_open () { return KEY_API(open) (); } /* * When select(2) has noticed our application needs attendance, this is what * gets called. FD is the file descriptor causing the alarm. */ void sysdep_app_handler (int fd) { KEY_API (handler) (fd); } /* Check that the connection named NAME is active, or else make it active. */ void sysdep_connection_check (char *name) { KEY_API (connection_check) (name); } /* * Generate a SPI for protocol PROTO and the source/destination pair given by * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. */ u_int8_t * sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, struct sockaddr *dst, u_int32_t seq) { if (app_none) { *sz = IPSEC_SPI_SIZE; /* XXX should be random instead I think. */ return strdup ("\x12\x34\x56\x78"); } return KEY_API (get_spi) (sz, proto, src, dst, seq); } struct sa_kinfo * sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, struct sockaddr *dst) { if (app_none) return 0; /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ return 0; } /* Force communication on socket FD to go in the clear. */ int sysdep_cleartext (int fd, int af) { char *buf; char *policy[] = { "in bypass", "out bypass", NULL }; char **p; int ipp; if (app_none) return 0; switch (af) { case AF_INET: ipp = IPPROTO_IP; break; case AF_INET6: ipp = IPPROTO_IPV6; break; default: log_print ("sysdep_cleartext: unsupported protocol family %d", af); return -1; } /* * Need to bypass system security policy, so I can send and * receive key management datagrams in the clear. */ for (p = policy; p && *p; p++) { buf = ipsec_set_policy (*p, strlen(*p)); if (buf == NULL) { log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror()); return -1; } if (setsockopt(fd, ipp, IP_IPSEC_POLICY, buf, ipsec_get_policylen(buf)) < 0) { log_error ("sysdep_cleartext: " "setsockopt (%d, IPPROTO_IP, IP_IPSEC_POLICY, ...) failed", fd); return -1; } free(buf); } return 0; } int sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) { if (app_none) return 0; return KEY_API (delete_spi) (sa, proto, incoming); } int sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API (enable_sa) (sa, isakmp_sa); } int sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2, int incoming) { if (app_none) return 0; return KEY_API (group_spis) (sa, proto1, proto2, incoming); } int sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa); } #endif isakmpd-20041012.orig/sysdep/darwin/GNUmakefile.sysdep0000644000175000017500000000351210133045740022731 0ustar jdivejdive00000000000000# $OpenBSD: GNUmakefile.sysdep,v 1.3 2004/06/26 03:40:57 mcbride Exp $ # # Copyright (c) 1999,2002 Håkan Olsson. All rights reserved. # Copyright (c) 1999 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # LDADD+= -lipsec # gcc under MacOS X does not seem to like building things -static LDSTATIC= CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_OPENSSL CFLAGS+= -DHAVE_GETIFADDRS FEATURES= debug tripledes des blowdish cast ec aggressive x509 FEATURES+= rawkey isakmp_cfg # Not yet #FEATURES+= policy IPSEC_SRCS= pf_key_v2.c IPSEC_CFLAGS= -DUSE_PF_KEY_V2 USE_LIBCRYPTO= defined isakmpd-20041012.orig/sysdep/darwin/sysdep-os.h0000644000175000017500000000514710133045740021456 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep-os.h,v 1.3 2003/08/06 11:23:11 markus Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. All rights reserved. * Copyright (c) 2002 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _SYSDEP_OS_H_ #define _SYSDEP_OS_H_ #define KAME #include typedef u_int32_t socklen_t; #ifndef CPI_RESERVED_MAX #define CPI_RESERVED_MIN 1 #define CPI_RESERVED_MAX 255 #define CPI_PRIVATE_MIN 61440 #define CPI_PRIVATE_MAX 65536 #endif #if !defined(SADB_X_EALG_CAST) && defined(SADB_X_EALG_CAST128CBC) #define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC #endif #if !defined(SADB_X_EALG_BLF) && defined(SADB_X_EALG_BLOWFISHCBC) #define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC #endif #if 1 /* OpenSSL differs from OpenBSD very slightly... */ #define MD5Init MD5_Init #define MD5Update MD5_Update #define MD5Final MD5_Final #define SHA1Init SHA1_Init #define SHA1Update SHA1_Update #define SHA1Final SHA1_Final #define SHA1_CTX SHA_CTX #define cast_key CAST_KEY #define cast_setkey(k, d, l) CAST_set_key ((k), (l), (d)) #define cast_encrypt(k, i, o) do { \ memcpy ((o), (i), BLOCKSIZE); \ CAST_encrypt ((CAST_LONG *)(o), (k)); \ } while (0) #define cast_decrypt(k, i, o) do { \ memcpy ((o), (i), BLOCKSIZE); \ CAST_decrypt ((CAST_LONG *)(o), (k)); \ } while (0) #endif #endif /* _SYSDEP_OS_H_ */ isakmpd-20041012.orig/sysdep/darwin/CVS/0000755000175000017500000000000010133045751020005 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/freeswan/0000755000175000017500000000000010133045740017676 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/freeswan/klips.h0000644000175000017500000000402010133045740021165 0ustar jdivejdive00000000000000/* $OpenBSD: klips.h,v 1.2 2003/06/03 14:53:11 ho Exp $ */ /* * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _KLIPS_H_ #define _KLIPS_H_ #include #include struct proto; struct sa; struct sockaddr; extern void klips_connection_check (char *); extern int klips_delete_spi (struct sa *, struct proto *, int); extern int klips_enable_sa (struct sa *, struct sa *); extern u_int8_t *klips_get_spi (size_t *, u_int8_t, struct sockaddr *, int, struct sockaddr *, int, u_int32_t); extern int klips_group_spis (struct sa *, struct proto *, struct proto *, int); extern int klips_open (void); extern int klips_set_spi (struct sa *, struct proto *, int); #endif /* _KLIPS_H_ */ isakmpd-20041012.orig/sysdep/freeswan/klips.c0000644000175000017500000004320010133045740021163 0ustar jdivejdive00000000000000/* $OpenBSD: klips.c,v 1.3 2003/09/26 15:59:34 aaron Exp $ */ /* * Copyright (c) 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sysdep.h" #include "conf.h" #include "exchange.h" #include "hash.h" #include "ipsec.h" #include "ipsec_doi.h" #include "ipsec_num.h" #include "isakmp.h" #include "log.h" #include "klips.h" #include "sa.h" #include "timer.h" #include "transport.h" #define KLIPS_DEVICE "/dev/ipsec" #define PROC_ROUTE_FILE "/proc/net/route" #define PROC_ROUTE_FMT "%15s %127s %127s %X %d %d %d %127s %d %d %d\n" /* XXX Maybe these are available through some system-supplied define? */ #define AH_NEW_XENCAP_LEN (3 * sizeof(u_short) + 2 * sizeof(u_char)) #define ESP_NEW_XENCAP_LEN sizeof (struct espblkrply_edata) #define EMT_GRPSPIS_COMPLEN (sizeof (((struct encap_msghdr *)0)->em_rel[0])) /* How often should we check that connections we require to be up, are up? */ #define KLIPS_CHECK_FREQ 60 static int klips_socket; /* Open the KLIPS device. */ int klips_open () { int fd; fd = open (KLIPS_DEVICE, O_RDWR); if (fd == -1) { log_error ("klips_open: open (\"%s\", O_RDWR) failed", KLIPS_DEVICE); return -1; } klips_socket = fd; return fd; } /* Write a KLIPS request down to the kernel. */ static int klips_write (struct encap_msghdr *em) { ssize_t n; em->em_magic = EM_MAGIC; em->em_version = 0; LOG_DBG_BUF ((LOG_SYSDEP, 30, "klips_write: em", (u_int8_t *)em, em->em_msglen)); n = write (klips_socket, em, em->em_msglen); if (n == -1) { log_error ("write (%d, ...) failed", klips_socket); return -1; } if ((size_t)n != em->em_msglen) { log_error ("write (%d, ...) returned prematurely", klips_socket); return -1; } return 0; } /* * Generate a SPI for protocol PROTO and the source/destination pair given by * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. */ u_int8_t * klips_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, struct sockaddr *dst, u_int32_t seq) { u_int8_t *spi; u_int32_t spinum; *sz = IPSEC_SPI_SIZE; spi = malloc (*sz); if (!spi) return 0; do spinum = sysdep_random (); while (spinum < IPSEC_SPI_LOW); spinum = htonl (spinum); memcpy (spi, &spinum, *sz); LOG_DBG_BUF ((LOG_SYSDEP, 50, "klips_get_spi: spi", spi, *sz)); return spi; } /* Group 2 SPIs in a chain. XXX Not fully implemented yet. */ int klips_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2, int incoming) { struct encap_msghdr *emsg = 0; struct sockaddr *dst; emsg = calloc (1, EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN); if (!emsg) return -1; emsg->em_msglen = EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN; emsg->em_type = EMT_GRPSPIS; /* * XXX The code below is wrong if we are in tunnel mode. * The fix is to reorder stuff so the IP-in-IP SA will always come * upfront, and if there are two such, one is dropped. */ memcpy (&emsg->em_rel[0].emr_spi, proto1->spi[incoming], sizeof emsg->em_rel[0].emr_spi); memcpy (&emsg->em_rel[1].emr_spi, proto2->spi[incoming], sizeof emsg->em_rel[1].emr_spi); if (incoming) sa->transport->vtbl->get_src (sa->transport, &dst); else sa->transport->vtbl->get_dst (sa->transport, &dst); emsg->em_rel[0].emr_dst = emsg->em_rel[1].emr_dst = ((struct sockaddr_in *)dst)->sin_addr; /* XXX What if IPCOMP etc. comes along? */ emsg->em_rel[0].emr_proto = proto1->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH; emsg->em_rel[1].emr_proto = proto2->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH; if (klips_write (emsg)) goto cleanup; free (emsg); LOG_DBG ((LOG_SYSDEP, 50, "klips_group_spis: done")); return 0; cleanup: if (emsg) free (emsg); return -1; } /* Store/update a SPI with full information into the kernel. */ int klips_set_spi (struct sa *sa, struct proto *proto, int incoming, struct sa *isakmp_sa) { struct encap_msghdr *emsg = 0; struct ipsec_proto *iproto = proto->data; struct sockaddr *dst, *src; int keylen, hashlen; size_t len; struct ipe4_xdata *ip4x; /* Actually works for all. */ struct espblkrply_edata *edx; /* Actually works for all. */ struct ahhmacmd5_edata *amx; switch (proto->proto) { case IPSEC_PROTO_IPSEC_ESP: keylen = ipsec_esp_enckeylength (proto); hashlen = ipsec_esp_authkeylength (proto); len = EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN; emsg = calloc (1, len); if (!emsg) return -1; emsg->em_proto = IPPROTO_ESP; edx = (struct espblkrply_edata *)emsg->em_dat; /* Funny expression due to I just want one switch. */ switch (proto->id | (iproto->auth << 8)) { case IPSEC_ESP_3DES: emsg->em_alg = XF_ESP3DES; break; case IPSEC_ESP_3DES | (IPSEC_AUTH_HMAC_MD5 << 8): emsg->em_alg = XF_ESP3DESMD596; break; case IPSEC_ESP_3DES | (IPSEC_AUTH_HMAC_SHA << 8): emsg->em_alg = XF_ESP3DESSHA196; break; default: LOG_DBG ((LOG_SYSDEP, 10, "klips_set_spi: Unsupported enc/auth alg negotiated")); return -1; } /* XXX What if we have a protocol requiring IV? */ edx->eme_ivlen = EMT_ESPDES_IV_SZ; edx->eme_klen = keylen; edx->ame_klen = hashlen; #if 0 /* I have reason to believe Shared-SADB won't work at all in KLIPS. */ edx->eme_ooowin = conf_get_str ("General", "Shared-SADB") ? 0 : iproto->replay_window; #else edx->eme_ooowin = iproto->replay_window; #endif /* * XXX Pluto sets the unused by KLIPS flag EME_INITIATOR in * edx->eme_flags, if the party is the initiator. Should we too? */ edx->eme_flags = 0; memcpy (edx->eme_key, iproto->keymat[incoming], keylen); if (iproto->auth) memcpy (edx->ame_key, iproto->keymat[incoming] + keylen, hashlen); break; case IPSEC_PROTO_IPSEC_AH: hashlen = ipsec_ah_keylength (proto); len = EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN + hashlen; emsg = calloc (1, len); if (!emsg) return -1; emsg->em_proto = IPPROTO_AH; amx = (struct ahhmacmd5_edata *)emsg->em_dat; switch (proto->id) { case IPSEC_AH_MD5: emsg->em_alg = XF_AHHMACMD5; break; case IPSEC_AH_SHA: emsg->em_alg = XF_AHHMACSHA1; break; default: /* XXX Log? */ goto cleanup; } /* XXX Should we be able to send in different lengths here? */ amx->ame_alen = amx->ame_klen = hashlen; #if 0 /* I have reason to believe Shared-SADB won't work at all in KLIPS. */ amx->ame_ooowin = conf_get_str ("General", "Shared-SADB") ? 0 : iproto->replay_window; #else amx->ame_ooowin = iproto->replay_window; #endif amx->ame_replayp = amx->ame_ooowin > 0; memcpy (amx->ame_key, iproto->keymat[incoming], hashlen); break; default: /* XXX Log? */ goto cleanup; } emsg->em_msglen = len; emsg->em_type = EMT_SETSPI; memcpy (&emsg->em_spi, proto->spi[incoming], sizeof emsg->em_spi); emsg->em_flags = incoming ? EMT_INBOUND : 0; /* * XXX Addresses has to be thought through. Assumes IPv4. */ sa->transport->vtbl->get_dst (sa->transport, &dst); sa->transport->vtbl->get_src (sa->transport, &src); emsg->em_dst = ((struct sockaddr_in *)(incoming ? src : dst))->sin_addr; /* * Klips does not know about expirations, thus we need to do them inside * isakmpd. */ if (sa->seconds) if (sa_setup_expirations (sa)) goto cleanup; LOG_DBG ((LOG_SYSDEP, 10, "klips_set_spi: proto %d dst %s SPI 0x%x", emsg->em_proto, inet_ntoa (emsg->em_dst), htonl (emsg->em_spi))); if (klips_write (emsg)) goto cleanup; free (emsg); /* If we are tunneling we have to setup an IP in IP tunnel too. */ if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) { len = EMT_SETSPI_FLEN + EMT_IPE4_ULEN; emsg = calloc (1, len); if (!emsg) goto cleanup; emsg->em_proto = IPPROTO_IPIP; emsg->em_msglen = len; emsg->em_type = EMT_SETSPI; /* * XXX Code in Pluto suggests this is not possible, but that we have * to have a unique SPI for the IP4 SA. */ memcpy (&emsg->em_spi, proto->spi[incoming], sizeof emsg->em_spi); emsg->em_flags = 0; emsg->em_alg = XF_IP4; ip4x = (struct ipe4_xdata *)emsg->em_dat; ip4x->i4_dst = emsg->em_dst = ((struct sockaddr_in *)(incoming ? src : dst))->sin_addr; ip4x->i4_src = ((struct sockaddr_in *)(incoming ? dst : src))->sin_addr; LOG_DBG ((LOG_SYSDEP, 10, "klips_set_spi: proto %d dst %s SPI 0x%x", emsg->em_proto, inet_ntoa (emsg->em_dst), htonl (emsg->em_spi))); if (klips_write (emsg)) goto cleanup; free (emsg); /* * Grouping the IP-in-IP SA with the IPsec one means we must be careful * in klips_group_spis so that we'll remove duplicate IP-in-IP SAs * and get everything grouped in the right order. * * XXX Could we not share code with klips_group_spis here? */ emsg = calloc (1, EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN); if (!emsg) goto cleanup; emsg->em_msglen = EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN; emsg->em_type = EMT_GRPSPIS; memcpy (&emsg->em_rel[0].emr_spi, proto->spi[incoming], sizeof emsg->em_rel[0].emr_spi); memcpy (&emsg->em_rel[1].emr_spi, proto->spi[incoming], sizeof emsg->em_rel[1].emr_spi); emsg->em_rel[0].emr_dst = emsg->em_rel[1].emr_dst = ((struct sockaddr_in *)(incoming ? src : dst))->sin_addr; emsg->em_rel[0].emr_proto = IPPROTO_IPIP; /* XXX What if IPCOMP etc. comes along? */ emsg->em_rel[1].emr_proto = proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH; if (klips_write (emsg)) goto cleanup; free (emsg); } LOG_DBG ((LOG_SYSDEP, 50, "klips_set_spi: done")); return 0; cleanup: /* XXX Cleanup the potential SAs we have setup. */ if (emsg) free (emsg); return -1; } /* * Delete the IPsec SA represented by the INCOMING direction in protocol PROTO * of the IKE security association SA. */ int klips_delete_spi (struct sa *sa, struct proto *proto, int incoming) { struct encap_msghdr *emsg = 0; struct sockaddr *dst; struct ipsec_proto *iproto = proto->data; emsg = calloc (1, EMT_SETSPI_FLEN); if (!emsg) return -1; emsg->em_msglen = EMT_SETSPI_FLEN; emsg->em_type = EMT_DELSPI; memcpy (&emsg->em_spi, proto->spi[incoming], sizeof emsg->em_spi); if (incoming) sa->transport->vtbl->get_src (sa->transport, &dst); else sa->transport->vtbl->get_dst (sa->transport, &dst); emsg->em_dst = ((struct sockaddr_in *)dst)->sin_addr; /* XXX What if IPCOMP etc. comes along? */ emsg->em_proto = (iproto->encap_mode == IPSEC_ENCAP_TUNNEL ? IPPROTO_IPIP : proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH); if (klips_write (emsg)) goto cleanup; free (emsg); LOG_DBG ((LOG_SYSDEP, 50, "klips_delete_spi: done")); return 0; cleanup: if (emsg) free (emsg); return -1; } int klips_hex_decode (char *src, u_char *dst, int dstsize) { char *p, *pe; u_char *q, *qe, ch, cl; pe = src + strlen (src); qe = dst + dstsize; for (p = src, q = dst; p < pe && q < qe && isxdigit ((int)*p); p += 2) { ch = tolower (p[0]); cl = tolower (p[1]); if ((ch >= '0') && (ch <= '9')) ch -= '0'; else if ((ch >= 'a') && (ch <= 'f')) ch -= 'a' - 10; else return -1; if ((cl >= '0') && (cl <= '9')) cl -= '0'; else if ((cl >= 'a') && (cl <= 'f')) cl -= 'a' - 10; else return -1; *q++ = (ch << 4) | cl; } return (int)(q - dst); } /* Consult kernel routing table for next-hop lookup. From dugsong@monkey.org */ u_long klips_route_get (u_long dst) { FILE *f; char buf[BUFSIZ]; char ifbuf[16], netbuf[128], gatebuf[128], maskbuf[128]; int i, iflags, refcnt, use, metric, mss, win, irtt; u_long ret, gate, net, mask; if ((f = fopen (PROC_ROUTE_FILE, "r")) == NULL) return dst; ret = dst; while (fgets (buf, sizeof buf, f) != NULL) { i = sscanf (buf, PROC_ROUTE_FMT, ifbuf, netbuf, gatebuf, &iflags, &refcnt, &use, &metric, maskbuf, &mss, &win, &irtt); if (i < 10 || !(iflags & RTF_UP)) continue; klips_hex_decode (netbuf, (u_char *)&net, sizeof net); klips_hex_decode (gatebuf, (u_char *)&gate, sizeof gate); klips_hex_decode (maskbuf, (u_char *)&mask, sizeof mask); net = htonl (net); gate = htonl (gate); mask = htonl (mask); if ((dst & mask) == net) { if (gate != INADDR_ANY) ret = gate; break; } } fclose (f); return ret; } /* Enable a flow given a SA. */ int klips_enable_sa (struct sa *sa, struct sa *isakmp_sa) { struct ipsec_sa *isa = sa->data; struct sockaddr *dst; struct proto *proto = TAILQ_FIRST (&sa->protos); struct ipsec_proto *iproto = proto->data; struct encap_msghdr emsg; int s = -1; struct rtentry rt; sa->transport->vtbl->get_dst (sa->transport, &dst); /* XXX Is this needed? */ memset (&emsg, '\0', sizeof emsg); emsg.em_msglen = sizeof emsg; emsg.em_type = EMT_RPLACEROUTE; memcpy (&emsg.em_erspi, proto->spi[0], sizeof emsg.em_erspi); emsg.em_erdst = ((struct sockaddr_in *)dst)->sin_addr; LOG_DBG ((LOG_SYSDEP, 50, "klips_enable_sa: src %x %x dst %x %x", ntohl (isa->src_net), ntohl (isa->src_mask), ntohl (isa->dst_net), ntohl (isa->dst_mask))); /* XXX Magic constant from Pluto (26 = AF_ISDN in BSD). */ emsg.em_eaddr.sen_family = emsg.em_emask.sen_family = 26; emsg.em_eaddr.sen_type = SENT_IP4; /* XXX Magic constant from Pluto. */ emsg.em_emask.sen_type = 255; emsg.em_eaddr.sen_len = emsg.em_emask.sen_len = sizeof (struct sockaddr_encap); emsg.em_eaddr.sen_ip_src.s_addr = isa->src_net; emsg.em_emask.sen_ip_src.s_addr = isa->src_mask; emsg.em_eaddr.sen_ip_dst.s_addr = isa->dst_net; emsg.em_emask.sen_ip_dst.s_addr = isa->dst_mask; /* XXX What if IPCOMP etc. comes along? */ emsg.em_erproto = (iproto->encap_mode == IPSEC_ENCAP_TUNNEL ? IPPROTO_IPIP : proto->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH); if (klips_write (&emsg)) { emsg.em_type = EMT_SETEROUTE; if (klips_write (&emsg)) goto cleanup; } s = socket (PF_INET, SOCK_DGRAM, AF_UNSPEC); if (s == -1) { log_error ("klips_enable_sa: " "socket(PF_INET, SOCK_DGRAM, AF_UNSPEC) failed"); goto cleanup; } memset (&rt, '\0', sizeof rt); rt.rt_dst.sa_family = AF_INET; ((struct sockaddr_in *)&rt.rt_dst)->sin_addr.s_addr = isa->dst_net; rt.rt_genmask.sa_family = AF_INET; ((struct sockaddr_in *)&rt.rt_genmask)->sin_addr.s_addr = isa->dst_mask; rt.rt_gateway.sa_family = AF_INET; ((struct sockaddr_in *)&rt.rt_gateway)->sin_addr.s_addr = klips_route_get (emsg.em_erdst.s_addr); rt.rt_flags = RTF_UP | RTF_GATEWAY; /* XXX What if we have multiple interfaces? */ rt.rt_dev = "ipsec0"; if (ioctl (s, SIOCDELRT, &rt) == -1 && errno != ESRCH) { log_error ("klips_enable_sa: ioctl (%d, SIOCDELRT, %p) failed", s, &rt); goto cleanup; } if (ioctl (s, SIOCADDRT, &rt) == -1) { log_error ("klips_enable_sa: ioctl (%d, SIOCADDRT, %p) failed", s, &rt); goto cleanup; } close (s); return 0; cleanup: if (s != -1) close (s); return -1; } static void klips_stayalive (struct exchange *exchange, void *vconn, int fail) { char *conn = vconn; struct sa *sa; /* XXX What if it is phase 1? */ sa = sa_lookup_by_name (conn, 2); if (sa) sa->flags |= SA_FLAG_STAYALIVE; } /* Establish the connection in VCONN and set the stayalive flag for it. */ void klips_connection_check (char *conn) { if (!sa_lookup_by_name (conn, 2)) { LOG_DBG ((LOG_SYSDEP, 70, "klips_connection_check: SA for %s missing", conn)); exchange_establish (conn, klips_stayalive, conn); } else LOG_DBG ((LOG_SYSDEP, 70, "klips_connection_check: SA for %s exists", conn)); } isakmpd-20041012.orig/sysdep/freeswan/README0000644000175000017500000000111310133045740020552 0ustar jdivejdive00000000000000$OpenBSD: README,v 1.1 2003/05/14 20:49:37 ho Exp $ Currently, you have to manually configure any IPsec interfaces and do the association betweent these and the physical ones. This is done like this in FreeS/WAN: ipsec tncfg --attach --virtual ipsec0 --physical eth0 ifconfig ipsec0 A.B.C.D netmask E.F.G.H Then there is one special configuration option in the IPsec-connection sections for Phase 2 of the configuration file, named Next-hop, which should be set to the next hop's IP address along the way to the peer: Next-hop= I.J.K.L This is specific to the way FreeS/WAN works. isakmpd-20041012.orig/sysdep/freeswan/Makefile.sysdep0000644000175000017500000000521410133045740022646 0ustar jdivejdive00000000000000# $OpenBSD: Makefile.sysdep,v 1.2 2003/06/03 14:53:11 ho Exp $ # # Copyright (c) 1999 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # In order for this to work, invocations need to set FREESWAN to the # directory where FreeS/WAN is installed. BINDIR= /usr/local/sbin # Partly good for RedHat 5.2, but man(1) does not find them so I have it # disabled for now. #MANDIR= /var/catman/cat #MAN5= isakmpd.conf.0 #MAN8= isakmpd.0 NOMAN= IPSEC_SRCS= klips.c LDADD+= ${.CURDIR}/sysdep/common/libsysdep/libsysdep.a \ ${FREESWAN}/gmp/libgmp.a DPADD+= ${.CURDIR}/sysdep/common/libsysdep/libsysdep.a \ ${FREESWAN}/gmp/libgmp.a CFLAGS+= ${DEBUG} -I${FREESWAN}/gmp -I${FREESWAN}/libdes \ -I${FREESWAN}/klips -I${FREESWAN}/lib -DUSE_OLD_SOCKADDR \ -I${.CURDIR}/sysdep/common #USE_LIBCRYPTO= defined #USE_KEYNOTE= defined .ifndef USE_LIBCRYPTO DESLIB= ${FREESWAN}/libdes/libdes.a DESLIBDEP= ${FREESWAN}/libdes/libdes.a .endif # This is a hack in order to make sure libsysdep is built before the # linkstage of isakmpd. As a side effect the link is always done even if # not necessary. Well, I just don't care. GENERATED+= sysdep-target sysdep-target: cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS} .if make(clean) SUBDIR+= sysdep/common/libsysdep .endif # The regress/ subdir is completely broken in the linux environment .if !make(install) SUBDIR:= ${SUBDIR:Nregress} .endif isakmpd-20041012.orig/sysdep/freeswan/sysdep.c0000644000175000017500000001070310133045740021352 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep.c,v 1.3 2004/08/10 15:59:10 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #include #include #include #include #include #include #include #include #include #include "sysdep.h" #ifdef NEED_SYSDEP_APP #include "app.h" #include "conf.h" #include "ipsec.h" #include "klips.h" #endif /* NEED_SYSDEP_APP */ #include "log.h" #include "sysdep.h" extern char *__progname; u_int32_t sysdep_random () { u_int32_t rndval; u_char sig[16]; MD5_CTX ctx; int fd, i; struct { struct timeval tv; u_int rnd[(128 - sizeof (struct timeval)) / sizeof (u_int)]; } rdat; fd = open ("/dev/urandom", O_RDONLY); if (fd != -1) { read (fd, rdat.rnd, sizeof(rdat.rnd)); close (fd); } MD5Init (&ctx); MD5Update (&ctx, (char *)&rdat, sizeof(rdat)); MD5Final (sig, &ctx); rndval = 0; for (i = 0; i < 4; i++) { u_int32_t *tmp = (u_int32_t *)&sig[i * 4]; rndval ^= *tmp; } return rndval; } char * sysdep_progname () { return __progname; } /* Return the length of the sockaddr struct. */ u_int8_t sysdep_sa_len (struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET: return sizeof (struct sockaddr_in); case AF_INET6: return sizeof (struct sockaddr_in6); } log_print ("sysdep_sa_len: unknown sa family %d", sa->sa_family); return sizeof (struct sockaddr_in); } /* As regress/ use this file I protect the sysdep_app_* stuff like this. */ #ifdef NEED_SYSDEP_APP int sysdep_app_open () { return klips_open (); } void sysdep_app_handler (int fd) { } /* Check that the connection named NAME is active, or else make it active. */ void sysdep_connection_check (char *name) { klips_connection_check (name); } /* * Generate a SPI for protocol PROTO and the source/destination pair given by * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. */ u_int8_t * sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, struct sockaddr *dst, u_int32_t seq) { if (app_none) { *sz = IPSEC_SPI_SIZE; /* XXX should be random instead I think. */ return strdup ("\x12\x34\x56\x78"); } return klips_get_spi (sz, proto, src, dst, seq); } struct sa_kinfo * sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, struct sockaddr *dst) { if (app_none) return 0; /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ return 0; } int sysdep_cleartext (int fd, int af) { return 0; } int sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) { return klips_delete_spi (sa, proto, incoming); } int sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) { return klips_enable_sa (sa, isakmp_sa); } int sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2, int incoming) { return klips_group_spis (sa, proto1, proto2, incoming); } int sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, struct sa *isakmp_sa) { return klips_set_spi (sa, proto, incoming, isakmp_sa); } #endif isakmpd-20041012.orig/sysdep/freeswan/sys/0000755000175000017500000000000010133045740020514 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/freeswan/sys/queue.h0000644000175000017500000002671410133045740022023 0ustar jdivejdive00000000000000/* $OpenBSD: queue.h,v 1.2 2003/06/02 20:06:15 millert Exp $ */ /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ #ifndef NULL #define NULL ((void *)0) #endif /* * This file defines four types of data structures: lists, simple queues, * tail queues, and circular queues. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A simple queue is headed by a pair of pointers, one the head of the * list and the other to the tail of the list. The elements are singly * linked to save space, so only elements can only be removed from the * head of the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the * list. A simple queue may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * A circle queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the list. * A circle queue may be traversed in either direction, but has a more * complex end of list detection. * * For details on the use of these macros, see the queue(3) manual page. */ /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } #define LIST_FIRST(head) ((head)->lh_first) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_END(head) NULL /* * List functions. */ #define LIST_INIT(head) do { \ (head)->lh_first = NULL; \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (0) #define LIST_REMOVE(elm, field) do { \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ } while (0) /* * Simple queue definitions. */ #define SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } #define SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } /* * Simple queue functions. */ #define SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (0) #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (0) #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (0) #define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \ if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) /* * Tail queue definitions. */ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_END(head) NULL #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) /* * Tail queue functions. */ #define TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_REMOVE(head, elm, field) do { \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ } while (0) /* * Circular queue definitions. */ #define CIRCLEQ_HEAD(name, type) \ struct name { \ struct type *cqh_first; /* first element */ \ struct type *cqh_last; /* last element */ \ } #define CIRCLEQ_ENTRY(type) \ struct { \ struct type *cqe_next; /* next element */ \ struct type *cqe_prev; /* previous element */ \ } #define CIRCLEQ_FIRST(head) ((head)->cqh_first) #define CIRCLEQ_LAST(head) ((head)->cqh_last) #define CIRCLEQ_END(head) ((void *)(head)) #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) /* * Circular queue functions. */ #define CIRCLEQ_INIT(head) do { \ (head)->cqh_first = (void *)(head); \ (head)->cqh_last = (void *)(head); \ } while (0) #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ (elm)->field.cqe_prev = (listelm); \ if ((listelm)->field.cqe_next == (void *)(head)) \ (head)->cqh_last = (elm); \ else \ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ (listelm)->field.cqe_next = (elm); \ } while (0) #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm); \ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ if ((listelm)->field.cqe_prev == (void *)(head)) \ (head)->cqh_first = (elm); \ else \ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ (listelm)->field.cqe_prev = (elm); \ } while (0) #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.cqe_next = (head)->cqh_first; \ (elm)->field.cqe_prev = (void *)(head); \ if ((head)->cqh_last == (void *)(head)) \ (head)->cqh_last = (elm); \ else \ (head)->cqh_first->field.cqe_prev = (elm); \ (head)->cqh_first = (elm); \ } while (0) #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.cqe_next = (void *)(head); \ (elm)->field.cqe_prev = (head)->cqh_last; \ if ((head)->cqh_first == (void *)(head)) \ (head)->cqh_first = (elm); \ else \ (head)->cqh_last->field.cqe_next = (elm); \ (head)->cqh_last = (elm); \ } while (0) #define CIRCLEQ_REMOVE(head, elm, field) do { \ if ((elm)->field.cqe_next == (void *)(head)) \ (head)->cqh_last = (elm)->field.cqe_prev; \ else \ (elm)->field.cqe_next->field.cqe_prev = \ (elm)->field.cqe_prev; \ if ((elm)->field.cqe_prev == (void *)(head)) \ (head)->cqh_first = (elm)->field.cqe_next; \ else \ (elm)->field.cqe_prev->field.cqe_next = \ (elm)->field.cqe_next; \ } while (0) #endif /* !_SYS_QUEUE_H_ */ isakmpd-20041012.orig/sysdep/freeswan/sys/CVS/0000755000175000017500000000000010133045751021151 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/freeswan/GNUmakefile.sysdep0000644000175000017500000000512210133045740023256 0ustar jdivejdive00000000000000# $OpenBSD: GNUmakefile.sysdep,v 1.2 2003/06/03 14:53:11 ho Exp $ # # Copyright (c) 1999 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # # In order for this to work, invocations need to set FREESWAN to the # directory where FreeS/WAN is installed. ifndef FREESWAN FREESWAN= /usr/src/freeswan endif BINDIR= /usr/local/sbin # Partly good for RedHat 5.2, but man(1) does not find them so I have it # disabled for now. #MANDIR= /var/catman/cat #MAN5= isakmpd.conf.0 #MAN8= isakmpd.0 NOMAN= LIBGMP= -lgmp LIBDES= ${FREESWAN}/libdes/libdes.a LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep LIBSYSDEP= ${LIBSYSDEPDIR}/libsysdep.a FEATURES= tripledes blowfish cast ec aggressive debug SRCS+= klips.c LDADD+= ${LIBSYSDEP} ${LIBGMP} ${LIBDES} -ldl DPADD+= ${LIBSYSDEP} ${LIBGMP} ${LIBDES} CFLAGS+= -I${FREESWAN}/gmp -I${FREESWAN}/libdes \ -I${FREESWAN}/klips -I${FREESWAN}/lib -DUSE_OLD_SOCKADDR \ -I${.CURDIR}/sysdep/common -DSYMBOL_PREFIX='"_"' CFLAGS+= -DMP_FLAVOUR=MP_FLAVOUR_GMP CFLAGS+= -D'SALEN(x)=8' ${LIBSYSDEP}: cd ${LIBSYSDEPDIR}; \ ${MAKE} --no-print-directory ${MAKEFLAGS} CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ifneq ($(findstring install,$(MAKECMDGOALS)),install) SUBDIR+= sysdep/common/libsysdep # The regress/ subdir is completely broken in the linux environment SUBDIR:= $(filter-out regress,${SUBDIR}) endif isakmpd-20041012.orig/sysdep/freeswan/sysdep-os.h0000644000175000017500000000335110133045740021777 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep-os.h,v 1.2 2003/06/03 14:53:11 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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. * * 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. */ /* * This code was written under funding by Ericsson Radio Systems. */ #ifndef _SYSDEP_OS_H_ #define _SYSDEP_OS_H_ typedef u_int16_t in_port_t; typedef u_int32_t in_addr_t; #if 0 /* * Why -D__USE_GNU does not work in order to get this from stdio.h beats me. */ extern int asprintf(char **, const char *, ...); #endif #define DL_LAZY RTLD_LAZY #endif /* _SYSDEP_OS_H_ */ isakmpd-20041012.orig/sysdep/freeswan/CVS/0000755000175000017500000000000010133045751020333 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/netbsd/0000755000175000017500000000000010133045740017343 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/netbsd/Makefile.sysdep0000644000175000017500000000545510133045740022322 0ustar jdivejdive00000000000000# $OpenBSD: Makefile.sysdep,v 1.10 2004/06/26 03:40:57 mcbride Exp $ # # Copyright (c) 1999 Niklas Hallqvist. 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 # 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. # # 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 INN 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. # # Override default features FEATURES= tripledes des blowfish cast ec aggressive debug x509 FEATURES+= rawkey # Not yet #FEATURES+= policy isakmp_cfg LIBGMP= /usr/pkg/lib/libgmp.a LIBCRYPTO= /usr/lib/libcrypto.a LIBSYSDEPDIR= ${.CURDIR}/sysdep/common/libsysdep LDADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a -lipsec DPADD+= ${LIBGMP} ${LIBSYSDEPDIR}/libsysdep.a ${LIBIPSEC} CFLAGS+= -DNO_RSA -DNO_IDEA -DNO_RC5 \ -DHAVE_GETIFADDRS \ -I${.CURDIR}/sysdep/common .if exists(/usr/pkg/include/openssl/rsa.h) CFLAGS+= -I/usr/pkg/include/openssl .elif exists(/usr/include/openssl/rsa.h) CFLAGS+= -I/usr/include -I/usr/include/openssl .endif # mandatory for gmp CFLAGS+= -I/usr/pkg/include LDADD+= -L/usr/pkg/lib IPSEC_SRCS= pf_key_v2.c IPSEC_CFLAGS= -DUSE_PF_KEY_V2 USE_LIBCRYPTO= defined USE_GMP= defined # This is a hack in order to make sure libsysdep is built before the # linkstage of isakmpd. As a side effect the link is always done even if # not necessary. Well, I just don't care. GENERATED+= sysdep-target sysdep-target: cd ${.CURDIR}/sysdep/common/libsysdep; ${MAKE} ${.MAKEFLAGS} .if make(clean) || make(cleandir) SUBDIR+= sysdep/common/libsysdep .endif # Kludge around bug in /usr/share/mk/bsd.subdir.mk NO_REGRESS= defined beforedepend: rm -f ssl .if exists(/usr/pkg/include/openssl/rsa.h) ln -sf /usr/pkg/include/openssl ssl .elif exists(/usr/include/openssl/rsa.h) ln -sf /usr/include/openssl ssl .endif isakmpd-20041012.orig/sysdep/netbsd/sysdep.c0000644000175000017500000001267510133045740021031 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep.c,v 1.13 2004/08/10 15:59:10 ho Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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 * 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. * * 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 #include #include #include #include #include #include "sysdep.h" #include "util.h" #ifdef NEED_SYSDEP_APP #include "app.h" #include "conf.h" #include "ipsec.h" #ifdef USE_PF_KEY_V2 #include "pf_key_v2.h" #define KEY_API(x) pf_key_v2_##x #endif #endif /* NEED_SYSDEP_APP */ #include "log.h" extern char *__progname; /* * An as strong as possible random number generator, reverting to a * deterministic pseudo-random one if regrand is set. */ u_int32_t sysdep_random () { return random(); } /* Return the basename of the command used to invoke us. */ char * sysdep_progname () { return __progname; } /* Return the length of the sockaddr struct. */ u_int8_t sysdep_sa_len (struct sockaddr *sa) { return sa->sa_len; } /* As regress/ use this file I protect the sysdep_app_* stuff like this. */ #ifdef NEED_SYSDEP_APP /* * Prepare the application we negotiate SAs for (i.e. the IPsec stack) * for communication. We return a file descriptor useable to select(2) on. */ int sysdep_app_open () { return KEY_API(open) (); } /* * When select(2) has noticed our application needs attendance, this is what * gets called. FD is the file descriptor causing the alarm. */ void sysdep_app_handler (int fd) { KEY_API (handler) (fd); } /* Check that the connection named NAME is active, or else make it active. */ void sysdep_connection_check (char *name) { KEY_API (connection_check) (name); } /* * Generate a SPI for protocol PROTO and the source/destination pair given by * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. */ u_int8_t * sysdep_ipsec_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, struct sockaddr *dst, u_int32_t seq) { if (app_none) { *sz = IPSEC_SPI_SIZE; /* XXX should be random instead I think. */ return strdup ("\x12\x34\x56\x78"); } return KEY_API (get_spi) (sz, proto, src, dst, seq); } struct sa_kinfo * sysdep_ipsec_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto, struct sockaddr *dst) { if (app_none) return 0; /* XXX return KEY_API(get_kernel_sa)(spi, spi_sz, proto, dst); */ return 0; } /* Force communication on socket FD to go in the clear. */ int sysdep_cleartext (int fd, int af) { char *buf; char *policy[] = { "in bypass", "out bypass", NULL }; char **p; int ipp; int opt; char *msgstr; if (app_none) return 0; switch (af) { case AF_INET: ipp = IPPROTO_IP; opt = IP_IPSEC_POLICY; msgstr = ""; break; case AF_INET6: ipp = IPPROTO_IPV6; opt = IPV6_IPSEC_POLICY; msgstr = "V6"; break; default: log_print ("sysdep_cleartext: unsupported protocol family %d", af); return -1; } /* * Need to bypass system security policy, so I can send and * receive key management datagrams in the clear. */ for (p = policy; p && *p; p++) { buf = ipsec_set_policy (*p, strlen(*p)); if (buf == NULL) { log_error ("sysdep_cleartext: %s: %s", *p, ipsec_strerror()); return -1; } if (setsockopt(fd, ipp, opt, buf, ipsec_get_policylen(buf)) < 0) { log_error ("sysdep_cleartext: " "setsockopt (%d, IPPROTO_IP%s, IP%s_IPSEC_POLICY, ...) " "failed", fd, msgstr, msgstr); return -1; } free(buf); } return 0; } int sysdep_ipsec_delete_spi (struct sa *sa, struct proto *proto, int incoming) { if (app_none) return 0; return KEY_API (delete_spi) (sa, proto, incoming); } int sysdep_ipsec_enable_sa (struct sa *sa, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API (enable_sa) (sa, isakmp_sa); } int sysdep_ipsec_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2, int incoming) { if (app_none) return 0; return KEY_API (group_spis) (sa, proto1, proto2, incoming); } int sysdep_ipsec_set_spi (struct sa *sa, struct proto *proto, int incoming, struct sa *isakmp_sa) { if (app_none) return 0; return KEY_API (set_spi) (sa, proto, incoming, isakmp_sa); } #endif isakmpd-20041012.orig/sysdep/netbsd/GNUmakefile.sysdep0000644000175000017500000000441510133045740022727 0ustar jdivejdive00000000000000# $OpenBSD: GNUmakefile.sysdep,v 1.8 2004/06/26 03:40:57 mcbride Exp $ # # Copyright (c) 1999 Niklas Hallqvist. 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 # 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. # # 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. # LIBGMP:= /usr/pkg/lib/libgmp.a LIBCRYPTO:= /usr/lib/libcrypto.a LIBSYSDEPDIR:= ${.CURDIR}/sysdep/common/libsysdep LIBSYSDEP:= ${LIBSYSDEPDIR}/libsysdep.a LDADD+= ${LIBGMP} ${LIBSYSDEP} DPADD+= ${LIBGMP} ${LIBSYSDEP} FEATURES= debug tripledes des blowfish cast ec aggressive x509 # Not yet #FEATURES+= policy CFLAGS+= -DNO_RSA -DNO_RC5 -DNO_IDEA \ -I${.CURDIR}/sysdep/common -I/usr/include/openssl \ -I/usr/include/machine -I/usr/pkg/include IPSEC_SRCS= pf_key_v2.c IPSEC_CFLAGS= -DUSE_PF_KEY_V2 USE_LIBCRYPTO= defined # # hack libsysdep.a dependency # ${LIBSYSDEPDIR}/.depend ${LIBSYSDEP}: @cd ${LIBSYSDEPDIR} && \ ${MAKE} --no-print-directory ${MAKEFLAGS} \ CFLAGS="${CFLAGS}" MKDEP="${MKDEP}" ${MAKECMDGOALS} depend: ${LIBSYSDEPDIR}/.depend ifeq ($(findstring clean, $(MAKECMDGOALS)), clean) SUBDIR+= sysdep/common/libsysdep MAKEFLAGS+= --no-print-directory endif isakmpd-20041012.orig/sysdep/netbsd/sysdep-os.h0000644000175000017500000000365310133045740021451 0ustar jdivejdive00000000000000/* $OpenBSD: sysdep-os.h,v 1.5 2003/08/06 11:20:00 markus Exp $ */ /* * Copyright (c) 1998, 1999 Niklas Hallqvist. 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 * 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. * * 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. */ #ifndef _SYSDEP_OS_H_ #define _SYSDEP_OS_H_ #define KAME #include #ifndef CPI_RESERVED_MAX #define CPI_RESERVED_MIN 1 #define CPI_RESERVED_MAX 255 #define CPI_PRIVATE_MIN 61440 #define CPI_PRIVATE_MAX 65536 #endif #if !defined(SADB_X_EALG_CAST) && defined(SADB_X_EALG_CAST128CBC) #define SADB_X_EALG_CAST SADB_X_EALG_CAST128CBC #endif #if !defined(SADB_X_EALG_BLF) && defined(SADB_X_EALG_BLOWFISHCBC) #define SADB_X_EALG_BLF SADB_X_EALG_BLOWFISHCBC #endif #endif /* _SYSDEP_OS_H_ */ isakmpd-20041012.orig/sysdep/netbsd/CVS/0000755000175000017500000000000010133045751020000 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/common/0000755000175000017500000000000010133045740017354 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/common/pcap.h0000644000175000017500000000523010133045740020450 0ustar jdivejdive00000000000000/* $OpenBSD: pcap.h,v 1.2 2002/05/10 15:09:00 ho Exp $ */ /* * Copyright (c) 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. * * @(#) $Header: /cvs/src/sbin/isakmpd/sysdep/common/pcap.h,v 1.2 2002/05/10 15:09:00 ho Exp $ (LBL) */ #ifndef lib_pcap_h #define lib_pcap_h #include #include #define PCAP_VERSION_MAJOR 2 #define PCAP_VERSION_MINOR 4 #define DLT_LOOP 12 /* from /usr/include/net/bpf.h */ struct pcap_file_header { u_int32_t magic; u_int16_t version_major; u_int16_t version_minor; int32_t thiszone; /* gmt to local correction */ u_int32_t sigfigs; /* accuracy of timestamps */ u_int32_t snaplen; /* max length saved portion of each pkt */ u_int32_t linktype; /* data link type (DLT_*) */ }; struct pcap_pkthdr { struct timeval ts; /* time stamp */ u_int32_t caplen; /* length of portion present */ u_int32_t len; /* length this packet (off wire) */ }; #endif /* lib_pcap_h */ isakmpd-20041012.orig/sysdep/common/libsysdep/0000755000175000017500000000000010133045740021352 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/common/libsysdep/Makefile0000644000175000017500000000325510133045740023017 0ustar jdivejdive00000000000000# $OpenBSD: Makefile,v 1.4 2003/06/03 14:52:06 ho Exp $ # # Copyright (c) 1999 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # OPSYS!= uname -s LIB= sysdep SRCS= arc4random.c blowfish.c cast.c md5.c sha1.c strlcat.c strlcpy.c NOPROFILE= NOPIC= NOMAN= .if ${OPSYS} == "NetBSD" CPPFLAGS+= -I${.CURDIR}/.. -I/usr/include/machine .else CFLAGS+= -I${.CURDIR}/.. -I/usr/include/machine .endif .include isakmpd-20041012.orig/sysdep/common/libsysdep/strlcat.c0000644000175000017500000000354310133045740023177 0ustar jdivejdive00000000000000/* $OpenBSD: strlcat.c,v 1.3 2003/06/17 21:56:24 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcat.c,v 1.3 2003/06/17 21:56:24 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t strlcat(dst, src, siz) char *dst; const char *src; size_t siz; { register char *d = dst; register const char *s = src; register size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } isakmpd-20041012.orig/sysdep/common/libsysdep/GNUmakefile0000644000175000017500000000356510133045740023435 0ustar jdivejdive00000000000000# $OpenBSD: GNUmakefile,v 1.4 2003/06/03 14:52:06 ho Exp $ # # Copyright (c) 1999 Niklas Hallqvist. 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. # # 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. # # # This code was written under funding by Ericsson Radio Systems. # .CURDIR:= $(shell pwd) LIB= sysdep SRCS= arc4random.c blowfish.c cast.c md5.c sha1.c strlcat.c strlcpy.c NOMAN= CFLAGS+= -I${.CURDIR}/.. -I/usr/include/machine lib${LIB}.a: ${SRCS:%.c=%.o} ar cq $@ ${SRCS:%.c=%.o} clean: rm -f lib${LIB}.a ${SRCS:%.c=%.o} cleandir: clean cleandepend depend: .depend .depend: ${SRCS} @rm -f .depend ${MKDEP} ${CFLAGS} ${SRCS} > .depend cleandepend: rm -f .depend ifneq ($(findstring clean,$(MAKECMDGOALS)),clean) -include .depend endif isakmpd-20041012.orig/sysdep/common/libsysdep/arc4random.c0000644000175000017500000000710110133045740023547 0ustar jdivejdive00000000000000/* $OpenBSD: arc4random.c,v 1.6 2004/10/08 15:18:26 hshoexer Exp $ */ /* * Arc4 random number generator for OpenBSD. * Copyright 1996 David Mazieres . * * Modification and redistribution in source and binary forms is * permitted provided that due credit is given to the author and the * OpenBSD project by leaving this copyright notice intact. */ /* * This code is derived from section 17.1 of Applied Cryptography, * second edition, which describes a stream cipher allegedly * compatible with RSA Labs "RC4" cipher (the actual description of * which is a trade secret). The same algorithm is used as a stream * cipher called "arcfour" in Tatu Ylonen's ssh package. * * Here the stream cipher has been modified always to include the time * when initializing the state. That makes it impossible to * regenerate the same random sequence twice, so this can't be used * for encryption, but will generate good random numbers. * * RC4 is a registered trademark of RSA Laboratories. */ #include #include #include #include #include #ifdef __GNUC__ #define inline __inline #else /* !__GNUC__ */ #define inline #endif /* !__GNUC__ */ struct arc4_stream { u_int8_t i; u_int8_t j; u_int8_t s[256]; }; int rs_initialized; static struct arc4_stream rs; static inline u_int8_t arc4_getbyte(struct arc4_stream *); static inline void arc4_init(struct arc4_stream *as) { int n; for (n = 0; n < 256; n++) as->s[n] = n; as->i = 0; as->j = 0; } static inline void arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen) { int n; u_int8_t si; as->i--; for (n = 0; n < 256; n++) { as->i = (as->i + 1); si = as->s[as->i]; as->j = (as->j + si + dat[n % datlen]); as->s[as->i] = as->s[as->j]; as->s[as->j] = si; } as->j = as->i; } static void arc4_stir(struct arc4_stream *as) { int fd; struct { struct timeval tv; u_int8_t rnd[128 - sizeof(struct timeval)]; } rdat; gettimeofday(&rdat.tv, NULL); fd = open("/dev/arandom", O_RDONLY); if (fd < 0) fd = open("/dev/random", O_RDONLY); if (fd >= 0) { read(fd, rdat.rnd, sizeof(rdat.rnd)); close(fd); } /* fd < 0? Ah, what the heck. We'll just take whatever was on the * stack... */ arc4_addrandom(as, (void *)&rdat, sizeof(rdat)); /* * Discard early keystream, as per recommendations in: * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps */ for (i = 0; i < 256; i++) (void)arc4_getbyte(as); } static inline u_int8_t arc4_getbyte(struct arc4_stream *as) { u_int8_t si, sj; as->i = (as->i + 1); si = as->s[as->i]; as->j = (as->j + si); sj = as->s[as->j]; as->s[as->i] = sj; as->s[as->j] = si; return (as->s[(si + sj) & 0xff]); } static inline u_int32_t arc4_getword(struct arc4_stream *as) { u_int32_t val; val = arc4_getbyte(as) << 24; val |= arc4_getbyte(as) << 16; val |= arc4_getbyte(as) << 8; val |= arc4_getbyte(as); return val; } void arc4random_stir(void) { if (!rs_initialized) { arc4_init(&rs); rs_initialized = 1; } arc4_stir(&rs); } void arc4random_addrandom(u_char *dat, int datlen) { if (!rs_initialized) arc4random_stir(); arc4_addrandom(&rs, dat, datlen); } u_int32_t arc4random(void) { if (!rs_initialized) arc4random_stir(); return arc4_getword(&rs); } #if 0 /*-------- Test code for i386 --------*/ #include #include int main(int argc, char **argv) { const int iter = 1000000; int i; pctrval v; v = rdtsc(); for (i = 0; i < iter; i++) arc4random(); v = rdtsc() - v; v /= iter; printf("%qd cycles\n", v); } #endif isakmpd-20041012.orig/sysdep/common/libsysdep/cast.c0000644000175000017500000007747310133045740022472 0ustar jdivejdive00000000000000/* $OpenBSD: cast.c,v 1.3 2001/06/05 00:12:51 niklas Exp $ */ /* * CAST-128 in C * Written by Steve Reid * 100% Public Domain - no warranty * Released 1997.10.11 */ #include #include /* CAST S-Boxes */ static const u_int32_t cast_sbox1[256] = { 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, 0x1E213F2F, 0x9C004DD3, 0x6003E540, 0xCF9FC949, 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675, 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, 0x28683B6F, 0xC07FD059, 0xFF2379C8, 0x775F50E2, 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D, 0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, 0x2ABE32E1, 0xAA54166B, 0x22568E3A, 0xA2D341D0, 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE, 0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, 0xB82CBAEF, 0xD751D159, 0x6FF7F0ED, 0x5A097A1F, 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935, 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, 0xB7332290, 0xE93B159F, 0xB48EE411, 0x4BFF345D, 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165, 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, 0x882240F2, 0x0C6E4F38, 0xA4E4BFD7, 0x4F5BA272, 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE, 0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, 0x57538AD5, 0x6A390493, 0xE63D37E0, 0x2A54F6B3, 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A, 0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, 0x38901091, 0xC6B505EB, 0x84C7CB8C, 0x2AD75A0F, 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291, 0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, 0x6C00B32D, 0x73E2BB14, 0xA0BEBC3C, 0x54623779, 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6, 0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, 0x81383F05, 0x6963C5C8, 0x76CB5AD6, 0xD49974C9, 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511, 0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, 0x31366241, 0x051EF495, 0xAA573B04, 0x4A805D8D, 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E, 0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, 0x6B54BFAB, 0x2B0B1426, 0xAB4CC9D7, 0x449CCD82, 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324, 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, 0xEADF55B3, 0xD5BD9E98, 0xE31231B2, 0x2AD5AD6C, 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F, 0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, 0x7B5A41F0, 0xD37CFBAD, 0x1B069505, 0x41ECE491, 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D, 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, 0xE01063DA, 0x4736F464, 0x5AD328D8, 0xB347CC96, 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A, 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, 0x3F04442F, 0x6188B153, 0xE0397A2E, 0x5727CB79, 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D, 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, 0x4744EAD4, 0xB11C3274, 0xDD24CB9E, 0x7E1C54BD, 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755, 0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, 0x580304F0, 0xCA042CF1, 0x011A37EA, 0x8DBFAADB, 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9, 0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, 0x7C63B2CF, 0x700B45E1, 0xD5EA50F1, 0x85A92872, 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79, 0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, 0x474D6AD7, 0x7C0C5E5C, 0xD1231959, 0x381B7298, 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E, 0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, 0x962BDA1C, 0xE1E696FF, 0xB141AB08, 0x7CCA89B9, 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D, 0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF }; static const u_int32_t cast_sbox2[256] = { 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, 0xFE61CF7A, 0xEEC5207A, 0x55889C94, 0x72FC0651, 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA, 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, 0xA0B52F7B, 0x59E83605, 0xEE15B094, 0xE9FFD909, 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB, 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, 0x01420DDB, 0xE4E7EF5B, 0x25A1FF41, 0xE180F806, 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4, 0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, 0xE113C85B, 0xACC40083, 0xD7503525, 0xF7EA615F, 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359, 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, 0x071F6181, 0x39F7627F, 0x361E3084, 0xE4EB573B, 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D, 0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, 0x10843094, 0x2537A95E, 0xF46F6FFE, 0xA1FF3B1F, 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34, 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, 0x8A45388C, 0x1D804366, 0x721D9BFD, 0xA58684BB, 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4, 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, 0xC5D655DD, 0xEB667064, 0x77840B4D, 0xA1B6A801, 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860, 0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, 0xB5625DBF, 0x68561BE6, 0x83CA6B94, 0x2D6ED23B, 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709, 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, 0x81ED6F61, 0x20E74364, 0xB45E1378, 0xDE18639B, 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B, 0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, 0x488CB402, 0x1BA4FE5B, 0xA4B09F6B, 0x1CA815CF, 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9, 0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, 0xEE41E729, 0x6E1D2D7C, 0x50045286, 0x1E6685F3, 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13, 0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, 0xCDFF33A6, 0xA02B1741, 0x7CBAD9A2, 0x2180036F, 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB, 0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, 0xCDF0B680, 0x17844D3B, 0x31EEF84D, 0x7E0824E4, 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6, 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, 0xB3FAEC54, 0x157FD7FA, 0xEF8579CC, 0xD152DE58, 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8, 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, 0xB8DA230C, 0x80823028, 0xDCDEF3C8, 0xD35FB171, 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D, 0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, 0x8B1C34BC, 0x301E16E6, 0x273BE979, 0xB0FFEAA6, 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B, 0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, 0xDC8637A0, 0x16A7D3B1, 0x9FC393B7, 0xA7136EEB, 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6, 0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, 0xDB92F2FB, 0x5EEA29CB, 0x145892F5, 0x91584F7F, 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA, 0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, 0xB284600C, 0xD835731D, 0xDCB1C647, 0xAC4C56EA, 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA, 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, 0x649DA589, 0xA345415E, 0x5C038323, 0x3E5D3BB9, 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF, 0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 }; static const u_int32_t cast_sbox3[256] = { 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, 0x47607FFF, 0x369FE44B, 0x8C1FC644, 0xAECECA90, 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE, 0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, 0x11107D9F, 0x07647DB9, 0xB2E3E4D4, 0x3D4F285E, 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E, 0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, 0x21FFFCEE, 0x825B1BFD, 0x9255C5ED, 0x1257A240, 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E, 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, 0xA8C01DB7, 0x579FC264, 0x67094F31, 0xF2BD3F5F, 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B, 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, 0xA197C81C, 0x4A012D6E, 0xC5884A28, 0xCCC36F71, 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F, 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, 0xA747D2D0, 0x1651192E, 0xAF70BF3E, 0x58C31380, 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82, 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, 0x8427F4A0, 0x1EAC5790, 0x796FB449, 0x8252DC15, 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504, 0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, 0x23EFE941, 0xA903F12E, 0x60270DF2, 0x0276E4B6, 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176, 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, 0x842F7D83, 0x340CE5C8, 0x96BBB682, 0x93B4B148, 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D, 0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, 0x8B907CEE, 0xB51FD240, 0xE7C07CE3, 0xE566B4A1, 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341, 0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, 0xF76CEDD9, 0xBDA8229C, 0x127DADAA, 0x438A074E, 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15, 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, 0x68CC7BFB, 0xD90F2788, 0x12490181, 0x5DE5FFD4, 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F, 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, 0x6D498623, 0x193CBCFA, 0x27627545, 0x825CF47A, 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392, 0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, 0x285BA1C8, 0x3C62F44F, 0x35C0EAA5, 0xE805D231, 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B, 0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, 0x694BCC11, 0x236A5CAE, 0x12DECA4D, 0x2C3F8CC5, 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67, 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, 0x3A609437, 0xEC00C9A9, 0x44715253, 0x0A874B49, 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536, 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, 0x07478CD1, 0x006E1888, 0xA2E53F55, 0xB9E6D4BC, 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D, 0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, 0x947B0001, 0x570075D2, 0xF9BB88F8, 0x8942019E, 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69, 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, 0xCF1FEBD2, 0x61EFC8C2, 0xF1AC2571, 0xCC8239C2, 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE, 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, 0x5727C148, 0x2BE98A1D, 0x8AB41738, 0x20E1BE24, 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D, 0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, 0x642B1E31, 0x9C305A00, 0x52BCE688, 0x1B03588A, 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5, 0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 }; static const u_int32_t cast_sbox4[256] = { 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, 0x4A4F7BDB, 0x64AD8C57, 0x85510443, 0xFA020ED1, 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120, 0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, 0x28147F5F, 0x4FA2B8CD, 0xC9430040, 0x0CC32220, 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15, 0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, 0x1A05645F, 0x0C13FEFE, 0x081B08CA, 0x05170121, 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701, 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, 0xCE84FFDF, 0xF5718801, 0x3DD64B04, 0xA26F263B, 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5, 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, 0xD3772061, 0x11B638E1, 0x72500E03, 0xF80EB2BB, 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746, 0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, 0x4D351805, 0x7F3D5CE3, 0xA6C866C6, 0x5D5BCCA9, 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D, 0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, 0x022083B8, 0x3FB6180C, 0x18F8931E, 0x281658E6, 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C, 0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, 0x69DEAD38, 0x1574CA16, 0xDF871B62, 0x211C40B7, 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003, 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, 0x557BE8DE, 0x00EAE4A7, 0x0CE5C2EC, 0x4DB4BBA6, 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327, 0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, 0x6E85CB75, 0xBE07C002, 0xC2325577, 0x893FF4EC, 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24, 0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, 0xAAC9548A, 0xECA1D7C7, 0x041AFA32, 0x1D16625A, 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031, 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, 0x026A4CEB, 0x52437EFF, 0x2F8F76B4, 0x0DF980A5, 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF, 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, 0x1741A254, 0xE5B6A035, 0x213D42F6, 0x2C1C7C26, 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69, 0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, 0x63315C21, 0x5E0A72EC, 0x49BAFEFD, 0x187908D9, 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7, 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, 0x71EAE2A1, 0x1F9AF36E, 0xCFCBD12F, 0xC1DE8417, 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3, 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, 0x6F7DE532, 0x58FD7EB6, 0xD01EE900, 0x24ADFFC2, 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2, 0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, 0x29908415, 0x7FBB977F, 0xAF9EB3DB, 0x29C9ED2A, 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091, 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, 0x77079103, 0xDEA03AF6, 0x78A8565E, 0xDEE356DF, 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF, 0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, 0xAFE67AFB, 0xF470C4B2, 0xF3E0EB5B, 0xD6CC9876, 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367, 0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, 0xB5676E69, 0x9BD3DDDA, 0xDF7E052F, 0xDB25701C, 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04, 0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, 0x41823979, 0x932BCDF6, 0xB657C34D, 0x4EDFD282, 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E, 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 }; static const u_int32_t cast_sbox5[256] = { 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, 0xB86A7FFF, 0x1DD358F5, 0x44DD9D44, 0x1731167F, 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00, 0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, 0xE6A2E77F, 0xF0C720CD, 0xC4494816, 0xCCF5C180, 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF, 0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, 0x4E40B48D, 0x248EB6FB, 0x8DBA1CFE, 0x41A99B02, 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725, 0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, 0xF2F3F763, 0x68AF8040, 0xED0C9E56, 0x11B4958B, 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7, 0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, 0x0C05372A, 0x578535F2, 0x2261BE02, 0xD642A0C9, 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC, 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, 0x5C1FF900, 0xFE38D399, 0x0C4EFF0B, 0x062407EA, 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774, 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, 0xDF65001F, 0x0EC50966, 0xDFDD55BC, 0x29DE0655, 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468, 0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, 0xBCF3F0AA, 0x87AC36E9, 0xE53A7426, 0x01B3D82B, 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910, 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, 0x636737B6, 0x50F5B616, 0xF24766E3, 0x8ECA36C1, 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4, 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, 0x26E46695, 0xB7566419, 0xF654EFC5, 0xD08D58B7, 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049, 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, 0xC62BF3CD, 0x9E0885F9, 0x68CB3E47, 0x086C010F, 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6, 0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, 0x0AB378D5, 0xD951FB0C, 0xDED7DA56, 0x4124BBE4, 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE, 0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, 0xC3DC0280, 0x05687715, 0x646C6BD7, 0x44904DB3, 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6, 0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, 0x76F0AE02, 0x083BE84D, 0x28421C9A, 0x44489406, 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4, 0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, 0x3CA5D717, 0x7D161BBA, 0x9CAD9010, 0xAF462BA2, 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487, 0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, 0x445F7382, 0x175683F4, 0xCDC66A97, 0x70BE0288, 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5, 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, 0x1C5C1572, 0xF6721B2C, 0x1AD2FFF3, 0x8C25404E, 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78, 0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, 0x44094F85, 0x3F481D87, 0xFCFEAE7B, 0x77B5FF76, 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801, 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, 0xDF3B0874, 0x95055110, 0x1B5AD7A8, 0xF61ED5AD, 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58, 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, 0x5CE96C28, 0xE176EDA3, 0x6BAC307F, 0x376829D2, 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20, 0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, 0xF9E0659A, 0xEEB9491D, 0x34010718, 0xBB30CAB8, 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55, 0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 }; static const u_int32_t cast_sbox6[256] = { 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, 0x95DB08E7, 0x016843B4, 0xECED5CBC, 0x325553AC, 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9, 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, 0x33F14961, 0xC01937BD, 0xF506C6DA, 0xE4625E7E, 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367, 0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, 0xA084DB2D, 0x09A8486F, 0xA888614A, 0x2900AF98, 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C, 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, 0xFD41197E, 0x9305A6B0, 0xE86BE3DA, 0x74BED3CD, 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3, 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, 0x5C3D9C01, 0x64BDB941, 0x2C0E636A, 0xBA7DD9CD, 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D, 0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, 0x284CAF89, 0xAA928223, 0x9334BE53, 0x3B3A21BF, 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9, 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, 0x5B7C5ECC, 0x221DB3A6, 0x9A69A02F, 0x68818A54, 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A, 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, 0x53BDDB65, 0xE76FFBE7, 0xE967FD78, 0x0BA93563, 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC, 0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, 0xE81F994F, 0x9528CD89, 0xFD339FED, 0xB87834BF, 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE, 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, 0x4EC75B95, 0x24F2C3C0, 0x42D15D99, 0xCD0D7FA0, 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F, 0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, 0x372B74AF, 0x692573E4, 0xE9A9D848, 0xF3160289, 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853, 0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, 0x36F73523, 0x4CFB6E87, 0x7DA4CEC0, 0x6C152DAA, 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F, 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, 0x2B05D08D, 0x48B9D585, 0xDC049441, 0xC8098F9B, 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751, 0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, 0xBF32679D, 0xD45B5B75, 0xB353FD00, 0xCBB0E358, 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13, 0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, 0x47CF8E7A, 0xB6C85283, 0x3CC2ACFB, 0x3FC06976, 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459, 0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, 0x3007CD3E, 0x74719EEF, 0xDC872681, 0x073340D4, 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891, 0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, 0x6FE4AC98, 0xB173ECC0, 0xBC60B42A, 0x953498DA, 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB, 0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, 0xE8816F4A, 0x3814F200, 0xA3F94043, 0x9C7A54C2, 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084, 0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, 0xBA5AC7B5, 0xB6F6DEAF, 0x3A479C3A, 0x5302DA25, 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B, 0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, 0xB81A928A, 0x60ED5869, 0x97C55B96, 0xEAEC991B, 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5, 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, 0xD36B4CF1, 0xF544EDEB, 0xB0E93524, 0xBEBB8FBD, 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454, 0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F }; static const u_int32_t cast_sbox7[256] = { 0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, 0x2A8D7F6F, 0xAB9BC912, 0xDE6008A1, 0x2028DA1F, 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82, 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, 0xA05FBCF6, 0xCD4181E9, 0xE150210C, 0xE24EF1BD, 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43, 0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, 0x089766BE, 0xBAEEADF4, 0x1286BECF, 0xB6EACB19, 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9, 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, 0x107789BE, 0xB3B2E9CE, 0x0502AA8F, 0x0BC0351E, 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516, 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, 0x334266CE, 0x8C9341B7, 0xD0D854C0, 0xCB3A6C88, 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E, 0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, 0x0A961288, 0xE1A5C06E, 0x13749E67, 0x72FC081A, 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756, 0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, 0xBC8EC511, 0x38BC46E9, 0xC6E6FA14, 0xBAE8584A, 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B, 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, 0x92544A8B, 0x009B4FC3, 0xABA68CED, 0x9AC96F78, 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688, 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, 0xF7DEBB85, 0x61FE033C, 0x16746233, 0x3C034C28, 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802, 0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, 0x0C4FB99A, 0xBB325778, 0x3EC6D97B, 0x6E77A6A9, 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7, 0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, 0xB96D8C32, 0xEBD4E7BE, 0xBE8B9D2D, 0x7979FB06, 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858, 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, 0xF28EBFB0, 0xF5B9C310, 0xA0EAC280, 0x08B9767A, 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A, 0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, 0x826D2BEF, 0x4EEB8476, 0x488DCF25, 0x36C9D566, 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF, 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, 0xF22B017D, 0xA4173F70, 0xDD1E16C3, 0x15E0D7F9, 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962, 0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, 0x93D29A22, 0xE32DBF9A, 0x058745B9, 0x3453DC1E, 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07, 0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, 0x66626C1C, 0x7154C24C, 0xEA082B2A, 0x93EB2939, 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C, 0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, 0xD3A0C108, 0xA1E7160E, 0xE4F2DFA6, 0x693ED285, 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378, 0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, 0xC79F022F, 0x3C997E7E, 0x5E4F9504, 0x3FFAFBBD, 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE, 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, 0x5592A33D, 0xB5229301, 0xCFD2A87F, 0x60AEB767, 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2, 0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, 0x97FD61A9, 0xEA7759F4, 0x2D57539D, 0x569A58CF, 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914, 0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, 0x3FFA50BC, 0x3D40F021, 0xC3C0BDAE, 0x4958C24C, 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA, 0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 }; static const u_int32_t cast_sbox8[256] = { 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, 0x7789F8B7, 0xE6C1121B, 0x0E241600, 0x052CE8B5, 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174, 0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, 0xDE9ADEB1, 0x0A0CC32C, 0xBE197029, 0x84A00940, 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD, 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, 0xC7ECE831, 0x3F8F95E7, 0x72DF191B, 0x7580330D, 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164, 0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, 0x12A8DDEC, 0xFDAA335D, 0x176F43E8, 0x71FB46D4, 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862, 0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, 0x4CFDE06F, 0xC28EC4B8, 0x57E8726E, 0x647A78FC, 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6, 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, 0xBBD35049, 0x2998DF04, 0x980CF42A, 0x9B6DF491, 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E, 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, 0x3CF1D2E2, 0x19B47A38, 0x424F7618, 0x35856039, 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8, 0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, 0x7170C608, 0x2D5E3354, 0xD4DE495A, 0x64C6D006, 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42, 0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, 0xF8D7E54E, 0x3E378160, 0x7895CDA5, 0x859C15A5, 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB, 0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, 0x835FFCB8, 0x6DF4C1F2, 0x96F5B195, 0xFD0AF0FC, 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225, 0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, 0xC4618187, 0xEA7A6E98, 0x7CD16EFC, 0x1436876C, 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441, 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, 0xA842EEDF, 0xFDBA60B4, 0xF1907B75, 0x20E3030F, 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054, 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, 0xF1E47D8D, 0x844A1BE5, 0xBAE7DFDC, 0x42CBDA70, 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C, 0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, 0x77853B53, 0x37EFFCB5, 0xC5068778, 0xE580B3E6, 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C, 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, 0xDD06CAA2, 0x37DF932B, 0xC4248289, 0xACF3EBC3, 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4, 0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, 0xE87B40E4, 0xE98EA084, 0x5889E9E1, 0xEFD390FC, 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101, 0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, 0x646F1282, 0x7523D24A, 0xE0779695, 0xF9C17A8F, 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF, 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, 0x11403092, 0x00DA6D77, 0x4A0CDD61, 0xAD1F4603, 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A, 0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, 0x2DE705CA, 0x8951570F, 0xDF09822B, 0xBD691A6C, 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819, 0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, 0x5938FA0F, 0x42399EF3, 0x36997B07, 0x0E84093D, 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C, 0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, 0x589E8D82, 0x0D2059D1, 0xA466BB1E, 0xF8DA0A82, 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D, 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E }; /* Macros to access 8-bit bytes out of a 32-bit word */ #define U8a(x) ( (u_int8_t) (x>>24) ) #define U8b(x) ( (u_int8_t) ((x>>16)&255) ) #define U8c(x) ( (u_int8_t) ((x>>8)&255) ) #define U8d(x) ( (u_int8_t) ((x)&255) ) /* Circular left shift */ #define ROL(x, n) ( ((x)<<(n)) | ((x)>>(32-(n))) ) /* CAST-128 uses three different round functions */ #define F1(l, r, i) \ t = ROL(key->xkey[i] + r, key->xkey[i+16]); \ l ^= ((cast_sbox1[U8a(t)] ^ cast_sbox2[U8b(t)]) - \ cast_sbox3[U8c(t)]) + cast_sbox4[U8d(t)]; #define F2(l, r, i) \ t = ROL(key->xkey[i] ^ r, key->xkey[i+16]); \ l ^= ((cast_sbox1[U8a(t)] - cast_sbox2[U8b(t)]) + \ cast_sbox3[U8c(t)]) ^ cast_sbox4[U8d(t)]; #define F3(l, r, i) \ t = ROL(key->xkey[i] - r, key->xkey[i+16]); \ l ^= ((cast_sbox1[U8a(t)] + cast_sbox2[U8b(t)]) ^ \ cast_sbox3[U8c(t)]) - cast_sbox4[U8d(t)]; /***** Encryption Function *****/ void cast_encrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock) { u_int32_t t, l, r; /* Get inblock into l,r */ l = ((u_int32_t)inblock[0] << 24) | ((u_int32_t)inblock[1] << 16) | ((u_int32_t)inblock[2] << 8) | (u_int32_t)inblock[3]; r = ((u_int32_t)inblock[4] << 24) | ((u_int32_t)inblock[5] << 16) | ((u_int32_t)inblock[6] << 8) | (u_int32_t)inblock[7]; /* Do the work */ F1(l, r, 0); F2(r, l, 1); F3(l, r, 2); F1(r, l, 3); F2(l, r, 4); F3(r, l, 5); F1(l, r, 6); F2(r, l, 7); F3(l, r, 8); F1(r, l, 9); F2(l, r, 10); F3(r, l, 11); /* Only do full 16 rounds if key length > 80 bits */ if (key->rounds > 12) { F1(l, r, 12); F2(r, l, 13); F3(l, r, 14); F1(r, l, 15); } /* Put l,r into outblock */ outblock[0] = U8a(r); outblock[1] = U8b(r); outblock[2] = U8c(r); outblock[3] = U8d(r); outblock[4] = U8a(l); outblock[5] = U8b(l); outblock[6] = U8c(l); outblock[7] = U8d(l); /* Wipe clean */ t = l = r = 0; } /***** Decryption Function *****/ void cast_decrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock) { u_int32_t t, l, r; /* Get inblock into l,r */ r = ((u_int32_t)inblock[0] << 24) | ((u_int32_t)inblock[1] << 16) | ((u_int32_t)inblock[2] << 8) | (u_int32_t)inblock[3]; l = ((u_int32_t)inblock[4] << 24) | ((u_int32_t)inblock[5] << 16) | ((u_int32_t)inblock[6] << 8) | (u_int32_t)inblock[7]; /* Do the work */ /* Only do full 16 rounds if key length > 80 bits */ if (key->rounds > 12) { F1(r, l, 15); F3(l, r, 14); F2(r, l, 13); F1(l, r, 12); } F3(r, l, 11); F2(l, r, 10); F1(r, l, 9); F3(l, r, 8); F2(r, l, 7); F1(l, r, 6); F3(r, l, 5); F2(l, r, 4); F1(r, l, 3); F3(l, r, 2); F2(r, l, 1); F1(l, r, 0); /* Put l,r into outblock */ outblock[0] = U8a(l); outblock[1] = U8b(l); outblock[2] = U8c(l); outblock[3] = U8d(l); outblock[4] = U8a(r); outblock[5] = U8b(r); outblock[6] = U8c(r); outblock[7] = U8d(r); /* Wipe clean */ t = l = r = 0; } /***** Key Schedual *****/ void cast_setkey(cast_key* key, u_int8_t* rawkey, int keybytes) { u_int32_t t[4], z[4], x[4]; int i; /* Set number of rounds to 12 or 16, depending on key length */ key->rounds = (keybytes <= 10 ? 12 : 16); /* Copy key to workspace x */ for (i = 0; i < 4; i++) { x[i] = 0; if ((i*4+0) < keybytes) x[i] = (u_int32_t)rawkey[i*4+0] << 24; if ((i*4+1) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+1] << 16; if ((i*4+2) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+2] << 8; if ((i*4+3) < keybytes) x[i] |= (u_int32_t)rawkey[i*4+3]; } /* Generate 32 subkeys, four at a time */ for (i = 0; i < 32; i+=4) { switch (i & 4) { case 0: t[0] = z[0] = x[0] ^ cast_sbox5[U8b(x[3])] ^ cast_sbox6[U8d(x[3])] ^ cast_sbox7[U8a(x[3])] ^ cast_sbox8[U8c(x[3])] ^ cast_sbox7[U8a(x[2])]; t[1] = z[1] = x[2] ^ cast_sbox5[U8a(z[0])] ^ cast_sbox6[U8c(z[0])] ^ cast_sbox7[U8b(z[0])] ^ cast_sbox8[U8d(z[0])] ^ cast_sbox8[U8c(x[2])]; t[2] = z[2] = x[3] ^ cast_sbox5[U8d(z[1])] ^ cast_sbox6[U8c(z[1])] ^ cast_sbox7[U8b(z[1])] ^ cast_sbox8[U8a(z[1])] ^ cast_sbox5[U8b(x[2])]; t[3] = z[3] = x[1] ^ cast_sbox5[U8c(z[2])] ^ cast_sbox6[U8b(z[2])] ^ cast_sbox7[U8d(z[2])] ^ cast_sbox8[U8a(z[2])] ^ cast_sbox6[U8d(x[2])]; break; case 4: t[0] = x[0] = z[2] ^ cast_sbox5[U8b(z[1])] ^ cast_sbox6[U8d(z[1])] ^ cast_sbox7[U8a(z[1])] ^ cast_sbox8[U8c(z[1])] ^ cast_sbox7[U8a(z[0])]; t[1] = x[1] = z[0] ^ cast_sbox5[U8a(x[0])] ^ cast_sbox6[U8c(x[0])] ^ cast_sbox7[U8b(x[0])] ^ cast_sbox8[U8d(x[0])] ^ cast_sbox8[U8c(z[0])]; t[2] = x[2] = z[1] ^ cast_sbox5[U8d(x[1])] ^ cast_sbox6[U8c(x[1])] ^ cast_sbox7[U8b(x[1])] ^ cast_sbox8[U8a(x[1])] ^ cast_sbox5[U8b(z[0])]; t[3] = x[3] = z[3] ^ cast_sbox5[U8c(x[2])] ^ cast_sbox6[U8b(x[2])] ^ cast_sbox7[U8d(x[2])] ^ cast_sbox8[U8a(x[2])] ^ cast_sbox6[U8d(z[0])]; break; } switch (i & 12) { case 0: case 12: key->xkey[i+0] = cast_sbox5[U8a(t[2])] ^ cast_sbox6[U8b(t[2])] ^ cast_sbox7[U8d(t[1])] ^ cast_sbox8[U8c(t[1])]; key->xkey[i+1] = cast_sbox5[U8c(t[2])] ^ cast_sbox6[U8d(t[2])] ^ cast_sbox7[U8b(t[1])] ^ cast_sbox8[U8a(t[1])]; key->xkey[i+2] = cast_sbox5[U8a(t[3])] ^ cast_sbox6[U8b(t[3])] ^ cast_sbox7[U8d(t[0])] ^ cast_sbox8[U8c(t[0])]; key->xkey[i+3] = cast_sbox5[U8c(t[3])] ^ cast_sbox6[U8d(t[3])] ^ cast_sbox7[U8b(t[0])] ^ cast_sbox8[U8a(t[0])]; break; case 4: case 8: key->xkey[i+0] = cast_sbox5[U8d(t[0])] ^ cast_sbox6[U8c(t[0])] ^ cast_sbox7[U8a(t[3])] ^ cast_sbox8[U8b(t[3])]; key->xkey[i+1] = cast_sbox5[U8b(t[0])] ^ cast_sbox6[U8a(t[0])] ^ cast_sbox7[U8c(t[3])] ^ cast_sbox8[U8d(t[3])]; key->xkey[i+2] = cast_sbox5[U8d(t[1])] ^ cast_sbox6[U8c(t[1])] ^ cast_sbox7[U8a(t[2])] ^ cast_sbox8[U8b(t[2])]; key->xkey[i+3] = cast_sbox5[U8b(t[1])] ^ cast_sbox6[U8a(t[1])] ^ cast_sbox7[U8c(t[2])] ^ cast_sbox8[U8d(t[2])]; break; } switch (i & 12) { case 0: key->xkey[i+0] ^= cast_sbox5[U8c(z[0])]; key->xkey[i+1] ^= cast_sbox6[U8c(z[1])]; key->xkey[i+2] ^= cast_sbox7[U8b(z[2])]; key->xkey[i+3] ^= cast_sbox8[U8a(z[3])]; break; case 4: key->xkey[i+0] ^= cast_sbox5[U8a(x[2])]; key->xkey[i+1] ^= cast_sbox6[U8b(x[3])]; key->xkey[i+2] ^= cast_sbox7[U8d(x[0])]; key->xkey[i+3] ^= cast_sbox8[U8d(x[1])]; break; case 8: key->xkey[i+0] ^= cast_sbox5[U8b(z[2])]; key->xkey[i+1] ^= cast_sbox6[U8a(z[3])]; key->xkey[i+2] ^= cast_sbox7[U8c(z[0])]; key->xkey[i+3] ^= cast_sbox8[U8c(z[1])]; break; case 12: key->xkey[i+0] ^= cast_sbox5[U8d(x[0])]; key->xkey[i+1] ^= cast_sbox6[U8d(x[1])]; key->xkey[i+2] ^= cast_sbox7[U8a(x[2])]; key->xkey[i+3] ^= cast_sbox8[U8b(x[3])]; break; } if (i >= 16) { key->xkey[i+0] &= 31; key->xkey[i+1] &= 31; key->xkey[i+2] &= 31; key->xkey[i+3] &= 31; } } /* Wipe clean */ for (i = 0; i < 4; i++) { t[i] = x[i] = z[i] = 0; } } /* Made in Canada */ isakmpd-20041012.orig/sysdep/common/libsysdep/blowfish.c0000644000175000017500000005446110133045740023345 0ustar jdivejdive00000000000000/* $OpenBSD: blowfish.c,v 1.4 2003/06/03 14:52:06 ho Exp $ */ /* * Blowfish block cipher for OpenBSD * Copyright 1997 Niels Provos * All rights reserved. * * Implementation advice by David Mazieres . * * 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. * * 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. */ /* * This code is derived from section 14.3 and the given source * in section V of Applied Cryptography, second edition. * Blowfish is an unpatented fast block cipher designed by * Bruce Schneier. */ #if 0 #include /* used for debugging */ #include #endif #include #include #undef inline #ifdef __GNUC__ #define inline __inline #else /* !__GNUC__ */ #define inline #endif /* !__GNUC__ */ /* Function for Feistel Networks */ #define F(bc, x) ((((bc)->S[0][((x) & 0xFF000000) >> 24] \ + (bc)->S[1][((x) &0xFF0000 ) >> 16]) \ ^ (bc)->S[2][((x) & 0xFF00) >> 8]) \ + (bc)->S[3][(x) & 0x00FF]) #define BLFRND(bc,i,j,n) (i ^= F(bc,j) ^ (bc)->P[n]) void Blowfish_encipher(c, xl, xr) blf_ctx *c; u_int32_t *xl; u_int32_t *xr; { u_int32_t Xl; u_int32_t Xr; Xl = *xl; Xr = *xr; Xl ^= c->P[0]; BLFRND(c, Xr, Xl, 1); BLFRND(c, Xl, Xr, 2); BLFRND(c, Xr, Xl, 3); BLFRND(c, Xl, Xr, 4); BLFRND(c, Xr, Xl, 5); BLFRND(c, Xl, Xr, 6); BLFRND(c, Xr, Xl, 7); BLFRND(c, Xl, Xr, 8); BLFRND(c, Xr, Xl, 9); BLFRND(c, Xl, Xr, 10); BLFRND(c, Xr, Xl, 11); BLFRND(c, Xl, Xr, 12); BLFRND(c, Xr, Xl, 13); BLFRND(c, Xl, Xr, 14); BLFRND(c, Xr, Xl, 15); BLFRND(c, Xl, Xr, 16); *xl = Xr ^ c->P[17]; *xr = Xl; } void Blowfish_decipher(c, xl, xr) blf_ctx *c; u_int32_t *xl; u_int32_t *xr; { u_int32_t Xl; u_int32_t Xr; Xl = *xl; Xr = *xr; Xl ^= c->P[17]; BLFRND(c, Xr, Xl, 16); BLFRND(c, Xl, Xr, 15); BLFRND(c, Xr, Xl, 14); BLFRND(c, Xl, Xr, 13); BLFRND(c, Xr, Xl, 12); BLFRND(c, Xl, Xr, 11); BLFRND(c, Xr, Xl, 10); BLFRND(c, Xl, Xr, 9); BLFRND(c, Xr, Xl, 8); BLFRND(c, Xl, Xr, 7); BLFRND(c, Xr, Xl, 6); BLFRND(c, Xl, Xr, 5); BLFRND(c, Xr, Xl, 4); BLFRND(c, Xl, Xr, 3); BLFRND(c, Xr, Xl, 2); BLFRND(c, Xl, Xr, 1); *xl = Xr ^ c->P[0]; *xr = Xl; } void Blowfish_initstate(c) blf_ctx *c; { /* P-box and S-box tables initialized with digits of Pi */ const blf_ctx initstate = { { { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a}, { 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7}, { 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0}, { 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6} }, { 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b } }; *c = initstate; } u_int32_t Blowfish_stream2word(const u_int8_t *data, u_int16_t databytes, u_int16_t *current) { u_int8_t i; u_int16_t j; u_int32_t temp; temp = 0x00000000; j = *current; for (i = 0; i < 4; i++, j++) { if (j >= databytes) j = 0; temp = (temp << 8) | data[j]; } *current = j; return temp; } void Blowfish_expand0state(blf_ctx *c, const u_int8_t *key, u_int16_t keybytes) { u_int16_t i; u_int16_t j; u_int16_t k; u_int32_t temp; u_int32_t datal; u_int32_t datar; j = 0; for (i = 0; i < BLF_N + 2; i++) { /* Extract 4 int8 to 1 int32 from keystream */ temp = Blowfish_stream2word(key, keybytes, &j); c->P[i] = c->P[i] ^ temp; } j = 0; datal = 0x00000000; datar = 0x00000000; for (i = 0; i < BLF_N + 2; i += 2) { Blowfish_encipher(c, &datal, &datar); c->P[i] = datal; c->P[i + 1] = datar; } for (i = 0; i < 4; i++) { for (k = 0; k < 256; k += 2) { Blowfish_encipher(c, &datal, &datar); c->S[i][k] = datal; c->S[i][k + 1] = datar; } } } void Blowfish_expandstate(blf_ctx *c, const u_int8_t *data, u_int16_t databytes, const u_int8_t *key, u_int16_t keybytes) { u_int16_t i; u_int16_t j; u_int16_t k; u_int32_t temp; u_int32_t datal; u_int32_t datar; j = 0; for (i = 0; i < BLF_N + 2; i++) { /* Extract 4 int8 to 1 int32 from keystream */ temp = Blowfish_stream2word(key, keybytes, &j); c->P[i] = c->P[i] ^ temp; } j = 0; datal = 0x00000000; datar = 0x00000000; for (i = 0; i < BLF_N + 2; i += 2) { datal ^= Blowfish_stream2word(data, databytes, &j); datar ^= Blowfish_stream2word(data, databytes, &j); Blowfish_encipher(c, &datal, &datar); c->P[i] = datal; c->P[i + 1] = datar; } for (i = 0; i < 4; i++) { for (k = 0; k < 256; k += 2) { datal ^= Blowfish_stream2word(data, databytes, &j); datar ^= Blowfish_stream2word(data, databytes, &j); Blowfish_encipher(c, &datal, &datar); c->S[i][k] = datal; c->S[i][k + 1] = datar; } } } void blf_key(blf_ctx *c, const u_int8_t *k, u_int16_t len) { /* Initialize S-boxes and subkeys with Pi */ Blowfish_initstate(c); /* Transform S-boxes and subkeys with key */ Blowfish_expand0state(c, k, len); } void blf_enc(blf_ctx *c, u_int32_t *data, u_int16_t blocks) { u_int32_t *d; u_int16_t i; d = data; for (i = 0; i < blocks; i++) { Blowfish_encipher(c, d, d + 1); d += 2; } } void blf_dec(blf_ctx *c, u_int32_t *data, u_int16_t blocks) { u_int32_t *d; u_int16_t i; d = data; for (i = 0; i < blocks; i++) { Blowfish_decipher(c, d, d + 1); d += 2; } } void blf_ecb_encrypt(blf_ctx *c, u_int8_t *data, u_int32_t len) { u_int32_t l, r; u_int32_t i; for (i = 0; i < len; i += 8) { l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_encipher(c, &l, &r); data[0] = l >> 24 & 0xff; data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; data[4] = r >> 24 & 0xff; data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; data += 8; } } void blf_ecb_decrypt(blf_ctx *c, u_int8_t *data, u_int32_t len) { u_int32_t l, r; u_int32_t i; for (i = 0; i < len; i += 8) { l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_decipher(c, &l, &r); data[0] = l >> 24 & 0xff; data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; data[4] = r >> 24 & 0xff; data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; data += 8; } } void blf_cbc_encrypt(blf_ctx *c, u_int8_t *iv, u_int8_t *data, u_int32_t len) { u_int32_t l, r; u_int32_t i, j; for (i = 0; i < len; i += 8) { for (j = 0; j < 8; j++) data[j] ^= iv[j]; l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_encipher(c, &l, &r); data[0] = l >> 24 & 0xff; data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; data[4] = r >> 24 & 0xff; data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; iv = data; data += 8; } } void blf_cbc_decrypt(blf_ctx *c, u_int8_t *iva, u_int8_t *data, u_int32_t len) { u_int32_t l, r; u_int8_t *iv; u_int32_t i, j; iv = data + len - 16; data = data + len - 8; for (i = len - 8; i >= 8; i -= 8) { l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_decipher(c, &l, &r); data[0] = l >> 24 & 0xff; data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; data[4] = r >> 24 & 0xff; data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; for (j = 0; j < 8; j++) data[j] ^= iv[j]; iv -= 8; data -= 8; } l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; Blowfish_decipher(c, &l, &r); data[0] = l >> 24 & 0xff; data[1] = l >> 16 & 0xff; data[2] = l >> 8 & 0xff; data[3] = l & 0xff; data[4] = r >> 24 & 0xff; data[5] = r >> 16 & 0xff; data[6] = r >> 8 & 0xff; data[7] = r & 0xff; for (j = 0; j < 8; j++) data[j] ^= iva[j]; } #if 0 void report(u_int32_t data[], u_int16_t len) { u_int16_t i; for (i = 0; i < len; i += 2) printf("Block %0hd: %08lx %08lx.\n", i / 2, data[i], data[i + 1]); } void main(void) { blf_ctx c; char key[] = "AAAAA"; char key2[] = "abcdefghijklmnopqrstuvwxyz"; u_int32_t data[10]; u_int32_t data2[] = {0x424c4f57l, 0x46495348l}; u_int16_t i; /* First test */ for (i = 0; i < 10; i++) data[i] = i; blf_key(&c, (u_int8_t *) key, 5); blf_enc(&c, data, 5); blf_dec(&c, data, 1); blf_dec(&c, data + 2, 4); printf("Should read as 0 - 9.\n"); report(data, 10); /* Second test */ blf_key(&c, (u_int8_t *) key2, strlen(key2)); blf_enc(&c, data2, 1); printf("\nShould read as: 0x324ed0fe 0xf413a203.\n"); report(data2, 2); blf_dec(&c, data2, 1); report(data2, 2); } #endif isakmpd-20041012.orig/sysdep/common/libsysdep/sha1.c0000644000175000017500000001367710133045740022370 0ustar jdivejdive00000000000000/* $OpenBSD: sha1.c,v 1.2 2001/01/28 22:38:48 niklas Exp $ */ /* SHA-1 in C By Steve Reid 100% Public Domain Test Vectors (from FIPS PUB 180-1) "abc" A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 A million repetitions of "a" 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */ /* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ /* #define SHA1HANDSOFF * Copies data before messing with it. */ #define SHA1HANDSOFF #include #include "sha1.h" #ifndef WIN32 #include "endian.h" /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */ #endif #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ /* I got the idea of expanding during the round function from SSLeay */ #if BYTE_ORDER == LITTLE_ENDIAN #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ |(rol(block->l[i],8)&0x00FF00FF)) #elif BYTE_ORDER == BIG_ENDIAN #define blk0(i) block->l[i] #else #error "Endianness not defined!" #endif #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ ^block->l[(i+2)&15]^block->l[i&15],1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); /* Hash a single 512-bit block. This is the core of the algorithm. */ void SHA1Transform(unsigned long state[5], unsigned char buffer[64]) { unsigned long a, b, c, d, e; typedef union { unsigned char c[64]; unsigned long l[16]; } CHAR64LONG16; CHAR64LONG16* block; #ifdef SHA1HANDSOFF static CHAR64LONG16 workspace; block = &workspace; memcpy(block, buffer, 64); #else block = (CHAR64LONG16*)buffer; #endif /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; } /* SHA1Init - Initialize new context */ void SHA1Init(SHA1_CTX* context) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = context->count[1] = 0; } /* Run your data through this. */ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) { unsigned int i; unsigned long j; j = context->count[0]; if ((context->count[0] += len << 3) < j) context->count[1] += (len>>29)+1; j = (j >> 3) & 63; if ((j + len) > 63) { memcpy(&context->buffer[j], data, (i = 64-j)); SHA1Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { SHA1Transform(context->state, &data[i]); } j = 0; } else i = 0; memcpy(&context->buffer[j], &data[i], len - i); } /* Add padding and return the message digest. */ void SHA1Final(unsigned char digest[20], SHA1_CTX* context) { unsigned long i, j; unsigned char finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } SHA1Update(context, (unsigned char *)"\200", 1); while ((context->count[0] & 504) != 448) { SHA1Update(context, (unsigned char *)"\0", 1); } SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ for (i = 0; i < 20; i++) { digest[i] = (unsigned char) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } /* Wipe variables */ i = j = 0; memset(context->buffer, '\0', 64); memset(context->state, '\0', 20); memset(context->count, '\0', 8); memset(&finalcount, '\0', 8); #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ SHA1Transform(context->state, context->buffer); #endif } isakmpd-20041012.orig/sysdep/common/libsysdep/CVS/0000755000175000017500000000000010133045751022007 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/common/libsysdep/strlcpy.c0000644000175000017500000000336410133045740023224 0ustar jdivejdive00000000000000/* $OpenBSD: strlcpy.c,v 1.3 2003/06/17 21:56:24 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcpy.c,v 1.3 2003/06/17 21:56:24 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(dst, src, siz) char *dst; const char *src; size_t siz; { register char *d = dst; register const char *s = src; register size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } isakmpd-20041012.orig/sysdep/common/libsysdep/md5.c0000644000175000017500000002637710133045740022222 0ustar jdivejdive00000000000000/* $OpenBSD: md5.c,v 1.3 2002/06/14 21:34:58 todd Exp $ */ /* * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic * changes to accommodate it in the kernel by ji. */ /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ /* * Additions by JI * * HAVEMEMCOPY is defined if mem* routines are available * * HAVEHTON is defined if htons() and htonl() can be used * for big/little endian conversions * */ #include #include #include "md5.h" #ifndef WIN32 #include "endian.h" /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */ #endif #define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */ /* Constants for MD5Transform routine. */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 #define MD5Transform _MD5Transform static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); #if BYTE_ORDER == LITTLE_ENDIAN #define Encode MD5_memcpy #define Decode MD5_memcpy #else static void Encode PROTO_LIST ((unsigned char *, UINT4 *, unsigned int)); static void Decode PROTO_LIST ((UINT4 *, unsigned char *, unsigned int)); #endif #ifdef HAVEMEMCOPY #include #define MD5_memcpy memcpy #define MD5_memset memset #else #ifdef HAVEBCOPY #define MD5_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c)) #define MD5_memset(_a,_b,_c) memset((_a), '\0',(_c)) #else static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); #endif #endif static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* F, G, H and I are basic MD5 functions. */ #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | (~z))) /* ROTATE_LEFT rotates x left n bits. */ #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent recomputation. */ #define FF(a, b, c, d, x, s, ac) { \ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define GG(a, b, c, d, x, s, ac) { \ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define HH(a, b, c, d, x, s, ac) { \ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define II(a, b, c, d, x, s, ac) { \ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } /* MD5 initialization. Begins an MD5 operation, writing a new context. */ void MD5Init (context) MD5_CTX *context; /* context */ { context->count[0] = context->count[1] = 0; /* Load magic initialization constants. */ context->state[0] = 0x67452301; context->state[1] = 0xefcdab89; context->state[2] = 0x98badcfe; context->state[3] = 0x10325476; } /* MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context. */ void MD5Update (context, input, inputLen) MD5_CTX *context; /* context */ unsigned char *input; /* input block */ unsigned int inputLen; /* length of input block */ { unsigned int i, index, partLen; /* Compute number of bytes mod 64 */ index = (unsigned int)((context->count[0] >> 3) & 0x3F); /* Update number of bits */ if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3)) context->count[1]++; context->count[1] += ((UINT4)inputLen >> 29); partLen = 64 - index; /* Transform as many times as possible. */ if (inputLen >= partLen) { MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen); MD5Transform (context->state, context->buffer); for (i = partLen; i + 63 < inputLen; i += 64) MD5Transform (context->state, &input[i]); index = 0; } else i = 0; /* Buffer remaining input */ MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i); } /* MD5 finalization. Ends an MD5 message-digest operation, writing the the message digest and zeroizing the context. */ void MD5Final (digest, context) unsigned char digest[16]; /* message digest */ MD5_CTX *context; /* context */ { unsigned char bits[8]; unsigned int index, padLen; /* Save number of bits */ Encode (bits, context->count, 8); /* Pad out to 56 mod 64. */ index = (unsigned int)((context->count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); MD5Update (context, PADDING, padLen); /* Append length (before padding) */ MD5Update (context, bits, 8); if (digest != NULL) /* Bill Simpson's padding */ { /* store state in digest */ Encode (digest, context->state, 16); /* Zeroize sensitive information. */ MD5_memset ((POINTER)context, 0, sizeof (*context)); } } /* MD5 basic transformation. Transforms state based on block. */ static void MD5Transform (state, block) UINT4 state[4]; unsigned char block[64]; { UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; Decode (x, block, 64); /* Round 1 */ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; /* Zeroize sensitive information. */ MD5_memset ((POINTER)x, 0, sizeof (x)); } #if BYTE_ORDER != LITTLE_ENDIAN /* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */ static void Encode (output, input, len) unsigned char *output; UINT4 *input; unsigned int len; { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (unsigned char)(input[i] & 0xff); output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); } } /* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */ static void Decode (output, input, len) UINT4 *output; unsigned char *input; unsigned int len; { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); } #endif #ifndef HAVEMEMCOPY #ifndef HAVEBCOPY /* Note: Replace "for loop" with standard memcpy if possible. */ static void MD5_memcpy (output, input, len) POINTER output; POINTER input; unsigned int len; { unsigned int i; for (i = 0; i < len; i++) output[i] = input[i]; } /* Note: Replace "for loop" with standard memset if possible. */ static void MD5_memset (output, value, len) POINTER output; int value; unsigned int len; { unsigned int i; for (i = 0; i < len; i++) ((char *)output)[i] = (char)value; } #endif #endif isakmpd-20041012.orig/sysdep/common/cast.h0000644000175000017500000000114610133045740020461 0ustar jdivejdive00000000000000/* $OpenBSD: cast.h,v 1.1 2001/01/26 11:34:00 niklas Exp $ */ /* * CAST-128 in C * Written by Steve Reid * 100% Public Domain - no warranty * Released 1997.10.11 */ #ifndef _CAST_H_ #define _CAST_H_ typedef struct { u_int32_t xkey[32]; /* Key, after expansion */ int rounds; /* Number of rounds to use, 12 or 16 */ } cast_key; void cast_setkey(cast_key* key, u_int8_t* rawkey, int keybytes); void cast_encrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock); void cast_decrypt(cast_key* key, u_int8_t* inblock, u_int8_t* outblock); #endif /* ifndef _CAST_H_ */ isakmpd-20041012.orig/sysdep/common/sha1.h0000644000175000017500000000075110133045740020364 0ustar jdivejdive00000000000000/* $OpenBSD: sha1.h,v 1.2 2001/01/28 22:38:47 niklas Exp $ */ /* SHA-1 in C By Steve Reid 100% Public Domain */ typedef struct { unsigned long state[5]; unsigned long count[2]; unsigned char buffer[64]; } SHA1_CTX; void SHA1Transform(unsigned long state[5], unsigned char buffer[64]); void SHA1Init(SHA1_CTX* context); void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len); void SHA1Final(unsigned char digest[20], SHA1_CTX* context); isakmpd-20041012.orig/sysdep/common/CVS/0000755000175000017500000000000010133045751020011 5ustar jdivejdive00000000000000isakmpd-20041012.orig/sysdep/common/blf.h0000644000175000017500000000530310133045740020271 0ustar jdivejdive00000000000000/* $OpenBSD: blf.h,v 1.5 2003/06/03 14:52:06 ho Exp $ */ /* * Blowfish - a fast block cipher designed by Bruce Schneier * * Copyright 1997 Niels Provos * 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. * * 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. */ #ifndef _BLF_H_ #define _BLF_H_ /* Schneier states the maximum key length to be 56 bytes. * The way how the subkeys are initialized by the key up * to (N+2)*4 i.e. 72 bytes are utilized. * Warning: For normal blowfish encryption only 56 bytes * of the key affect all cipherbits. */ #define BLF_N 16 /* Number of Subkeys */ #define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */ /* Blowfish context */ typedef struct BlowfishContext { u_int32_t S[4][256]; /* S-Boxes */ u_int32_t P[BLF_N + 2]; /* Subkeys */ } blf_ctx; /* Raw access to customized Blowfish * blf_key is just: * Blowfish_initstate( state ) * Blowfish_expand0state( state, key, keylen ) */ void Blowfish_encipher(blf_ctx *, u_int32_t *, u_int32_t *); void Blowfish_decipher(blf_ctx *, u_int32_t *, u_int32_t *); void Blowfish_initstate(blf_ctx *); void Blowfish_expand0state(blf_ctx *, const u_int8_t *, u_int16_t); void Blowfish_expandstate (blf_ctx *, const u_int8_t *, u_int16_t, const u_int8_t *, u_int16_t); /* Standard Blowfish */ void blf_key(blf_ctx *, const u_int8_t *, u_int16_t); void blf_enc(blf_ctx *, u_int32_t *, u_int16_t); void blf_dec(blf_ctx *, u_int32_t *, u_int16_t); /* Converts u_int8_t to u_int32_t */ u_int32_t Blowfish_stream2word(const u_int8_t *, u_int16_t , u_int16_t *); #endif isakmpd-20041012.orig/sysdep/common/md5.h0000644000175000017500000000426410133045740020220 0ustar jdivejdive00000000000000/* $OpenBSD: md5.h,v 1.2 2001/01/28 22:38:47 niklas Exp $ */ /* GLOBAL.H - RSAREF types and constants */ /* PROTOTYPES should be set to one if and only if the compiler supports function argument prototyping. The following makes PROTOTYPES default to 0 if it has not already been defined with C compiler flags. */ #ifndef PROTOTYPES #define PROTOTYPES 1 #endif /* POINTER defines a generic pointer type */ typedef unsigned char *POINTER; /* UINT2 defines a two byte word */ typedef unsigned short int UINT2; /* UINT4 defines a four byte word */ typedef unsigned long int UINT4; /* PROTO_LIST is defined depending on how PROTOTYPES is defined above. If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it returns an empty list. */ #if PROTOTYPES #define PROTO_LIST(list) list #else #define PROTO_LIST(list) () #endif /* MD5.H - header file for MD5C.C */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ /* MD5 context. */ typedef struct { UINT4 state[4]; /* state (ABCD) */ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ unsigned char buffer[64]; /* input buffer */ } MD5_CTX; void MD5Init PROTO_LIST ((MD5_CTX *)); void MD5Update PROTO_LIST ((MD5_CTX *, unsigned char *, unsigned int)); void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); #define _MD5_H_ isakmpd-20041012.orig/sysdep/CVS/0000755000175000017500000000000010133045751016521 5ustar jdivejdive00000000000000