diff options
Diffstat (limited to 'src/pluto')
110 files changed, 0 insertions, 56318 deletions
diff --git a/src/pluto/Android.mk b/src/pluto/Android.mk deleted file mode 100644 index 618f79c42..000000000 --- a/src/pluto/Android.mk +++ /dev/null @@ -1,80 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -# copy-n-paste from Makefile.am -LOCAL_SRC_FILES := \ -ac.c ac.h \ -alg_info.c alg_info.h \ -ca.c ca.h \ -certs.c certs.h \ -connections.c connections.h \ -constants.c constants.h \ -cookie.c cookie.h \ -crl.c crl.h \ -crypto.c crypto.h \ -db_ops.c db_ops.h \ -defs.c defs.h \ -demux.c demux.h \ -event_queue.c event_queue.h \ -fetch.c fetch.h \ -foodgroups.c foodgroups.h \ -ike_alg.c ike_alg.h \ -ipsec_doi.c ipsec_doi.h \ -kameipsec.h \ -kernel.c kernel.h \ -kernel_alg.c kernel_alg.h \ -kernel_pfkey.c kernel_pfkey.h \ -keys.c keys.h \ -lex.c lex.h \ -log.c log.h \ -myid.c myid.h \ -modecfg.c modecfg.h \ -nat_traversal.c nat_traversal.h \ -ocsp.c ocsp.h \ -packet.c packet.h \ -pkcs7.c pkcs7.h \ -plugin_list.c plugin_list.h \ -pluto.c pluto.h \ -plutomain.c \ -rcv_whack.c rcv_whack.h \ -server.c server.h \ -smartcard.c smartcard.h \ -spdb.c spdb.h \ -state.c state.h \ -timer.c timer.h \ -vendor.c vendor.h \ -virtual.c virtual.h \ -whack_attribute.c whack_attribute.h \ -xauth/xauth_manager.c xauth/xauth_manager.h \ -xauth/xauth_provider.h xauth/xauth_verifier.h \ -x509.c x509.h \ -builder.c builder.h \ -rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h - -LOCAL_SRC_FILES += $(call add_plugin, xauth) - -# build pluto ------------------------------------------------------------------ - -LOCAL_C_INCLUDES += \ - $(libvstr_PATH) \ - $(strongswan_PATH)/src/libhydra \ - $(strongswan_PATH)/src/libstrongswan \ - $(strongswan_PATH)/src/libfreeswan \ - $(strongswan_PATH)/src/whack - -LOCAL_CFLAGS := $(strongswan_CFLAGS) \ - -DPLUTO -DVENDORID -DXAUTH_VID -DCISCO_QUIRKS \ - -DTHREADS -DKERNEL26_HAS_KAME_DUPLICATES \ - -DPLUGINS='"$(strongswan_PLUTO_PLUGINS)"' - -LOCAL_MODULE := pluto - -LOCAL_MODULE_TAGS := optional - -LOCAL_ARM_MODE := arm - -LOCAL_PRELINK_MODULE := false - -LOCAL_SHARED_LIBRARIES += libstrongswan libhydra libfreeswan libcutils - -include $(BUILD_EXECUTABLE) diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am deleted file mode 100644 index 3fd0e039c..000000000 --- a/src/pluto/Makefile.am +++ /dev/null @@ -1,155 +0,0 @@ -# Makefile.am was ported from the old Makefile the most -# painless way. Only the most important options are included, -# further work may be necessary here... - -ipsec_PROGRAMS = pluto - -if USE_ADNS -ipsec_PROGRAMS += _pluto_adns -endif - -pluto_SOURCES = \ -ac.c ac.h \ -alg_info.c alg_info.h \ -ca.c ca.h \ -certs.c certs.h \ -connections.c connections.h \ -constants.c constants.h \ -cookie.c cookie.h \ -crl.c crl.h \ -crypto.c crypto.h \ -db_ops.c db_ops.h \ -defs.c defs.h \ -demux.c demux.h \ -event_queue.c event_queue.h \ -fetch.c fetch.h \ -foodgroups.c foodgroups.h \ -ike_alg.c ike_alg.h \ -ipsec_doi.c ipsec_doi.h \ -kameipsec.h \ -kernel.c kernel.h \ -kernel_alg.c kernel_alg.h \ -kernel_pfkey.c kernel_pfkey.h \ -keys.c keys.h \ -lex.c lex.h \ -log.c log.h \ -myid.c myid.h \ -modecfg.c modecfg.h \ -nat_traversal.c nat_traversal.h \ -ocsp.c ocsp.h \ -packet.c packet.h \ -pkcs7.c pkcs7.h \ -plugin_list.c plugin_list.h \ -pluto.c pluto.h \ -plutomain.c \ -rcv_whack.c rcv_whack.h \ -server.c server.h \ -smartcard.c smartcard.h \ -spdb.c spdb.h \ -state.c state.h \ -timer.c timer.h \ -vendor.c vendor.h \ -virtual.c virtual.h \ -whack_attribute.c whack_attribute.h \ -xauth/xauth_manager.c xauth/xauth_manager.h \ -xauth/xauth_provider.h xauth/xauth_verifier.h \ -x509.c x509.h \ -builder.c builder.h \ -rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h - -if USE_ADNS -pluto_SOURCES += \ -dnskey.c dnskey.h - -_pluto_adns_SOURCES = \ -adns.c adns.h -endif - -plutomain.o : $(top_builddir)/config.status - -LIBSTRONGSWANDIR=$(top_builddir)/src/libstrongswan -LIBFREESWANDIR=$(top_builddir)/src/libfreeswan -LIBHYDRADIR=$(top_builddir)/src/libhydra - -INCLUDES = \ --I${linux_headers} \ --I$(top_srcdir)/src/libstrongswan \ --I$(top_srcdir)/src/libfreeswan \ --I$(top_srcdir)/src/libhydra \ --I$(top_srcdir)/src/whack - -AM_CFLAGS = -rdynamic \ --DIPSEC_DIR=\"${ipsecdir}\" \ --DIPSEC_CONFDIR=\"${sysconfdir}\" \ --DIPSEC_PIDDIR=\"${piddir}\" \ --DSHARED_SECRETS_FILE=\"${sysconfdir}/ipsec.secrets\" \ --DPLUGINS=\""${pluto_plugins}\"" \ --DPKCS11_DEFAULT_LIB=\"${default_pkcs11}\" \ --DKERNEL26_HAS_KAME_DUPLICATES \ --DPLUTO -DDEBUG - -pluto_LDADD = \ -$(LIBSTRONGSWANDIR)/libstrongswan.la \ -$(LIBFREESWANDIR)/libfreeswan.a \ -$(LIBHYDRADIR)/libhydra.la \ --lresolv $(PTHREADLIB) $(DLLIB) - -if USE_ADNS -_pluto_adns_LDADD = \ -$(LIBFREESWANDIR)/libfreeswan.a \ --lresolv $(DLLIB) -endif - -dist_man_MANS = pluto.8 - -EXTRA_DIST = Android.mk - -# compile options -################# - -# This compile option activates the sending of a strongSwan VID -if USE_VENDORID - AM_CFLAGS += -DVENDORID -endif - -# This compile option activates the sending of the XAUTH VID -if USE_XAUTH_VID - AM_CFLAGS += -DXAUTH_VID -endif - -# This compile option activates the support of the Cisco VPN client -if USE_CISCO_QUIRKS - AM_CFLAGS += -DCISCO_QUIRKS -endif - -# This compile option activates NAT traversal with IPSec transport mode -if USE_NAT_TRANSPORT - AM_CFLAGS += -DI_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT -endif - -# This compile option activates smartcard support -if USE_SMARTCARD - AM_CFLAGS += -DSMARTCARD -endif - -if USE_LIBCAP - pluto_LDADD += -lcap -endif - -if USE_THREADS - AM_CFLAGS += -DTHREADS -endif - -if USE_ADNS - AM_CFLAGS += -DADNS -endif - -# build optional plugins -######################## - -SUBDIRS = . - -if USE_XAUTH - SUBDIRS += plugins/xauth -endif - diff --git a/src/pluto/Makefile.in b/src/pluto/Makefile.in deleted file mode 100644 index b055ba289..000000000 --- a/src/pluto/Makefile.in +++ /dev/null @@ -1,1001 +0,0 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# Makefile.am was ported from the old Makefile the most -# painless way. Only the most important options are included, -# further work may be necessary here... - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -ipsec_PROGRAMS = pluto$(EXEEXT) $(am__EXEEXT_1) -@USE_ADNS_TRUE@am__append_1 = _pluto_adns -@USE_ADNS_TRUE@am__append_2 = \ -@USE_ADNS_TRUE@dnskey.c dnskey.h - - -# compile options -################# - -# This compile option activates the sending of a strongSwan VID -@USE_VENDORID_TRUE@am__append_3 = -DVENDORID - -# This compile option activates the sending of the XAUTH VID -@USE_XAUTH_VID_TRUE@am__append_4 = -DXAUTH_VID - -# This compile option activates the support of the Cisco VPN client -@USE_CISCO_QUIRKS_TRUE@am__append_5 = -DCISCO_QUIRKS - -# This compile option activates NAT traversal with IPSec transport mode -@USE_NAT_TRANSPORT_TRUE@am__append_6 = -DI_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT - -# This compile option activates smartcard support -@USE_SMARTCARD_TRUE@am__append_7 = -DSMARTCARD -@USE_LIBCAP_TRUE@am__append_8 = -lcap -@USE_THREADS_TRUE@am__append_9 = -DTHREADS -@USE_ADNS_TRUE@am__append_10 = -DADNS -@USE_XAUTH_TRUE@am__append_11 = plugins/xauth -subdir = src/pluto -DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ - $(top_srcdir)/m4/config/ltoptions.m4 \ - $(top_srcdir)/m4/config/ltsugar.m4 \ - $(top_srcdir)/m4/config/ltversion.m4 \ - $(top_srcdir)/m4/config/lt~obsolete.m4 \ - $(top_srcdir)/m4/macros/with.m4 \ - $(top_srcdir)/m4/macros/enable-disable.m4 \ - $(top_srcdir)/m4/macros/add-plugin.m4 \ - $(top_srcdir)/configure.in -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -@USE_ADNS_TRUE@am__EXEEXT_1 = _pluto_adns$(EXEEXT) -am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)" -PROGRAMS = $(ipsec_PROGRAMS) -am___pluto_adns_SOURCES_DIST = adns.c adns.h -@USE_ADNS_TRUE@am__pluto_adns_OBJECTS = adns.$(OBJEXT) -_pluto_adns_OBJECTS = $(am__pluto_adns_OBJECTS) -am__DEPENDENCIES_1 = -@USE_ADNS_TRUE@_pluto_adns_DEPENDENCIES = \ -@USE_ADNS_TRUE@ $(LIBFREESWANDIR)/libfreeswan.a \ -@USE_ADNS_TRUE@ $(am__DEPENDENCIES_1) -am__pluto_SOURCES_DIST = ac.c ac.h alg_info.c alg_info.h ca.c ca.h \ - certs.c certs.h connections.c connections.h constants.c \ - constants.h cookie.c cookie.h crl.c crl.h crypto.c crypto.h \ - db_ops.c db_ops.h defs.c defs.h demux.c demux.h event_queue.c \ - event_queue.h fetch.c fetch.h foodgroups.c foodgroups.h \ - ike_alg.c ike_alg.h ipsec_doi.c ipsec_doi.h kameipsec.h \ - kernel.c kernel.h kernel_alg.c kernel_alg.h kernel_pfkey.c \ - kernel_pfkey.h keys.c keys.h lex.c lex.h log.c log.h myid.c \ - myid.h modecfg.c modecfg.h nat_traversal.c nat_traversal.h \ - ocsp.c ocsp.h packet.c packet.h pkcs7.c pkcs7.h plugin_list.c \ - plugin_list.h pluto.c pluto.h plutomain.c rcv_whack.c \ - rcv_whack.h server.c server.h smartcard.c smartcard.h spdb.c \ - spdb.h state.c state.h timer.c timer.h vendor.c vendor.h \ - virtual.c virtual.h whack_attribute.c whack_attribute.h \ - xauth/xauth_manager.c xauth/xauth_manager.h \ - xauth/xauth_provider.h xauth/xauth_verifier.h x509.c x509.h \ - builder.c builder.h rsaref/pkcs11t.h rsaref/pkcs11.h \ - rsaref/unix.h rsaref/pkcs11f.h dnskey.c dnskey.h -@USE_ADNS_TRUE@am__objects_1 = dnskey.$(OBJEXT) -am_pluto_OBJECTS = ac.$(OBJEXT) alg_info.$(OBJEXT) ca.$(OBJEXT) \ - certs.$(OBJEXT) connections.$(OBJEXT) constants.$(OBJEXT) \ - cookie.$(OBJEXT) crl.$(OBJEXT) crypto.$(OBJEXT) \ - db_ops.$(OBJEXT) defs.$(OBJEXT) demux.$(OBJEXT) \ - event_queue.$(OBJEXT) fetch.$(OBJEXT) foodgroups.$(OBJEXT) \ - ike_alg.$(OBJEXT) ipsec_doi.$(OBJEXT) kernel.$(OBJEXT) \ - kernel_alg.$(OBJEXT) kernel_pfkey.$(OBJEXT) keys.$(OBJEXT) \ - lex.$(OBJEXT) log.$(OBJEXT) myid.$(OBJEXT) modecfg.$(OBJEXT) \ - nat_traversal.$(OBJEXT) ocsp.$(OBJEXT) packet.$(OBJEXT) \ - pkcs7.$(OBJEXT) plugin_list.$(OBJEXT) pluto.$(OBJEXT) \ - plutomain.$(OBJEXT) rcv_whack.$(OBJEXT) server.$(OBJEXT) \ - smartcard.$(OBJEXT) spdb.$(OBJEXT) state.$(OBJEXT) \ - timer.$(OBJEXT) vendor.$(OBJEXT) virtual.$(OBJEXT) \ - whack_attribute.$(OBJEXT) xauth_manager.$(OBJEXT) \ - x509.$(OBJEXT) builder.$(OBJEXT) $(am__objects_1) -pluto_OBJECTS = $(am_pluto_OBJECTS) -pluto_DEPENDENCIES = $(LIBSTRONGSWANDIR)/libstrongswan.la \ - $(LIBFREESWANDIR)/libfreeswan.a $(LIBHYDRADIR)/libhydra.la \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ -SOURCES = $(_pluto_adns_SOURCES) $(pluto_SOURCES) -DIST_SOURCES = $(am___pluto_adns_SOURCES_DIST) \ - $(am__pluto_SOURCES_DIST) -RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ - html-recursive info-recursive install-data-recursive \ - install-dvi-recursive install-exec-recursive \ - install-html-recursive install-info-recursive \ - install-pdf-recursive install-ps-recursive install-recursive \ - installcheck-recursive installdirs-recursive pdf-recursive \ - ps-recursive uninstall-recursive -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -man8dir = $(mandir)/man8 -NROFF = nroff -MANS = $(dist_man_MANS) -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ - $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ - distdir -ETAGS = etags -CTAGS = ctags -DIST_SUBDIRS = . plugins/xauth -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -ACLOCAL = @ACLOCAL@ -ALLOCA = @ALLOCA@ -AMTAR = @AMTAR@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BTLIB = @BTLIB@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLIB = @DLLIB@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GPERF = @GPERF@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LEX = @LEX@ -LEXLIB = @LEXLIB@ -LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -MYSQLCFLAG = @MYSQLCFLAG@ -MYSQLCONFIG = @MYSQLCONFIG@ -MYSQLLIB = @MYSQLLIB@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PERL = @PERL@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PTHREADLIB = @PTHREADLIB@ -RANLIB = @RANLIB@ -RTLIB = @RTLIB@ -RUBY = @RUBY@ -RUBYINCLUDE = @RUBYINCLUDE@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -SOCKLIB = @SOCKLIB@ -STRIP = @STRIP@ -VERSION = @VERSION@ -YACC = @YACC@ -YFLAGS = @YFLAGS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -attest_plugins = @attest_plugins@ -axis2c_CFLAGS = @axis2c_CFLAGS@ -axis2c_LIBS = @axis2c_LIBS@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -c_plugins = @c_plugins@ -clearsilver_LIBS = @clearsilver_LIBS@ -datadir = @datadir@ -datarootdir = @datarootdir@ -dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -gtk_CFLAGS = @gtk_CFLAGS@ -gtk_LIBS = @gtk_LIBS@ -h_plugins = @h_plugins@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -imcvdir = @imcvdir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -ipsecdir = @ipsecdir@ -ipsecgroup = @ipsecgroup@ -ipseclibdir = @ipseclibdir@ -ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ -libdir = @libdir@ -libexecdir = @libexecdir@ -linux_headers = @linux_headers@ -localedir = @localedir@ -localstatedir = @localstatedir@ -lt_ECHO = @lt_ECHO@ -maemo_CFLAGS = @maemo_CFLAGS@ -maemo_LIBS = @maemo_LIBS@ -manager_plugins = @manager_plugins@ -mandir = @mandir@ -medsrv_plugins = @medsrv_plugins@ -mkdir_p = @mkdir_p@ -nm_CFLAGS = @nm_CFLAGS@ -nm_LIBS = @nm_LIBS@ -nm_ca_dir = @nm_ca_dir@ -oldincludedir = @oldincludedir@ -openac_plugins = @openac_plugins@ -p_plugins = @p_plugins@ -pcsclite_CFLAGS = @pcsclite_CFLAGS@ -pcsclite_LIBS = @pcsclite_LIBS@ -pdfdir = @pdfdir@ -piddir = @piddir@ -pki_plugins = @pki_plugins@ -plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ -pool_plugins = @pool_plugins@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -random_device = @random_device@ -resolv_conf = @resolv_conf@ -routing_table = @routing_table@ -routing_table_prio = @routing_table_prio@ -s_plugins = @s_plugins@ -sbindir = @sbindir@ -scepclient_plugins = @scepclient_plugins@ -scripts_plugins = @scripts_plugins@ -sharedstatedir = @sharedstatedir@ -soup_CFLAGS = @soup_CFLAGS@ -soup_LIBS = @soup_LIBS@ -srcdir = @srcdir@ -starter_plugins = @starter_plugins@ -strongswan_conf = @strongswan_conf@ -sysconfdir = @sysconfdir@ -systemdsystemunitdir = @systemdsystemunitdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -urandom_device = @urandom_device@ -xml_CFLAGS = @xml_CFLAGS@ -xml_LIBS = @xml_LIBS@ -pluto_SOURCES = ac.c ac.h alg_info.c alg_info.h ca.c ca.h certs.c \ - certs.h connections.c connections.h constants.c constants.h \ - cookie.c cookie.h crl.c crl.h crypto.c crypto.h db_ops.c \ - db_ops.h defs.c defs.h demux.c demux.h event_queue.c \ - event_queue.h fetch.c fetch.h foodgroups.c foodgroups.h \ - ike_alg.c ike_alg.h ipsec_doi.c ipsec_doi.h kameipsec.h \ - kernel.c kernel.h kernel_alg.c kernel_alg.h kernel_pfkey.c \ - kernel_pfkey.h keys.c keys.h lex.c lex.h log.c log.h myid.c \ - myid.h modecfg.c modecfg.h nat_traversal.c nat_traversal.h \ - ocsp.c ocsp.h packet.c packet.h pkcs7.c pkcs7.h plugin_list.c \ - plugin_list.h pluto.c pluto.h plutomain.c rcv_whack.c \ - rcv_whack.h server.c server.h smartcard.c smartcard.h spdb.c \ - spdb.h state.c state.h timer.c timer.h vendor.c vendor.h \ - virtual.c virtual.h whack_attribute.c whack_attribute.h \ - xauth/xauth_manager.c xauth/xauth_manager.h \ - xauth/xauth_provider.h xauth/xauth_verifier.h x509.c x509.h \ - builder.c builder.h rsaref/pkcs11t.h rsaref/pkcs11.h \ - rsaref/unix.h rsaref/pkcs11f.h $(am__append_2) -@USE_ADNS_TRUE@_pluto_adns_SOURCES = \ -@USE_ADNS_TRUE@adns.c adns.h - -LIBSTRONGSWANDIR = $(top_builddir)/src/libstrongswan -LIBFREESWANDIR = $(top_builddir)/src/libfreeswan -LIBHYDRADIR = $(top_builddir)/src/libhydra -INCLUDES = \ --I${linux_headers} \ --I$(top_srcdir)/src/libstrongswan \ --I$(top_srcdir)/src/libfreeswan \ --I$(top_srcdir)/src/libhydra \ --I$(top_srcdir)/src/whack - -AM_CFLAGS = -rdynamic -DIPSEC_DIR=\"${ipsecdir}\" \ - -DIPSEC_CONFDIR=\"${sysconfdir}\" -DIPSEC_PIDDIR=\"${piddir}\" \ - -DSHARED_SECRETS_FILE=\"${sysconfdir}/ipsec.secrets\" \ - -DPLUGINS=\""${pluto_plugins}\"" \ - -DPKCS11_DEFAULT_LIB=\"${default_pkcs11}\" \ - -DKERNEL26_HAS_KAME_DUPLICATES -DPLUTO -DDEBUG $(am__append_3) \ - $(am__append_4) $(am__append_5) $(am__append_6) \ - $(am__append_7) $(am__append_9) $(am__append_10) -pluto_LDADD = $(LIBSTRONGSWANDIR)/libstrongswan.la \ - $(LIBFREESWANDIR)/libfreeswan.a $(LIBHYDRADIR)/libhydra.la \ - -lresolv $(PTHREADLIB) $(DLLIB) $(am__append_8) -@USE_ADNS_TRUE@_pluto_adns_LDADD = \ -@USE_ADNS_TRUE@$(LIBFREESWANDIR)/libfreeswan.a \ -@USE_ADNS_TRUE@-lresolv $(DLLIB) - -dist_man_MANS = pluto.8 -EXTRA_DIST = Android.mk - -# build optional plugins -######################## -SUBDIRS = . $(am__append_11) -all: all-recursive - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pluto/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/pluto/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): -install-ipsecPROGRAMS: $(ipsec_PROGRAMS) - @$(NORMAL_INSTALL) - test -z "$(ipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" - @list='$(ipsec_PROGRAMS)'; test -n "$(ipsecdir)" || list=; \ - for p in $$list; do echo "$$p $$p"; done | \ - sed 's/$(EXEEXT)$$//' | \ - while read p p1; do if test -f $$p || test -f $$p1; \ - then echo "$$p"; echo "$$p"; else :; fi; \ - done | \ - sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ - -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ - sed 'N;N;N;s,\n, ,g' | \ - $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ - { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ - if ($$2 == $$4) files[d] = files[d] " " $$1; \ - else { print "f", $$3 "/" $$4, $$1; } } \ - END { for (d in files) print "f", d, files[d] }' | \ - while read type dir files; do \ - if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ - test -z "$$files" || { \ - echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(ipsecdir)$$dir'"; \ - $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(ipsecdir)$$dir" || exit $$?; \ - } \ - ; done - -uninstall-ipsecPROGRAMS: - @$(NORMAL_UNINSTALL) - @list='$(ipsec_PROGRAMS)'; test -n "$(ipsecdir)" || list=; \ - files=`for p in $$list; do echo "$$p"; done | \ - sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ - -e 's/$$/$(EXEEXT)/' `; \ - test -n "$$list" || exit 0; \ - echo " ( cd '$(DESTDIR)$(ipsecdir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(ipsecdir)" && rm -f $$files - -clean-ipsecPROGRAMS: - @list='$(ipsec_PROGRAMS)'; test -n "$$list" || exit 0; \ - echo " rm -f" $$list; \ - rm -f $$list || exit $$?; \ - test -n "$(EXEEXT)" || exit 0; \ - list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f" $$list; \ - rm -f $$list -_pluto_adns$(EXEEXT): $(_pluto_adns_OBJECTS) $(_pluto_adns_DEPENDENCIES) - @rm -f _pluto_adns$(EXEEXT) - $(LINK) $(_pluto_adns_OBJECTS) $(_pluto_adns_LDADD) $(LIBS) -pluto$(EXEEXT): $(pluto_OBJECTS) $(pluto_DEPENDENCIES) - @rm -f pluto$(EXEEXT) - $(LINK) $(pluto_OBJECTS) $(pluto_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adns.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alg_info.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/builder.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ca.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/certs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connections.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/constants.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cookie.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crl.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/db_ops.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/demux.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnskey.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event_queue.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fetch.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/foodgroups.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_doi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_alg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_pfkey.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keys.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lex.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modecfg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/myid.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nat_traversal.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocsp.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs7.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_list.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pluto.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plutomain.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcv_whack.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smartcard.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spdb.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/state.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vendor.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/virtual.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/whack_attribute.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_manager.Po@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< - -xauth_manager.o: xauth/xauth_manager.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xauth_manager.o -MD -MP -MF $(DEPDIR)/xauth_manager.Tpo -c -o xauth_manager.o `test -f 'xauth/xauth_manager.c' || echo '$(srcdir)/'`xauth/xauth_manager.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xauth_manager.Tpo $(DEPDIR)/xauth_manager.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xauth/xauth_manager.c' object='xauth_manager.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xauth_manager.o `test -f 'xauth/xauth_manager.c' || echo '$(srcdir)/'`xauth/xauth_manager.c - -xauth_manager.obj: xauth/xauth_manager.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xauth_manager.obj -MD -MP -MF $(DEPDIR)/xauth_manager.Tpo -c -o xauth_manager.obj `if test -f 'xauth/xauth_manager.c'; then $(CYGPATH_W) 'xauth/xauth_manager.c'; else $(CYGPATH_W) '$(srcdir)/xauth/xauth_manager.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xauth_manager.Tpo $(DEPDIR)/xauth_manager.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xauth/xauth_manager.c' object='xauth_manager.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xauth_manager.obj `if test -f 'xauth/xauth_manager.c'; then $(CYGPATH_W) 'xauth/xauth_manager.c'; else $(CYGPATH_W) '$(srcdir)/xauth/xauth_manager.c'; fi` - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-man8: $(dist_man_MANS) - @$(NORMAL_INSTALL) - test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" - @list=''; test -n "$(man8dir)" || exit 0; \ - { for i in $$list; do echo "$$i"; done; \ - l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ - sed -n '/\.8[a-z]*$$/p'; \ - } | while read p; do \ - if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; echo "$$p"; \ - done | \ - sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ - -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ - sed 'N;N;s,\n, ,g' | { \ - list=; while read file base inst; do \ - if test "$$base" = "$$inst"; then list="$$list $$file"; else \ - echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ - $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ - fi; \ - done; \ - for i in $$list; do echo "$$i"; done | $(am__base_list) | \ - while read files; do \ - test -z "$$files" || { \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ - done; } - -uninstall-man8: - @$(NORMAL_UNINSTALL) - @list=''; test -n "$(man8dir)" || exit 0; \ - files=`{ for i in $$list; do echo "$$i"; done; \ - l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ - sed -n '/\.8[a-z]*$$/p'; \ - } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ - -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ - test -z "$$files" || { \ - echo " ( cd '$(DESTDIR)$(man8dir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(man8dir)" && rm -f $$files; } - -# This directory's subdirectories are mostly independent; you can cd -# into them and run `make' without going through this Makefile. -# To change the values of `make' variables: instead of editing Makefiles, -# (1) if the variable is set in `config.status', edit `config.status' -# (which will cause the Makefiles to be regenerated when you run `make'); -# (2) otherwise, pass the desired values on the `make' command line. -$(RECURSIVE_TARGETS): - @fail= failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -$(RECURSIVE_CLEAN_TARGETS): - @fail= failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - rev=''; for subdir in $$list; do \ - if test "$$subdir" = "."; then :; else \ - rev="$$subdir $$rev"; \ - fi; \ - done; \ - rev="$$rev ."; \ - target=`echo $@ | sed s/-recursive//`; \ - for subdir in $$rev; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done && test -z "$$fail" -tags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ - done -ctags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ - done - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: CTAGS -CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @list='$(MANS)'; if test -n "$$list"; then \ - list=`for p in $$list; do \ - if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ - if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ - if test -n "$$list" && \ - grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ - echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ - grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ - echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ - echo " typically \`make maintainer-clean' will remove them" >&2; \ - exit 1; \ - else :; fi; \ - else :; fi - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-recursive -all-am: Makefile $(PROGRAMS) $(MANS) -installdirs: installdirs-recursive -installdirs-am: - for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-recursive - -clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \ - mostlyclean-am - -distclean: distclean-recursive - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: install-ipsecPROGRAMS install-man - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: install-man8 - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: uninstall-ipsecPROGRAMS uninstall-man - -uninstall-man: uninstall-man8 - -.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ - install-am install-strip tags-recursive - -.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ - all all-am check check-am clean clean-generic \ - clean-ipsecPROGRAMS clean-libtool ctags ctags-recursive \ - distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-ipsecPROGRAMS install-man install-man8 \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ - uninstall uninstall-am uninstall-ipsecPROGRAMS uninstall-man \ - uninstall-man8 - - -plutomain.o : $(top_builddir)/config.status - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/pluto/ac.c b/src/pluto/ac.c deleted file mode 100644 index cd8007aea..000000000 --- a/src/pluto/ac.c +++ /dev/null @@ -1,298 +0,0 @@ -/* Support of X.509 attribute certificates - * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2003 Martin Berner, Lukas Suter - * Copyright (C) 2009 Andreas Steffen - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <sys/stat.h> -#include <time.h> - -#include <debug.h> -#include <utils/enumerator.h> -#include <utils/linked_list.h> -#include <credentials/certificates/ac.h> - -#include "ac.h" -#include "ca.h" -#include "certs.h" -#include "fetch.h" -#include "log.h" - -/** - * Chained list of X.509 attribute certificates - */ -static linked_list_t *acerts = NULL; - -/** - * Initialize the linked list of attribute certificates - */ -void ac_initialize(void) -{ - acerts = linked_list_create(); -} - -/** - * Free the linked list of attribute certificates - */ -void ac_finalize(void) -{ - if (acerts) - { - acerts->destroy_offset(acerts, offsetof(certificate_t, destroy)); - } -} - -/** - * Get a X.509 attribute certificate for a given holder - */ -certificate_t* ac_get_cert(identification_t *issuer, chunk_t serial) -{ - enumerator_t *enumerator; - certificate_t *cert, *found = NULL; - - enumerator = acerts->create_enumerator(acerts); - while (enumerator->enumerate(enumerator, &cert)) - { - ac_t *ac = (ac_t*)cert; - - if (issuer->equals(issuer, ac->get_holderIssuer(ac)) && - chunk_equals(serial, ac->get_holderSerial(ac))) - { - found = cert; - break; - } - } - enumerator->destroy(enumerator); - return found; -} - -/** - * Verifies a X.509 attribute certificate - */ -bool ac_verify_cert(certificate_t *cert, bool strict) -{ - ac_t *ac = (ac_t*)cert; - identification_t *subject = cert->get_subject(cert); - identification_t *issuer = cert->get_issuer(cert); - chunk_t authKeyID = ac->get_authKeyIdentifier(ac); - cert_t *aacert; - time_t notBefore, valid_until; - - DBG1(DBG_LIB, "holder: '%Y'", subject); - DBG1(DBG_LIB, "issuer: '%Y'", issuer); - - if (!cert->get_validity(cert, NULL, NULL, &valid_until)) - { - DBG1(DBG_LIB, "attribute certificate is invalid (valid from %T to %T)", - ¬Before, FALSE, &valid_until, FALSE); - return FALSE; - } - DBG1(DBG_LIB, "attribute certificate is valid until %T", &valid_until, - FALSE); - - lock_authcert_list("verify_x509acert"); - aacert = get_authcert(issuer, authKeyID, X509_AA); - unlock_authcert_list("verify_x509acert"); - - if (aacert == NULL) - { - DBG1(DBG_LIB, "issuer aacert not found"); - return FALSE; - } - DBG2(DBG_LIB, "issuer aacert found"); - - if (!cert->issued_by(cert, aacert->cert)) - { - DBG1(DBG_LIB, "attribute certificate signature is invalid"); - return FALSE; - } - DBG1(DBG_LIB, "attribute certificate signature is valid"); - - return verify_x509cert(aacert, strict, &valid_until); -} - -/** - * Add a X.509 attribute certificate to the chained list - */ -static void ac_add_cert(certificate_t *cert) -{ - ac_t *ac = (ac_t*)cert; - identification_t *hIssuer = ac->get_holderIssuer(ac); - chunk_t hSerial = ac->get_holderSerial(ac); - - enumerator_t *enumerator; - certificate_t *cert_old; - - enumerator = acerts->create_enumerator(acerts); - while (enumerator->enumerate(enumerator, &cert_old)) - { - ac_t *ac_old = (ac_t*)cert_old; - - if (hIssuer->equals(hIssuer, ac_old->get_holderIssuer(ac_old)) && - chunk_equals(hSerial, ac_old->get_holderSerial(ac_old))) - { - if (certificate_is_newer(cert, cert_old)) - { - acerts->remove_at(acerts, enumerator); - cert_old->destroy(cert_old); - } - else - { - cert->destroy(cert); - cert = NULL; - } - break; - } - } - enumerator->destroy(enumerator); - - if (cert) - { - acerts->insert_last(acerts, cert); - } -} - -/** - * Check if at least one peer attribute matches a connection attribute - */ -bool match_group_membership(ietf_attributes_t *peer_attributes, char *conn, - ietf_attributes_t *conn_attributes) -{ - bool match; - - if (conn_attributes == NULL) - { - return TRUE; - } - - match = conn_attributes->matches(conn_attributes, peer_attributes); - DBG1(DBG_LIB, "%s: peer with attributes '%s' is %sa member of the " - "groups '%s'", conn, peer_attributes->get_string(peer_attributes), - match ? "" : "not ", conn_attributes->get_string(conn_attributes)); - - return match; -} - -/** - * Loads X.509 attribute certificates - */ -void ac_load_certs(void) -{ - enumerator_t *enumerator; - struct stat st; - char *file; - - DBG1(DBG_LIB, "loading attribute certificates from '%s'", A_CERT_PATH); - - enumerator = enumerator_create_directory(A_CERT_PATH); - if (!enumerator) - { - return; - } - - while (enumerator->enumerate(enumerator, NULL, &file, &st)) - { - certificate_t *cert; - - if (!S_ISREG(st.st_mode)) - { - /* skip special file */ - continue; - } - cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, - BUILD_FROM_FILE, file, BUILD_END); - if (cert) - { - DBG1(DBG_LIB, " loaded attribute certificate from '%s'", file); - ac_add_cert(cert); - } - } - enumerator->destroy(enumerator); -} - -/** - * List all X.509 attribute certificates in the chained list - */ -void ac_list_certs(bool utc) -{ - enumerator_t *enumerator; - certificate_t *cert; - time_t now; - - /* determine the current time */ - time(&now); - - if (acerts->get_count(acerts) > 0) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:"); - } - - enumerator = acerts->create_enumerator(acerts); - while (enumerator->enumerate(enumerator, &cert)) - { - ac_t *ac = (ac_t*)cert; - identification_t *entityName, *holderIssuer, *issuer; - chunk_t holderSerial, serial, authKeyID; - time_t notBefore, notAfter; - ietf_attributes_t *groups; - - whack_log(RC_COMMENT, " "); - - entityName = cert->get_subject(cert); - if (entityName) - { - whack_log(RC_COMMENT, " holder: \"%Y\"", entityName); - } - - holderIssuer = ac->get_holderIssuer(ac); - if (holderIssuer) - { - whack_log(RC_COMMENT, " hissuer: \"%Y\"", holderIssuer); - } - - holderSerial = chunk_skip_zero(ac->get_holderSerial(ac)); - if (holderSerial.ptr) - { - whack_log(RC_COMMENT, " hserial: %#B", &holderSerial); - } - - groups = ac->get_groups(ac); - if (groups) - { - whack_log(RC_COMMENT, " groups: %s", groups->get_string(groups)); - groups->destroy(groups); - } - - issuer = cert->get_issuer(cert); - whack_log(RC_COMMENT, " issuer: \"%Y\"", issuer); - - serial = chunk_skip_zero(ac->get_serial(ac)); - whack_log(RC_COMMENT, " serial: %#B", &serial); - - cert->get_validity(cert, &now, ¬Before, ¬After); - whack_log(RC_COMMENT, " validity: not before %T %s", - ¬Before, utc, - (notBefore < now)?"ok":"fatal (not valid yet)"); - whack_log(RC_COMMENT, " not after %T %s", ¬After, utc, - check_expiry(notAfter, ACERT_WARNING_INTERVAL, TRUE)); - - authKeyID = ac->get_authKeyIdentifier(ac); - if (authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &authKeyID); - } - } - enumerator->destroy(enumerator); -} - diff --git a/src/pluto/ac.h b/src/pluto/ac.h deleted file mode 100644 index d4e0c1590..000000000 --- a/src/pluto/ac.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Support of X.509 attribute certificates - * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2003 Martin Berner, Lukas Suter - * Copyright (C) 2009 Andreas Steffen - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _AC_H -#define _AC_H - -#include <utils/identification.h> -#include <credentials/certificates/certificate.h> -#include <credentials/ietf_attributes/ietf_attributes.h> - -/* access structure for an X.509 attribute certificate */ - -extern void ac_initialize(void); -extern void ac_finalize(void); -extern void ac_load_certs(void); -extern void ac_list_certs(bool utc); - -extern certificate_t* ac_get_cert(identification_t *issuer, chunk_t serial); - -extern bool ac_verify_cert(certificate_t *ac, bool strict); - -extern bool match_group_membership(ietf_attributes_t *peer_attributes, - char *conn, - ietf_attributes_t *conn_attributes); - -#endif /* _AC_H */ diff --git a/src/pluto/adns.c b/src/pluto/adns.c deleted file mode 100644 index 76b459216..000000000 --- a/src/pluto/adns.c +++ /dev/null @@ -1,610 +0,0 @@ -/* Pluto Asynchronous DNS Helper Program -- for internal use only! - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* This program executes as multiple processes. The Master process - * receives queries (struct adns_query messages) from Pluto and distributes - * them amongst Worker processes. These Worker processes are created - * by the Master whenever a query arrives and no existing Worker is free. - * At most MAX_WORKERS will be created; after that, the Master will queue - * queries until a Worker becomes free. When a Worker has an answer from - * the resolver, it sends the answer as a struct adns_answer message to the - * Master. The Master then forwards the answer to Pluto, noting that - * the Worker is free to accept another query. - * - * The protocol is simple: Pluto sends a sequence of queries and receives - * a sequence of answers. select(2) is used by Pluto and by the Master - * process to decide when to read, but writes are done without checking - * for readiness. Communications is via pipes. Since only one process - * can write to each pipe, messages will not be interleaved. Fixed length - * records are used for simplicity. - * - * Pluto needs a way to indicate to the Master when to shut down - * and the Master needs to indicate this to each worker. EOF on the pipe - * signifies this. - * - * The interfaces between these components are considered private to - * Pluto. This allows us to get away with less checking. This is a - * reason to use pipes instead of TCP/IP. - * - * Although the code uses plain old UNIX processes, it could be modified - * to use threads. That might reduce resource requirements. It would - * preclude running on systems without thread-safe resolvers. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <syslog.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <resolv.h> -#include <netdb.h> /* ??? for h_errno */ - -#include <freeswan.h> - -/* GCC magic! */ -#ifdef GCC_LINT -# define UNUSED __attribute__ ((unused)) -#else -# define UNUSED /* ignore */ -#endif - -#include "constants.h" -#include "adns.h" /* needs <resolv.h> */ - -/* shared by all processes */ - -static const char *name; /* program name, for messages */ - -static bool debug = FALSE; - -/* Read a variable-length record from a pipe (and no more!). - * First bytes must be a size_t containing the length. - * HES_CONTINUE if record read - * HES_OK if EOF - * HES_IO_ERROR_IN if errno tells the tale. - * Others are errors. - */ -static enum helper_exit_status -read_pipe(int fd, unsigned char *stuff, size_t minlen, size_t maxlen) -{ - size_t n = 0; - size_t goal = minlen; - - do { - ssize_t m = read(fd, stuff + n, goal - n); - - if (m == -1) - { - if (errno != EINTR) - { - syslog(LOG_ERR, "Input error on pipe: %s", strerror(errno)); - return HES_IO_ERROR_IN; - } - } - else if (m == 0) - { - return HES_OK; /* treat empty message as EOF */ - } - else - { - n += m; - if (n >= sizeof(size_t)) - { - goal = *(size_t *)(void *)stuff; - if (goal < minlen || maxlen < goal) - { - if (debug) - fprintf(stderr, "%lu : [%lu, %lu]\n" - , (unsigned long)goal - , (unsigned long)minlen, (unsigned long)maxlen); - return HES_BAD_LEN; - } - } - } - } while (n < goal); - - return HES_CONTINUE; -} - -/* Write a variable-length record to a pipe. - * First bytes must be a size_t containing the length. - * HES_CONTINUE if record written - * Others are errors. - */ -static enum helper_exit_status -write_pipe(int fd, const unsigned char *stuff) -{ - size_t len = *(const size_t *)(const void *)stuff; - size_t n = 0; - - do { - ssize_t m = write(fd, stuff + n, len - n); - - if (m == -1) - { - /* error, but ignore and retry if EINTR */ - if (errno != EINTR) - { - syslog(LOG_ERR, "Output error from master: %s", strerror(errno)); - return HES_IO_ERROR_OUT; - } - } - else - { - n += m; - } - } while (n != len); - return HES_CONTINUE; -} - -/**************** worker process ****************/ - -/* The interface in RHL6.x and BIND distribution 8.2.2 are different, - * so we build some of our own :-( - */ - -/* Support deprecated interface to allow for older releases of the resolver. - * Fake new interface! - * See resolver(3) bind distribution (should be in RHL6.1, but isn't). - * __RES was 19960801 in RHL6.2, an old resolver. - */ - -#if (__RES) <= 19960801 -# define OLD_RESOLVER 1 -#endif - -#ifdef OLD_RESOLVER - -# define res_ninit(statp) res_init() -# define res_nquery(statp, dname, class, type, answer, anslen) \ - res_query(dname, class, type, answer, anslen) -# define res_nclose(statp) res_close() - -static struct __res_state *statp = &_res; - -#else /* !OLD_RESOLVER */ - -static struct __res_state my_res_state /* = { 0 } */; -static res_state statp = &my_res_state; - -#endif /* !OLD_RESOLVER */ - -static int -worker(int qfd, int afd) -{ - { - int r = res_ninit(statp); - - if (r != 0) - { - syslog(LOG_ERR, "cannot initialize resolver"); - return HES_RES_INIT; - } -#ifndef OLD_RESOLVER - statp->options |= RES_ROTATE; -#endif - statp->options |= RES_DEBUG; - } - - for (;;) - { - struct adns_query q; - struct adns_answer a; - - enum helper_exit_status r = read_pipe(qfd, (unsigned char *)&q - , sizeof(q), sizeof(q)); - - if (r != HES_CONTINUE) - return r; /* some kind of exit */ - - if (q.qmagic != ADNS_Q_MAGIC) - { - syslog(LOG_ERR, "error in input from master: bad magic"); - return HES_BAD_MAGIC; - } - - a.amagic = ADNS_A_MAGIC; - a.serial = q.serial; - a.continuation = NULL; - - a.result = res_nquery(statp, q.name_buf, C_IN, q.type, a.ans, sizeof(a.ans)); - a.h_errno_val = h_errno; - - a.len = offsetof(struct adns_answer, ans) + (a.result < 0? 0 : a.result); - -#ifdef DEBUG - if (((q.debugging & IMPAIR_DELAY_ADNS_KEY_ANSWER) && q.type == T_KEY) - || ((q.debugging & IMPAIR_DELAY_ADNS_TXT_ANSWER) && q.type == T_TXT)) - sleep(30); /* delay the answer */ -#endif - - /* write answer, possibly a bit at a time */ - r = write_pipe(afd, (const unsigned char *)&a); - - if (r != HES_CONTINUE) - return r; /* some kind of exit */ - } -} - -/**************** master process ****************/ - -bool eof_from_pluto = FALSE; -#define PLUTO_QFD 0 /* queries come on stdin */ -#define PLUTO_AFD 1 /* answers go out on stdout */ - -#ifndef MAX_WORKERS -# define MAX_WORKERS 10 /* number of in-flight queries */ -#endif - -struct worker_info { - int qfd; /* query pipe's file descriptor */ - int afd; /* answer pipe's file descriptor */ - pid_t pid; - bool busy; - void *continuation; /* of outstanding request */ -}; - -static struct worker_info wi[MAX_WORKERS]; -static struct worker_info *wi_roof = wi; - -/* request FIFO */ - -struct query_list { - struct query_list *next; - struct adns_query aq; -}; - -static struct query_list *oldest_query = NULL; -static struct query_list *newest_query; /* undefined when oldest == NULL */ -static struct query_list *free_queries = NULL; - -static bool -spawn_worker(void) -{ - int qfds[2]; - int afds[2]; - pid_t p; - - if (pipe(qfds) != 0 || pipe(afds) != 0) - { - syslog(LOG_ERR, "pipe(2) failed: %s", strerror(errno)); - exit(HES_PIPE); - } - - wi_roof->qfd = qfds[1]; /* write end of query pipe */ - wi_roof->afd = afds[0]; /* read end of answer pipe */ - - p = fork(); - if (p == -1) - { - /* fork failed: ignore if at least one worker exists */ - if (wi_roof == wi) - { - syslog(LOG_ERR, "fork(2) error creating first worker: %s", strerror(errno)); - exit(HES_FORK); - } - close(qfds[0]); - close(qfds[1]); - close(afds[0]); - close(afds[1]); - return FALSE; - } - else if (p == 0) - { - /* child */ - struct worker_info *w; - - close(PLUTO_QFD); - close(PLUTO_AFD); - /* close all master pipes, including ours */ - for (w = wi; w <= wi_roof; w++) - { - close(w->qfd); - close(w->afd); - } - exit(worker(qfds[0], afds[1])); - } - else - { - /* parent */ - struct worker_info *w = wi_roof++; - - w->pid = p; - w->busy = FALSE; - close(qfds[0]); - close(afds[1]); - return TRUE; - } -} - -static void -send_eof(struct worker_info *w) -{ - pid_t p; - int status; - - close(w->qfd); - w->qfd = NULL_FD; - - close(w->afd); - w->afd = NULL_FD; - - /* reap child */ - p = waitpid(w->pid, &status, 0); - /* ignore result -- what could we do with it? */ -} - -static void -forward_query(struct worker_info *w) -{ - struct query_list *q = oldest_query; - - if (q == NULL) - { - if (eof_from_pluto) - send_eof(w); - } - else - { - enum helper_exit_status r - = write_pipe(w->qfd, (const unsigned char *) &q->aq); - - if (r != HES_CONTINUE) - exit(r); - - w->busy = TRUE; - - oldest_query = q->next; - q->next = free_queries; - free_queries = q; - } -} - -static void -query(void) -{ - struct query_list *q = free_queries; - enum helper_exit_status r; - - /* find an unused queue entry */ - if (q == NULL) - { - q = malloc(sizeof(*q)); - if (q == NULL) - { - syslog(LOG_ERR, "malloc(3) failed"); - exit(HES_MALLOC); - } - } - else - { - free_queries = q->next; - } - - r = read_pipe(PLUTO_QFD, (unsigned char *)&q->aq - , sizeof(q->aq), sizeof(q->aq)); - - if (r == HES_OK) - { - /* EOF: we're done, except for unanswered queries */ - struct worker_info *w; - - eof_from_pluto = TRUE; - q->next = free_queries; - free_queries = q; - - /* Send bye-bye to unbusy processes. - * Note that if there are queued queries, there won't be - * any non-busy workers. - */ - for (w = wi; w != wi_roof; w++) - if (!w->busy) - send_eof(w); - } - else if (r != HES_CONTINUE) - { - exit(r); - } - else if (q->aq.qmagic != ADNS_Q_MAGIC) - { - syslog(LOG_ERR, "error in query from Pluto: bad magic"); - exit(HES_BAD_MAGIC); - } - else - { - struct worker_info *w; - - /* got a query */ - - /* add it to FIFO */ - q->next = NULL; - if (oldest_query == NULL) - oldest_query = q; - else - newest_query->next = q; - newest_query = q; - - /* See if any worker available */ - for (w = wi; ; w++) - { - if (w == wi_roof) - { - /* no free worker */ - if (w == wi + MAX_WORKERS) - break; /* no more to be created */ - /* make a new one */ - if (!spawn_worker()) - break; /* cannot create one at this time */ - } - if (!w->busy) - { - /* assign first to free worker */ - forward_query(w); - break; - } - } - } - return; -} - -static void -answer(struct worker_info *w) -{ - struct adns_answer a; - enum helper_exit_status r = read_pipe(w->afd, (unsigned char *)&a - , offsetof(struct adns_answer, ans), sizeof(a)); - - if (r == HES_OK) - { - /* unexpected EOF */ - syslog(LOG_ERR, "unexpected EOF from worker"); - exit(HES_IO_ERROR_IN); - } - else if (r != HES_CONTINUE) - { - exit(r); - } - else if (a.amagic != ADNS_A_MAGIC) - { - syslog(LOG_ERR, "Input from worker error: bad magic"); - exit(HES_BAD_MAGIC); - } - else if (a.continuation != w->continuation) - { - /* answer doesn't match query */ - syslog(LOG_ERR, "Input from worker error: continuation mismatch"); - exit(HES_SYNC); - } - else - { - /* pass the answer on to Pluto */ - enum helper_exit_status r - = write_pipe(PLUTO_AFD, (const unsigned char *) &a); - - if (r != HES_CONTINUE) - exit(r); - w->busy = FALSE; - forward_query(w); - } -} - -/* assumption: input limited; accept blocking on output */ -static int -master(void) -{ - for (;;) - { - fd_set readfds; - int maxfd = PLUTO_QFD; /* approximate lower bound */ - int ndes = 0; - struct worker_info *w; - - FD_ZERO(&readfds); - if (!eof_from_pluto) - { - FD_SET(PLUTO_QFD, &readfds); - ndes++; - } - for (w = wi; w != wi_roof; w++) - { - if (w->busy) - { - FD_SET(w->afd, &readfds); - ndes++; - if (maxfd < w->afd) - maxfd = w->afd; - } - } - - if (ndes == 0) - return HES_OK; /* done! */ - - do { - ndes = select(maxfd + 1, &readfds, NULL, NULL, NULL); - } while (ndes == -1 && errno == EINTR); - if (ndes == -1) - { - syslog(LOG_ERR, "select(2) error: %s", strerror(errno)); - exit(HES_IO_ERROR_SELECT); - } - else if (ndes > 0) - { - if (FD_ISSET(PLUTO_QFD, &readfds)) - { - query(); - ndes--; - } - for (w = wi; ndes > 0 && w != wi_roof; w++) - { - if (w->busy && FD_ISSET(w->afd, &readfds)) - { - answer(w); - ndes--; - } - } - } - } -} - -/* Not to be invoked by strangers -- user hostile. - * Mandatory args: query-fd answer-fd - * Optional arg: -d, signifying "debug". - */ - -static void -adns_usage(const char *fmt, const char *arg) -{ - const char **sp = ipsec_copyright_notice(); - - fprintf(stderr, "INTERNAL TO PLUTO: DO NOT EXECUTE\n"); - - fprintf(stderr, fmt, arg); - fprintf(stderr, "\nstrongSwan "VERSION"\n"); - - for (; *sp != NULL; sp++) - fprintf(stderr, "%s\n", *sp); - - syslog(LOG_ERR, fmt, arg); - exit(HES_INVOCATION); -} - -int -main(int argc UNUSED, char **argv) -{ - int i = 1; - - name = argv[0]; - - while (i < argc) - { - if (streq(argv[i], "-d")) - { - i++; - debug = TRUE; - } - else - { - adns_usage("unexpected argument \"%s\"", argv[i]); - /*NOTREACHED*/ - } - } - - return master(); -} diff --git a/src/pluto/adns.h b/src/pluto/adns.h deleted file mode 100644 index dfbcbaf16..000000000 --- a/src/pluto/adns.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Pluto Asynchronous DNS Helper Program's Header - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef ADNS - -/* dummy struct to make compilers happy */ -struct adns_query { -}; - -#else /* rest of file */ - -/* The interface in RHL6.x and BIND distribution 8.2.2 are different, - * so we build some of our own :-( - */ - -# ifndef NS_MAXDNAME -# define NS_MAXDNAME MAXDNAME /* I hope this is long enough for IPv6 */ -# endif - -# ifndef NS_PACKETSZ -# define NS_PACKETSZ PACKETSZ -# endif - -/* protocol version */ - -#define ADNS_Q_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 4) -#define ADNS_A_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 128 + 4) - -/* note: both struct adns_query and struct adns_answer must start with - * size_t len; - */ - -struct adns_query { - size_t len; - unsigned int qmagic; - unsigned long serial; - lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */ - u_char name_buf[NS_MAXDNAME + 2]; - int type; /* T_KEY or T_TXT */ -}; - -struct adns_answer { - size_t len; - unsigned int amagic; - unsigned long serial; - struct adns_continuation *continuation; - int result; - int h_errno_val; - u_char ans[NS_PACKETSZ * 10]; /* very probably bigger than necessary */ -}; - -enum helper_exit_status { - HES_CONTINUE = -1, /* not an exit */ - HES_OK = 0, /* all's well that ends well (perhaps EOF) */ - HES_INVOCATION, /* improper invocation */ - HES_IO_ERROR_SELECT, /* IO error in select() */ - HES_MALLOC, /* malloc failed */ - HES_IO_ERROR_IN, /* error reading pipe */ - HES_IO_ERROR_OUT, /* error reading pipe */ - HES_PIPE, /* pipe(2) failed */ - HES_SYNC, /* answer from worker doesn't match query */ - HES_FORK, /* fork(2) failed */ - HES_RES_INIT, /* resolver initialization failed */ - HES_BAD_LEN, /* implausible .len field */ - HES_BAD_MAGIC, /* .magic field wrong */ -}; -#endif /* ADNS */ diff --git a/src/pluto/alg_info.c b/src/pluto/alg_info.c deleted file mode 100644 index fe27c10b2..000000000 --- a/src/pluto/alg_info.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Algorithm info parsing and creation functions - * Copyright (C) JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stddef.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <ctype.h> -#include <freeswan.h> -#include <pfkeyv2.h> - -#include <utils.h> -#include <utils/lexparser.h> -#include <crypto/diffie_hellman.h> -#include <crypto/transform.h> -#include <crypto/proposal/proposal_keywords.h> - - -#include "alg_info.h" -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "whack.h" -#include "crypto.h" -#include "kernel_alg.h" -#include "ike_alg.h" - -/* - * sadb/ESP aa attrib converters - */ -int alg_info_esp_aa2sadb(int auth) -{ - int sadb_aalg = 0; - - switch(auth) - { - case AUTH_ALGORITHM_HMAC_MD5: - case AUTH_ALGORITHM_HMAC_SHA1: - sadb_aalg = auth + 1; - break; - default: - sadb_aalg = auth; - } - return sadb_aalg; -} - -int alg_info_esp_sadb2aa(int sadb_aalg) -{ - int auth = 0; - - switch(sadb_aalg) - { - case SADB_AALG_MD5HMAC: - case SADB_AALG_SHA1HMAC: - auth = sadb_aalg - 1; - break; - default: - auth = sadb_aalg; - } - return auth; -} - -void alg_info_free(struct alg_info *alg_info) -{ - free(alg_info); -} - -/* - * Raw add routine: only checks for no duplicates - */ -static void __alg_info_esp_add(struct alg_info_esp *alg_info, int ealg_id, - unsigned ek_bits, int aalg_id, unsigned ak_bits) -{ - struct esp_info *esp_info = alg_info->esp; - unsigned cnt = alg_info->alg_info_cnt, i; - - /* check for overflows */ - passert(cnt < countof(alg_info->esp)); - - /* dont add duplicates */ - for (i = 0; i < cnt; i++) - { - if (esp_info[i].esp_ealg_id == ealg_id - && (!ek_bits || esp_info[i].esp_ealg_keylen == ek_bits) - && esp_info[i].esp_aalg_id == aalg_id - && (!ak_bits || esp_info[i].esp_aalg_keylen == ak_bits)) - { - return; - } - } - - esp_info[cnt].esp_ealg_id = ealg_id; - esp_info[cnt].esp_ealg_keylen = ek_bits; - esp_info[cnt].esp_aalg_id = aalg_id; - esp_info[cnt].esp_aalg_keylen = ak_bits; - - /* sadb values */ - esp_info[cnt].encryptalg = ealg_id; - esp_info[cnt].authalg = alg_info_esp_aa2sadb(aalg_id); - alg_info->alg_info_cnt++; - - DBG(DBG_CRYPT, - DBG_log("esp alg added: %s_%d/%s, cnt=%d", - enum_show(&esp_transform_names, ealg_id), ek_bits, - enum_show(&auth_alg_names, aalg_id), - alg_info->alg_info_cnt) - ) -} - -/** - * Returns true if the given alg is an authenticated encryption algorithm - */ -static bool is_authenticated_encryption(int ealg_id) -{ - switch (ealg_id) - { - case ESP_AES_CCM_8: - case ESP_AES_CCM_12: - case ESP_AES_CCM_16: - case ESP_AES_GCM_8: - case ESP_AES_GCM_12: - case ESP_AES_GCM_16: - case ESP_AES_GMAC: - return TRUE; - } - return FALSE; -} - -/* - * Add ESP alg info _with_ logic (policy): - */ -static void alg_info_esp_add(struct alg_info *alg_info, int ealg_id, - int ek_bits, int aalg_id, int ak_bits) -{ - /* Policy: default to 3DES */ - if (ealg_id == 0) - { - ealg_id = ESP_3DES; - } - if (ealg_id > 0) - { - if (is_authenticated_encryption(ealg_id)) - { - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - AUTH_ALGORITHM_NONE, 0); - } - else if (aalg_id > 0) - { - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - aalg_id, ak_bits); - } - else - { - /* Policy: default to SHA-1 and MD5 */ - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - AUTH_ALGORITHM_HMAC_SHA1, ak_bits); - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - AUTH_ALGORITHM_HMAC_MD5, ak_bits); - } - } -} - -static void __alg_info_ike_add (struct alg_info_ike *alg_info, int ealg_id, - unsigned ek_bits, int aalg_id, unsigned ak_bits, - int modp_id) -{ - struct ike_info *ike_info = alg_info->ike; - unsigned cnt = alg_info->alg_info_cnt; - unsigned i; - - /* check for overflows */ - passert(cnt < countof(alg_info->ike)); - - /* dont add duplicates */ - for (i = 0; i < cnt; i++) - { - if (ike_info[i].ike_ealg == ealg_id - && (!ek_bits || ike_info[i].ike_eklen == ek_bits) - && ike_info[i].ike_halg == aalg_id - && (!ak_bits || ike_info[i].ike_hklen == ak_bits) - && ike_info[i].ike_modp==modp_id) - return; - } - - ike_info[cnt].ike_ealg = ealg_id; - ike_info[cnt].ike_eklen = ek_bits; - ike_info[cnt].ike_halg = aalg_id; - ike_info[cnt].ike_hklen = ak_bits; - ike_info[cnt].ike_modp = modp_id; - alg_info->alg_info_cnt++; - - DBG(DBG_CRYPT, - DBG_log("ikg alg added: %s_%d/%s/%s, cnt=%d", - enum_show(&oakley_enc_names, ealg_id), ek_bits, - enum_show(&oakley_hash_names, aalg_id), - enum_show(&oakley_group_names, modp_id), - alg_info->alg_info_cnt) - ) -} - -/* - * Proposals will be built by looping over default_ike_groups array and - * merging alg_info (ike_info) contents - */ - -static int default_ike_groups[] = { - MODP_1536_BIT, - MODP_1024_BIT -}; - -/* - * Add IKE alg info _with_ logic (policy): - */ -static void alg_info_ike_add (struct alg_info *alg_info, int ealg_id, - int ek_bits, int aalg_id, int ak_bits, int modp_id) -{ - int i = 0; - int n_groups = countof(default_ike_groups); - - /* if specified modp_id avoid loop over default_ike_groups */ - if (modp_id) - { - n_groups=0; - goto in_loop; - } - - for (; n_groups--; i++) - { - modp_id = default_ike_groups[i]; -in_loop: - /* Policy: default to 3DES */ - if (ealg_id == 0) - { - ealg_id = OAKLEY_3DES_CBC; - } - if (ealg_id > 0) - { - if (aalg_id > 0) - { - __alg_info_ike_add((struct alg_info_ike *)alg_info, - ealg_id, ek_bits, - aalg_id, ak_bits, - modp_id); - } - else - { - /* Policy: default to MD5 and SHA */ - __alg_info_ike_add((struct alg_info_ike *)alg_info, - ealg_id, ek_bits, - OAKLEY_MD5, ak_bits, - modp_id); - __alg_info_ike_add((struct alg_info_ike *)alg_info, - ealg_id, ek_bits, - OAKLEY_SHA, ak_bits, - modp_id); - } - } - } -} - -static status_t alg_info_add(chunk_t alg, unsigned protoid, - int *ealg, size_t *ealg_keysize, - int *aalg, size_t *aalg_keysize, int *dh_group) -{ - const proposal_token_t *token = proposal_get_token(alg.ptr, alg.len); - - if (token == NULL) - { - return FAILED; - } - switch (token->type) - { - case ENCRYPTION_ALGORITHM: - if (*ealg != 0) - { - return FAILED; - } - *ealg = (protoid == PROTO_ISAKMP) ? - oakley_from_encryption_algorithm(token->algorithm) : - esp_from_encryption_algorithm(token->algorithm); - if (*ealg == 0) - { - return FAILED; - } - *ealg_keysize = token->keysize; - break; - case INTEGRITY_ALGORITHM: - if (*aalg != 0) - { - return FAILED; - } - *aalg = (protoid == PROTO_ISAKMP) ? - oakley_from_integrity_algorithm(token->algorithm) : - esp_from_integrity_algorithm(token->algorithm); - if (*aalg == 0) - { - return FAILED; - } - *aalg_keysize = token->keysize; - break; - case DIFFIE_HELLMAN_GROUP: - if (protoid == PROTO_ISAKMP) - { - if (*dh_group != 0) - { - return FAILED; - } - *dh_group = token->algorithm; - } - break; - default: - return FAILED; - } - return SUCCESS; -} - - -static status_t alg_info_parse_str(struct alg_info *alg_info, char *alg_str) -{ - char *strict, *single; - status_t status = SUCCESS; - - strict = alg_str + strlen(alg_str) - 1; - if (*strict == '!') - { - alg_info->alg_info_flags |= ALG_INFO_F_STRICT; - *strict = '\0'; - } - while ((single = strsep(&alg_str, ","))) - { - chunk_t string = { (u_char *)single, strlen(single) }; - int ealg = 0; - int aalg = 0; - int dh_group = 0; - size_t ealg_keysize = 0; - size_t aalg_keysize = 0; - - eat_whitespace(&string); - - if (string.len > 0) - { - chunk_t alg; - - /* get all token, separated by '-' */ - while (extract_token(&alg, '-', &string)) - { - status |= alg_info_add(alg, alg_info->alg_info_protoid, - &ealg, &ealg_keysize, - &aalg, &aalg_keysize, &dh_group); - } - if (string.len) - { - status |= alg_info_add(string, alg_info->alg_info_protoid, - &ealg, &ealg_keysize, - &aalg, &aalg_keysize, &dh_group); - } - } - if (status == SUCCESS) - - { - switch (alg_info->alg_info_protoid) - { - case PROTO_IPSEC_ESP: - alg_info_esp_add(alg_info, ealg, ealg_keysize, - aalg, aalg_keysize); - break; - case PROTO_ISAKMP: - alg_info_ike_add(alg_info, ealg, ealg_keysize, - aalg, aalg_keysize, - dh_group); - break; - default: - break; - } - } - } - return status; -} - -struct alg_info_esp *alg_info_esp_create_from_str(char *alg_str) -{ - struct alg_info_esp *alg_info_esp; - char esp_buf[BUF_LEN]; - char *pfs_name; - status_t status = SUCCESS; - /* - * alg_info storage should be sized dynamically - * but this may require 2passes to know - * transform count in advance. - */ - alg_info_esp = malloc_thing (struct alg_info_esp); - zero(alg_info_esp); - - pfs_name=strchr(alg_str, ';'); - if (pfs_name) - { - memcpy(esp_buf, alg_str, pfs_name-alg_str); - esp_buf[pfs_name-alg_str] = 0; - alg_str = esp_buf; - pfs_name++; - - /* if pfs strings AND first char is not '0' */ - if (*pfs_name && pfs_name[0] != '0') - { - const proposal_token_t *token; - - token = proposal_get_token(pfs_name, strlen(pfs_name)); - if (token == NULL || token->type != DIFFIE_HELLMAN_GROUP) - { - /* Bomb if pfsgroup not found */ - DBG(DBG_CRYPT, - DBG_log("alg_info_esp_create_from_str(): pfsgroup \"%s\" not found" - , pfs_name) - ) - status = FAILED; - goto out; - } - alg_info_esp->esp_pfsgroup = token->algorithm; - } - } - else - { - alg_info_esp->esp_pfsgroup = 0; - } - alg_info_esp->alg_info_protoid = PROTO_IPSEC_ESP; - status = alg_info_parse_str((struct alg_info *)alg_info_esp, alg_str); - -out: - if (status == SUCCESS) - { - alg_info_esp->ref_cnt = 1; - return alg_info_esp; - } - else - { - free(alg_info_esp); - return NULL; - } -} - -struct alg_info_ike *alg_info_ike_create_from_str(char *alg_str) -{ - struct alg_info_ike *alg_info_ike; - /* - * alg_info storage should be sized dynamically - * but this may require 2passes to know - * transform count in advance. - */ - alg_info_ike = malloc_thing (struct alg_info_ike); - zero(alg_info_ike); - alg_info_ike->alg_info_protoid = PROTO_ISAKMP; - - if (alg_info_parse_str((struct alg_info *)alg_info_ike, alg_str) == SUCCESS) - { - alg_info_ike->ref_cnt = 1; - return alg_info_ike; - } - else - { - free(alg_info_ike); - return NULL; - } -} - -/* - * alg_info struct can be shared by - * several connections instances, - * handle free() with ref_cnts - */ -void -alg_info_addref(struct alg_info *alg_info) -{ - if (alg_info != NULL) - { - alg_info->ref_cnt++; - } -} - -void -alg_info_delref(struct alg_info **alg_info_p) -{ - struct alg_info *alg_info = *alg_info_p; - - if (alg_info != NULL) - { - passert(alg_info->ref_cnt != 0); - alg_info->ref_cnt--; - if (alg_info->ref_cnt == 0) - { - alg_info_free(alg_info); - } - *alg_info_p = NULL; - } -} - -/* snprint already parsed transform list (alg_info) */ -int -alg_info_snprint(char *buf, int buflen, struct alg_info *alg_info) -{ - char *ptr = buf; - int np = 0; - struct esp_info *esp_info; - struct ike_info *ike_info; - int cnt; - - switch (alg_info->alg_info_protoid) { - case PROTO_IPSEC_ESP: - { - struct alg_info_esp *alg_info_esp = (struct alg_info_esp *)alg_info; - - ALG_INFO_ESP_FOREACH(alg_info_esp, esp_info, cnt) - { - np = snprintf(ptr, buflen, "%s", - enum_show(&esp_transform_names, esp_info->esp_ealg_id)); - ptr += np; - buflen -= np; - if (esp_info->esp_ealg_keylen) - { - np = snprintf(ptr, buflen, "_%zu", esp_info->esp_ealg_keylen); - ptr += np; - buflen -= np; - } - np = snprintf(ptr, buflen, "/%s, ", - enum_show(&auth_alg_names, esp_info->esp_aalg_id)); - ptr += np; - buflen -= np; - if (buflen < 0) - goto out; - } - if (alg_info_esp->esp_pfsgroup) - { - np = snprintf(ptr, buflen, "; pfsgroup=%s; ", - enum_show(&oakley_group_names, alg_info_esp->esp_pfsgroup)); - ptr += np; - buflen -= np; - if (buflen < 0) - goto out; - } - break; - } - - case PROTO_ISAKMP: - ALG_INFO_IKE_FOREACH((struct alg_info_ike *)alg_info, ike_info, cnt) - { - np = snprintf(ptr, buflen, "%s", - enum_show(&oakley_enc_names, ike_info->ike_ealg)); - ptr += np; - buflen -= np; - if (ike_info->ike_eklen) - { - np = snprintf(ptr, buflen, "_%zu", ike_info->ike_eklen); - ptr += np; - buflen -= np; - } - np = snprintf(ptr, buflen, "/%s/%s, ", - enum_show(&oakley_hash_names, ike_info->ike_halg), - enum_show(&oakley_group_names, ike_info->ike_modp)); - ptr += np; - buflen -= np; - if (buflen < 0) - goto out; - } - break; - default: - np = snprintf(buf, buflen, "INVALID protoid=%d\n" - , alg_info->alg_info_protoid); - ptr += np; - buflen -= np; - goto out; - } - - np = snprintf(ptr, buflen, "%s" - , alg_info->alg_info_flags & ALG_INFO_F_STRICT? - "strict":""); - ptr += np; - buflen -= np; -out: - if (buflen < 0) - { - loglog(RC_LOG_SERIOUS - , "buffer space exhausted in alg_info_snprint_ike(), buflen=%d" - , buflen); - } - - return ptr - buf; -} - -int alg_info_snprint_esp(char *buf, int buflen, struct alg_info_esp *alg_info) -{ - char *ptr = buf; - - int cnt = alg_info->alg_info_cnt; - struct esp_info *esp_info = alg_info->esp; - - while (cnt--) - { - if (kernel_alg_esp_enc_ok(esp_info->esp_ealg_id, 0, NULL) - && kernel_alg_esp_auth_ok(esp_info->esp_aalg_id, NULL)) - { - u_int eklen = (esp_info->esp_ealg_keylen) - ? esp_info->esp_ealg_keylen - : kernel_alg_esp_enc_keylen(esp_info->esp_ealg_id) - * BITS_PER_BYTE; - - u_int aklen = esp_info->esp_aalg_keylen - ? esp_info->esp_aalg_keylen - : kernel_alg_esp_auth_keylen(esp_info->esp_aalg_id) - * BITS_PER_BYTE; - - int ret = snprintf(ptr, buflen, "%d_%03d-%d_%03d, ", - esp_info->esp_ealg_id, eklen, - esp_info->esp_aalg_id, aklen); - ptr += ret; - buflen -= ret; - if (buflen < 0) - break; - } - esp_info++; - } - return ptr - buf; -} - -int alg_info_snprint_ike(char *buf, int buflen, struct alg_info_ike *alg_info) -{ - char *ptr = buf; - - int cnt = alg_info->alg_info_cnt; - struct ike_info *ike_info = alg_info->ike; - - while (cnt--) - { - struct encrypt_desc *enc_desc = ike_alg_get_crypter(ike_info->ike_ealg); - struct hash_desc *hash_desc = ike_alg_get_hasher(ike_info->ike_halg); - struct dh_desc *dh_desc = ike_alg_get_dh_group(ike_info->ike_modp); - - if (enc_desc && hash_desc && dh_desc) - { - - u_int eklen = (ike_info->ike_eklen) - ? ike_info->ike_eklen - : enc_desc->keydeflen; - - u_int aklen = (ike_info->ike_hklen) - ? ike_info->ike_hklen - : hash_desc->hash_digest_size * BITS_PER_BYTE; - - int ret = snprintf(ptr, buflen, "%d_%03d-%d_%03d-%d, ", - ike_info->ike_ealg, eklen, - ike_info->ike_halg, aklen, - ike_info->ike_modp); - ptr += ret; - buflen -= ret; - if (buflen < 0) - break; - } - ike_info++; - } - return ptr - buf; -} - diff --git a/src/pluto/alg_info.h b/src/pluto/alg_info.h deleted file mode 100644 index 85b88ddff..000000000 --- a/src/pluto/alg_info.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Algorithm info parsing and creation functions - * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef ALG_INFO_H -#define ALG_INFO_H - -struct esp_info { - u_int8_t transid; /* ESP transform */ - u_int16_t auth; /* AUTH */ - size_t enckeylen; /* keylength for ESP transform */ - size_t authkeylen; /* keylength for AUTH */ - u_int8_t encryptalg; /* normally encryptalg=transid */ - u_int8_t authalg; /* normally authalg=auth+1 */ -}; - -struct ike_info { - u_int16_t ike_ealg; /* high 16 bit nums for reserved */ - u_int8_t ike_halg; - size_t ike_eklen; - size_t ike_hklen; - u_int16_t ike_modp; -}; - -#define ALG_INFO_COMMON \ - int alg_info_cnt; \ - int ref_cnt; \ - unsigned alg_info_flags; \ - unsigned alg_info_protoid - -struct alg_info { - ALG_INFO_COMMON; -}; - -struct alg_info_esp { - ALG_INFO_COMMON; - struct esp_info esp[64]; - int esp_pfsgroup; -}; - -struct alg_info_ike { - ALG_INFO_COMMON; - struct ike_info ike[64]; -}; -#define esp_ealg_id transid -#define esp_aalg_id auth -#define esp_ealg_keylen enckeylen /* bits */ -#define esp_aalg_keylen authkeylen /* bits */ - -/* alg_info_flags bits */ -#define ALG_INFO_F_STRICT 0x01 - -extern int alg_info_esp_aa2sadb(int auth); -extern int alg_info_esp_sadb2aa(int sadb_aalg); -extern void alg_info_free(struct alg_info *alg_info); -extern void alg_info_addref(struct alg_info *alg_info); -extern void alg_info_delref(struct alg_info **alg_info); -extern struct alg_info_esp* alg_info_esp_create_from_str(char *alg_str); -extern struct alg_info_ike* alg_info_ike_create_from_str(char *alg_str); -extern int alg_info_parse(const char *str); -extern int alg_info_snprint(char *buf, int buflen, struct alg_info *alg_info); -extern int alg_info_snprint_esp(char *buf, int buflen - , struct alg_info_esp *alg_info); -extern int alg_info_snprint_ike(char *buf, int buflen - , struct alg_info_ike *alg_info); -#define ALG_INFO_ESP_FOREACH(ai, ai_esp, i) \ - for (i=(ai)->alg_info_cnt,ai_esp=(ai)->esp; i--; ai_esp++) -#define ALG_INFO_IKE_FOREACH(ai, ai_ike, i) \ - for (i=(ai)->alg_info_cnt,ai_ike=(ai)->ike; i--; ai_ike++) -#endif /* ALG_INFO_H */ diff --git a/src/pluto/builder.c b/src/pluto/builder.c deleted file mode 100644 index a6e05a330..000000000 --- a/src/pluto/builder.c +++ /dev/null @@ -1,150 +0,0 @@ -/* Pluto certificate/CRL/AC builder hooks. - * Copyright (C) 2002-2009 Andreas Steffen - * Copyright (C) 2009 Martin Willi - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "builder.h" - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <time.h> - -#include <freeswan.h> - -#include <library.h> -#include <credentials/certificates/certificate.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "certs.h" -#include "crl.h" - -/** - * Load a certificate - */ -static cert_t *builder_load_cert(certificate_type_t type, va_list args) -{ - x509_flag_t flags = 0; - chunk_t blob = chunk_empty; - bool pgp = FALSE; - - while (TRUE) - { - switch (va_arg(args, builder_part_t)) - { - case BUILD_BLOB_PGP: - pgp = TRUE; - /* FALL */ - case BUILD_BLOB_ASN1_DER: - blob = va_arg(args, chunk_t); - continue; - case BUILD_X509_FLAG: - flags |= va_arg(args, x509_flag_t); - continue; - case BUILD_END: - break; - default: - return NULL; - } - break; - } - if (blob.ptr) - { - cert_t *cert = malloc_thing(cert_t); - - *cert = cert_empty; - - if (pgp) - { - cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_GPG, - BUILD_BLOB_PGP, blob, - BUILD_END); - } - else - { - cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, blob, - BUILD_X509_FLAG, flags, - BUILD_END); - } - if (cert->cert) - { - return cert; - } - plog(" error in X.509 certificate"); - cert_free(cert); - } - return NULL; -} - -/** - * Load a CRL - */ -static x509crl_t *builder_load_crl(certificate_type_t type, va_list args) -{ - chunk_t blob = chunk_empty; - x509crl_t *crl; - - while (TRUE) - { - switch (va_arg(args, builder_part_t)) - { - case BUILD_BLOB_ASN1_DER: - blob = va_arg(args, chunk_t); - continue; - case BUILD_END: - break; - default: - return NULL; - } - break; - } - if (blob.ptr) - { - crl = malloc_thing(x509crl_t); - crl->next = NULL; - crl->distributionPoints = linked_list_create(); - crl->crl = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509_CRL, - BUILD_BLOB_ASN1_DER, blob, - BUILD_END); - if (crl->crl) - { - return crl; - } - plog(" error in X.509 crl"); - free_crl(crl); - } - return NULL; -} - -void init_builder(void) -{ - lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT, FALSE, - (builder_function_t)builder_load_cert); - lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CRL, FALSE, - (builder_function_t)builder_load_crl); -} - -void free_builder(void) -{ - lib->creds->remove_builder(lib->creds, (builder_function_t)builder_load_cert); - lib->creds->remove_builder(lib->creds, (builder_function_t)builder_load_crl); -} - diff --git a/src/pluto/builder.h b/src/pluto/builder.h deleted file mode 100644 index 784751b7c..000000000 --- a/src/pluto/builder.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Pluto certificate/CRL/AC builder hooks. - * Copyright (C) 2009 Martin Willi - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _BUILDER_H -#define _BUILDER_H - -/* register credential builder hooks */ -extern void init_builder(); -/* unregister credential builder hooks */ -extern void free_builder(); - -#endif /* _BUILDER_H */ diff --git a/src/pluto/ca.c b/src/pluto/ca.c deleted file mode 100644 index 827b98121..000000000 --- a/src/pluto/ca.c +++ /dev/null @@ -1,712 +0,0 @@ -/* Certification Authority (CA) support for IKE authentication - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include <debug.h> -#include <utils/enumerator.h> -#include <credentials/certificates/x509.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "ca.h" -#include "certs.h" -#include "whack.h" -#include "fetch.h" -#include "smartcard.h" - -/* chained list of X.509 authority certificates (ca, aa, and ocsp) */ - -static cert_t *x509authcerts = NULL; - -/* chained list of X.509 certification authority information records */ - -static ca_info_t *ca_infos = NULL; - -/* - * Checks if CA a is trusted by CA b - */ -bool trusted_ca(identification_t *a, identification_t *b, int *pathlen) -{ - bool match = FALSE; - - /* no CA b specified -> any CA a is accepted */ - if (b == NULL) - { - *pathlen = (a == NULL) ? 0 : X509_MAX_PATH_LEN; - return TRUE; - } - - /* no CA a specified -> trust cannot be established */ - if (a == NULL) - { - *pathlen = X509_MAX_PATH_LEN; - return FALSE; - } - - *pathlen = 0; - - /* CA a equals CA b -> we have a match */ - if (a->equals(a, b)) - { - return TRUE; - } - - /* CA a might be a subordinate CA of b */ - lock_authcert_list("trusted_ca"); - - while ((*pathlen)++ < X509_MAX_PATH_LEN) - { - certificate_t *certificate; - identification_t *issuer; - cert_t *cacert; - - cacert = get_authcert(a, chunk_empty, X509_CA); - if (cacert == NULL) - { - break; - } - certificate = cacert->cert; - - /* is the certificate self-signed? */ - { - x509_t *x509 = (x509_t*)certificate; - - if (x509->get_flags(x509) & X509_SELF_SIGNED) - { - break; - } - } - - /* does the issuer of CA a match CA b? */ - issuer = certificate->get_issuer(certificate); - match = b->equals(b, issuer); - - /* we have a match and exit the loop */ - if (match) - { - break; - } - /* go one level up in the CA chain */ - a = issuer; - } - - unlock_authcert_list("trusted_ca"); - return match; -} - -/* - * does our CA match one of the requested CAs? - */ -bool match_requested_ca(linked_list_t *requested_ca, identification_t *our_ca, - int *our_pathlen) -{ - identification_t *ca; - enumerator_t *enumerator; - - /* if no ca is requested than any ca will match */ - if (requested_ca == NULL || requested_ca->get_count(requested_ca) == 0) - { - *our_pathlen = 0; - return TRUE; - } - - *our_pathlen = X509_MAX_PATH_LEN + 1; - - enumerator = requested_ca->create_enumerator(requested_ca); - while (enumerator->enumerate(enumerator, &ca)) - { - int pathlen; - - if (trusted_ca(our_ca, ca, &pathlen) && pathlen < *our_pathlen) - { - *our_pathlen = pathlen; - } - } - enumerator->destroy(enumerator); - - if (*our_pathlen > X509_MAX_PATH_LEN) - { - *our_pathlen = X509_MAX_PATH_LEN; - return FALSE; - } - else - { - return TRUE; - } -} - -/* - * free the first authority certificate in the chain - */ -static void free_first_authcert(void) -{ - cert_t *first = x509authcerts; - - x509authcerts = first->next; - cert_free(first); -} - -/* - * free all CA certificates - */ -void free_authcerts(void) -{ - lock_authcert_list("free_authcerts"); - - while (x509authcerts != NULL) - { - free_first_authcert(); - } - unlock_authcert_list("free_authcerts"); -} - -/* - * get a X.509 authority certificate with a given subject or keyid - */ -cert_t* get_authcert(identification_t *subject, chunk_t keyid, - x509_flag_t auth_flags) -{ - cert_t *cert, *prev_cert = NULL; - - /* the authority certificate list is empty */ - if (x509authcerts == NULL) - { - return NULL; - } - - for (cert = x509authcerts; cert != NULL; prev_cert = cert, cert = cert->next) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - - /* skip non-matching types of authority certificates */ - if (!(x509->get_flags(x509) & auth_flags)) - { - continue; - } - - /* compare the keyid with the certificate's subjectKeyIdentifier */ - if (keyid.ptr) - { - chunk_t subjectKeyId; - - subjectKeyId = x509->get_subjectKeyIdentifier(x509); - if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId)) - { - continue; - } - } - - /* compare the subjectDistinguishedNames */ - if (!(subject && certificate->has_subject(certificate, subject)) && - (subject || !keyid.ptr)) - { - continue; - } - - /* found the authcert */ - if (cert != x509authcerts) - { - /* bring the certificate up front */ - prev_cert->next = cert->next; - cert->next = x509authcerts; - x509authcerts = cert; - } - return cert; - } - return NULL; -} - -/* - * add an authority certificate to the chained list - */ -cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags) -{ - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - cert_t *old_cert; - - lock_authcert_list("add_authcert"); - - old_cert = get_authcert(certificate->get_subject(certificate), - x509->get_subjectKeyIdentifier(x509), - auth_flags); - if (old_cert) - { - if (certificate->equals(certificate, old_cert->cert)) - { - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log(" authcert is already present and identical") - ) - unlock_authcert_list("add_authcert"); - - cert_free(cert); - return old_cert; - } - else - { - /* cert is already present but will be replaced by new cert */ - free_first_authcert(); - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log(" existing authcert deleted") - ) - } - } - - /* add new authcert to chained list */ - cert->next = x509authcerts; - x509authcerts = cert; - cert_share(cert); /* set count to one */ - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" authcert inserted") - ) - unlock_authcert_list("add_authcert"); - return cert; -} - -/* - * Loads authority certificates - */ -void load_authcerts(char *type, char *path, x509_flag_t auth_flags) -{ - enumerator_t *enumerator; - struct stat st; - char *file; - - DBG1(DBG_LIB, "loading %s certificates from '%s'", type, path); - - enumerator = enumerator_create_directory(path); - if (!enumerator) - { - DBG1(DBG_LIB, " reading directory '%s' failed", path); - return; - } - - while (enumerator->enumerate(enumerator, NULL, &file, &st)) - { - cert_t *cert; - - if (!S_ISREG(st.st_mode)) - { - /* skip special file */ - continue; - } - cert = load_cert(file, type, auth_flags); - if (cert) - { - add_authcert(cert, auth_flags); - } - } - enumerator->destroy(enumerator); -} - -/* - * list all X.509 authcerts with given auth flags in a chained list - */ -void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc) -{ - lock_authcert_list("list_authcerts"); - list_x509cert_chain(caption, x509authcerts, auth_flags, utc); - unlock_authcert_list("list_authcerts"); -} - -/* - * get a cacert with a given subject or keyid from an alternative list - */ -static const cert_t* get_alt_cacert(identification_t *subject, chunk_t keyid, - const cert_t *cert) -{ - if (cert == NULL) - { - return NULL; - } - for (; cert != NULL; cert = cert->next) - { - certificate_t *certificate = cert->cert; - - /* compare the keyid with the certificate's subjectKeyIdentifier */ - if (keyid.ptr) - { - x509_t *x509 = (x509_t*)certificate; - chunk_t subjectKeyId; - - subjectKeyId = x509->get_subjectKeyIdentifier(x509); - if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId)) - { - continue; - } - } - - /* compare the subjectDistinguishedNames */ - if (!certificate->has_subject(certificate, subject)) - { - continue; - } - - /* we found the cacert */ - return cert; - } - return NULL; -} - -/* establish trust into a candidate authcert by going up the trust chain. - * validity and revocation status are not checked. - */ -bool trust_authcert_candidate(const cert_t *cert, const cert_t *alt_chain) -{ - int pathlen; - - lock_authcert_list("trust_authcert_candidate"); - - for (pathlen = 0; pathlen < X509_MAX_PATH_LEN; pathlen++) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *subject = certificate->get_subject(certificate); - identification_t *issuer = certificate->get_issuer(certificate); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - const cert_t *authcert = NULL; - - DBG(DBG_CONTROL, - DBG_log("subject: '%Y'", subject); - DBG_log("issuer: '%Y'", issuer); - if (authKeyID.ptr != NULL) - { - DBG_log("authkey: %#B", &authKeyID); - } - ) - - /* search in alternative chain first */ - authcert = get_alt_cacert(issuer, authKeyID, alt_chain); - - if (authcert != NULL) - { - DBG(DBG_CONTROL, - DBG_log("issuer cacert found in alternative chain") - ) - } - else - { - /* search in trusted chain */ - authcert = get_authcert(issuer, authKeyID, X509_CA); - - if (authcert != NULL) - { - DBG(DBG_CONTROL, - DBG_log("issuer cacert found") - ) - } - else - { - plog("issuer cacert not found"); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; - } - } - - if (!certificate->issued_by(certificate, authcert->cert)) - { - plog("certificate signature is invalid"); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate signature is valid") - ) - - /* check if cert is a self-signed root ca */ - if (pathlen > 0 && (x509->get_flags(x509) & X509_SELF_SIGNED)) - { - DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca") - ) - unlock_authcert_list("trust_authcert_candidate"); - return TRUE; - } - - /* go up one step in the trust chain */ - cert = authcert; - } - plog("maximum ca path length of %d levels exceeded", X509_MAX_PATH_LEN); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; -} - -/* - * get a CA info record with a given authName or authKeyID - */ -ca_info_t* get_ca_info(identification_t *name, chunk_t keyid) -{ - ca_info_t *ca= ca_infos; - - while (ca != NULL) - { - if ((keyid.ptr) ? same_keyid(keyid, ca->authKeyID) - : name->equals(name, ca->authName)) - { - return ca; - } - ca = ca->next; - } - return NULL; -} - - -/* - * free the dynamic memory used by a ca_info record - */ -static void -free_ca_info(ca_info_t* ca_info) -{ - if (ca_info == NULL) - { - return; - } - ca_info->crluris->destroy_function(ca_info->crluris, free); - DESTROY_IF(ca_info->authName); - free(ca_info->name); - free(ca_info->ldaphost); - free(ca_info->ldapbase); - free(ca_info->ocspuri); - free(ca_info->authKeyID.ptr); - free(ca_info); -} - -/* - * free all CA certificates - */ -void free_ca_infos(void) -{ - while (ca_infos != NULL) - { - ca_info_t *ca = ca_infos; - - ca_infos = ca_infos->next; - free_ca_info(ca); - } -} - -/* - * find a CA information record by name and optionally delete it - */ -bool find_ca_info_by_name(const char *name, bool delete) -{ - ca_info_t **ca_p = &ca_infos; - ca_info_t *ca = *ca_p; - - while (ca != NULL) - { - /* is there already an entry? */ - if (streq(name, ca->name)) - { - if (delete) - { - lock_ca_info_list("find_ca_info_by_name"); - *ca_p = ca->next; - free_ca_info(ca); - plog("deleting ca description \"%s\"", name); - unlock_ca_info_list("find_ca_info_by_name"); - } - return TRUE; - } - ca_p = &ca->next; - ca = *ca_p; - } - return FALSE; -} - -/* - * Create an empty ca_info_t record - */ -ca_info_t* create_ca_info(void) -{ - ca_info_t *ca_info = malloc_thing(ca_info_t); - - memset(ca_info, 0, sizeof(ca_info_t)); - ca_info->crluris = linked_list_create(); - - return ca_info; -} - -/** - * Adds a CA description to a chained list - */ -void add_ca_info(const whack_message_t *msg) -{ - smartcard_t *sc = NULL; - cert_t *cert = NULL; - bool cached_cert = FALSE; - - if (find_ca_info_by_name(msg->name, FALSE)) - { - loglog(RC_DUPNAME, "attempt to redefine ca record \"%s\"", msg->name); - return; - } - - if (scx_on_smartcard(msg->cacert)) - { - /* load CA cert from smartcard */ - cert = scx_load_cert(msg->cacert, &sc, &cached_cert); - } - else - { - /* load CA cert from file */ - cert = load_ca_cert(msg->cacert); - } - - if (cert) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *subject = certificate->get_subject(certificate); - chunk_t subjectKeyID = x509->get_subjectKeyIdentifier(x509); - ca_info_t *ca = NULL; - - /* does the authname already exist? */ - ca = get_ca_info(subject, subjectKeyID); - - if (ca != NULL) - { - /* ca_info is already present */ - loglog(RC_DUPNAME, " duplicate ca information in record \"%s\" found," - "ignoring \"%s\"", ca->name, msg->name); - cert_free(cert); - return; - } - - plog("added ca description \"%s\"", msg->name); - - /* create and initialize new ca_info record */ - ca = create_ca_info(); - - /* name */ - ca->name = clone_str(msg->name); - - /* authName */ - ca->authName = subject->clone(subject); - DBG(DBG_CONTROL, - DBG_log("authname: '%Y'", subject) - ) - - /* authKeyID */ - if (subjectKeyID.ptr) - { - ca->authKeyID = chunk_clone(subjectKeyID); - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log("authkey: %#B", &subjectKeyID) - ) - } - - /* ldaphost */ - ca->ldaphost = clone_str(msg->ldaphost); - - /* ldapbase */ - ca->ldapbase = clone_str(msg->ldapbase); - - /* ocspuri */ - if (msg->ocspuri != NULL) - { - if (strncasecmp(msg->ocspuri, "http", 4) == 0) - ca->ocspuri = clone_str(msg->ocspuri); - else - plog(" ignoring ocspuri with unknown protocol"); - } - - /* add crl uris */ - add_distribution_point(ca->crluris, msg->crluri); - add_distribution_point(ca->crluris, msg->crluri2); - - /* strictrlpolicy */ - ca->strictcrlpolicy = msg->whack_strict; - - /* insert ca_info record into the chained list */ - lock_ca_info_list("add_ca_info"); - - ca->next = ca_infos; - ca_infos = ca; - - unlock_ca_info_list("add_ca_info"); - - /* add cacert to list of authcerts */ - cert = add_authcert(cert, X509_CA); - if (!cached_cert && sc != NULL) - { - if (sc->last_cert != NULL) - { - sc->last_cert->count--; - } - sc->last_cert = cert; - cert_share(sc->last_cert); - } - if (sc != NULL) - time(&sc->last_load); - } -} - -/* - * list all ca_info records in the chained list - */ -void list_ca_infos(bool utc) -{ - ca_info_t *ca = ca_infos; - - if (ca != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 CA Information Records:"); - } - - while (ca != NULL) - { - /* strictpolicy per CA not supported yet - * - whack_log(RC_COMMENT, "%T, \"%s\", strictcrlpolicy: %s" - , &ca->installed, utc, ca->name - , ca->strictcrlpolicy? "yes":"no"); - */ - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " authname: \"%Y\"", ca->authName); - if (ca->ldaphost) - { - whack_log(RC_COMMENT, " ldaphost: '%s'", ca->ldaphost); - } - if (ca->ldapbase) - { - whack_log(RC_COMMENT, " ldapbase: '%s'", ca->ldapbase); - } - if (ca->ocspuri) - { - whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri); - } - - list_distribution_points(ca->crluris); - - if (ca->authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &ca->authKeyID); - } - ca = ca->next; - } -} - diff --git a/src/pluto/ca.h b/src/pluto/ca.h deleted file mode 100644 index d964a694a..000000000 --- a/src/pluto/ca.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Certification Authority (CA) support for IKE authentication - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CA_H -#define _CA_H - -#include <utils/linked_list.h> -#include <utils/identification.h> - -#include "certs.h" -#include "whack.h" - -/* CA info structures */ - -typedef struct ca_info ca_info_t; - -struct ca_info { - ca_info_t *next; - char *name; - identification_t *authName; - chunk_t authKeyID; - char *ldaphost; - char *ldapbase; - char *ocspuri; - linked_list_t *crluris; - bool strictcrlpolicy; -}; - -extern bool trusted_ca(identification_t *a, identification_t *b, int *pathlen); -extern bool match_requested_ca(linked_list_t *requested_ca, - identification_t *our_ca, int *our_pathlen); -extern cert_t* get_authcert(identification_t *subject, chunk_t keyid, - x509_flag_t auth_flags); -extern void load_authcerts(char *type, char *path, x509_flag_t auth_flags); -extern cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags); -extern void free_authcerts(void); -extern void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc); -extern bool trust_authcert_candidate(const cert_t *cert, const cert_t *alt_chain); -extern ca_info_t* get_ca_info(identification_t *name, chunk_t keyid); -extern bool find_ca_info_by_name(const char *name, bool delete); -extern void add_ca_info(const whack_message_t *msg); -extern void delete_ca_info(const char *name); -extern void free_ca_infos(void); -extern void list_ca_infos(bool utc); - -#endif /* _CA_H */ - diff --git a/src/pluto/certs.c b/src/pluto/certs.c deleted file mode 100644 index e866022df..000000000 --- a/src/pluto/certs.c +++ /dev/null @@ -1,268 +0,0 @@ -/* Certificate support for IKE authentication - * Copyright (C) 2002-2009 Andreas Steffen - * - * HSR - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <time.h> - -#include <freeswan.h> - -#include <library.h> -#include <asn1/asn1.h> -#include <credentials/certificates/certificate.h> -#include <credentials/certificates/pgp_certificate.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "certs.h" -#include "whack.h" -#include "fetch.h" -#include "keys.h" -#include "builder.h" - -/** - * Initialization - */ -const cert_t cert_empty = { - NULL , /* cert */ - NULL , /* *next */ - 0 , /* count */ - FALSE /* smartcard */ -}; - -/** - * Chained lists of X.509 and PGP end entity certificates - */ -static cert_t *certs = NULL; - -/** - * Free a pluto certificate - */ -void cert_free(cert_t *cert) -{ - if (cert) - { - certificate_t *certificate = cert->cert; - - if (certificate) - { - certificate->destroy(certificate); - } - free(cert); - } -} - -/** - * Add a pluto end entity certificate to the chained list - */ -cert_t* cert_add(cert_t *cert) -{ - certificate_t *certificate = cert->cert; - cert_t *c; - - lock_certs_and_keys("cert_add"); - - for (c = certs; c != NULL; c = c->next) - { - if (certificate->equals(certificate, c->cert)) - { /* already in chain, free cert */ - unlock_certs_and_keys("cert_add"); - cert_free(cert); - return c; - } - } - - /* insert new cert at the root of the chain */ - cert->next = certs; - certs = cert; - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" cert inserted") - ) - unlock_certs_and_keys("cert_add"); - return cert; -} - -/** - * Loads a X.509 or OpenPGP certificate - */ -cert_t* load_cert(char *filename, const char *label, x509_flag_t flags) -{ - cert_t *cert; - - cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT, - BUILD_FROM_FILE, filename, - BUILD_X509_FLAG, flags, - BUILD_END); - if (cert) - { - plog(" loaded %s certificate from '%s'", label, filename); - } - return cert; -} - -/** - * Loads a host certificate - */ -cert_t* load_host_cert(char *filename) -{ - char *path = concatenate_paths(HOST_CERT_PATH, filename); - - return load_cert(path, "host", X509_NONE); -} - -/** - * Loads a CA certificate - */ -cert_t* load_ca_cert(char *filename) -{ - char *path = concatenate_paths(CA_CERT_PATH, filename); - - return load_cert(path, "CA", X509_NONE); -} - -/** - * for each link pointing to the certificate increase the count by one - */ -void cert_share(cert_t *cert) -{ - if (cert != NULL) - { - cert->count++; - } -} - -/* release of a certificate decreases the count by one - * the certificate is freed when the counter reaches zero - */ -void cert_release(cert_t *cert) -{ - if (cert && --cert->count == 0) - { - cert_t **pp = &certs; - while (*pp != cert) - { - pp = &(*pp)->next; - } - *pp = cert->next; - cert_free(cert); - } -} - -/** - * Get a X.509 certificate with a given issuer found at a certain position - */ -cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, cert_t *chain) -{ - cert_t *cert = chain ? chain->next : certs; - - while (cert) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - - if (keyid.ptr ? same_keyid(keyid, authKeyID) : - certificate->has_issuer(certificate, issuer)) - { - return cert; - } - cert = cert->next; - } - return NULL; -} - -/** - * List all PGP end certificates in a chained list - */ -void list_pgp_end_certs(bool utc) -{ - cert_t *cert = certs; - time_t now = time(NULL); - bool first = TRUE; - - - while (cert != NULL) - { - certificate_t *certificate = cert->cert; - - if (certificate->get_type(certificate) == CERT_GPG) - { - time_t created, until; - public_key_t *key; - identification_t *userid = certificate->get_subject(certificate); - pgp_certificate_t *pgp_cert = (pgp_certificate_t*)certificate; - chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert); - - if (first) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of PGP End Entity Certificates:"); - first = false; - } - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " userid: '%Y'", userid); - whack_log(RC_COMMENT, " digest: %#B", &fingerprint); - - /* list validity */ - certificate->get_validity(certificate, &now, &created, &until); - whack_log(RC_COMMENT, " created: %T", &created, utc); - whack_log(RC_COMMENT, " until: %T %s%s", &until, utc, - check_expiry(until, CA_CERT_WARNING_INTERVAL, TRUE), - (until == TIME_32_BIT_SIGNED_MAX) ? " (expires never)":""); - - key = certificate->get_public_key(certificate); - if (key) - { - chunk_t keyid; - - whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", - key_type_names, key->get_type(key), - key->get_keysize(key), - has_private_key(cert)? ", has private key" : ""); - if (key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &keyid)) - { - whack_log(RC_COMMENT, " keyid: %#B", &keyid); - } - if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &keyid)) - { - whack_log(RC_COMMENT, " subjkey: %#B", &keyid); - } - } - } - cert = cert->next; - } -} - -/** - * List all X.509 end certificates in a chained list - */ -void list_x509_end_certs(bool utc) -{ - list_x509cert_chain("End Entity", certs, X509_NONE, utc); -} - -/** - * list all X.509 and OpenPGP end certificates - */ -void cert_list(bool utc) -{ - list_x509_end_certs(utc); - list_pgp_end_certs(utc); -} - diff --git a/src/pluto/certs.h b/src/pluto/certs.h deleted file mode 100644 index b31c4c3ed..000000000 --- a/src/pluto/certs.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Certificate support for IKE authentication - * Copyright (C) 2002-2009 Andreas Steffen - * - * HSR - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CERTS_H -#define _CERTS_H - -#include <credentials/keys/private_key.h> -#include <credentials/certificates/certificate.h> -#include <credentials/certificates/x509.h> - -#include <freeswan.h> - -#include "defs.h" - -/* path definitions for private keys, end certs, - * cacerts, attribute certs and crls - */ -#define PRIVATE_KEY_PATH IPSEC_CONFDIR "/ipsec.d/private" -#define HOST_CERT_PATH IPSEC_CONFDIR "/ipsec.d/certs" -#define CA_CERT_PATH IPSEC_CONFDIR "/ipsec.d/cacerts" -#define A_CERT_PATH IPSEC_CONFDIR "/ipsec.d/acerts" -#define AA_CERT_PATH IPSEC_CONFDIR "/ipsec.d/aacerts" -#define OCSP_CERT_PATH IPSEC_CONFDIR "/ipsec.d/ocspcerts" -#define CRL_PATH IPSEC_CONFDIR "/ipsec.d/crls" -#define REQ_PATH IPSEC_CONFDIR "/ipsec.d/reqs" - -/* advance warning of imminent expiry of - * cacerts, public keys, and crls - */ -#define CA_CERT_WARNING_INTERVAL 30 /* days */ -#define OCSP_CERT_WARNING_INTERVAL 30 /* days */ -#define PUBKEY_WARNING_INTERVAL 7 /* days */ -#define CRL_WARNING_INTERVAL 7 /* days */ -#define ACERT_WARNING_INTERVAL 1 /* day */ - -/* access structure for a pluto certificate */ - -typedef struct cert_t cert_t; - -struct cert_t { - certificate_t *cert; - cert_t *next; - int count; - bool smartcard; -}; - -/* used for initialization */ -extern const cert_t cert_empty; - -/* do not send certificate requests - * flag set in plutomain.c and used in ipsec_doi.c - */ -extern bool no_cr_send; - -extern cert_t* load_cert(char *filename, const char *label, x509_flag_t flags); -extern cert_t* load_host_cert(char *filename); -extern cert_t* load_ca_cert(char *filename); -extern cert_t* cert_add(cert_t *cert); -extern void cert_free(cert_t *cert); -extern void cert_share(cert_t *cert); -extern void cert_release(cert_t *cert); -extern void cert_list(bool utc); -extern cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, cert_t* chain); - -#endif /* _CERTS_H */ - - diff --git a/src/pluto/connections.c b/src/pluto/connections.c deleted file mode 100644 index 27cec40fc..000000000 --- a/src/pluto/connections.c +++ /dev/null @@ -1,4507 +0,0 @@ -/* information about connections between hosts and clients - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <string.h> -#include <stdio.h> -#include <stddef.h> -#include <stdlib.h> -#include <unistd.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ -#include <sys/queue.h> - -#include <freeswan.h> -#include "kameipsec.h" - -#include <hydra.h> -#include <credentials/certificates/ac.h> -#include <credentials/keys/private_key.h> - -#include "constants.h" -#include "defs.h" -#include "myid.h" -#include "x509.h" -#include "ca.h" -#include "crl.h" -#include "certs.h" -#include "ac.h" -#include "smartcard.h" -#include "fetch.h" -#include "connections.h" -#include "foodgroups.h" -#include "demux.h" -#include "state.h" -#include "timer.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "server.h" -#include "kernel.h" -#include "log.h" -#include "keys.h" -#include "adns.h" /* needs <resolv.h> */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "whack.h" -#include "alg_info.h" -#include "ike_alg.h" -#include "kernel_alg.h" -#include "nat_traversal.h" -#include "virtual.h" -#include "whack_attribute.h" -#include "modecfg.h" - -static void flush_pending_by_connection(connection_t *c); /* forward */ - -static connection_t *connections = NULL; - -/* struct host_pair: a nexus of information about a pair of hosts. - * A host is an IP address, UDP port pair. This is a debatable choice: - * - should port be considered (no choice of port in standard)? - * - should ID be considered (hard because not always known)? - * - should IP address matter on our end (we don't know our end)? - * Only oriented connections are registered. - * Unoriented connections are kept on the unoriented_connections - * linked list (using hp_next). For them, host_pair is NULL. - */ - -struct host_pair { - struct { - ip_address addr; - u_int16_t port; /* host order */ - } me, him; - bool initial_connection_sent; - connection_t *connections; /* connections with this pair */ - struct pending *pending; /* awaiting Keying Channel */ - struct host_pair *next; -}; - -static struct host_pair *host_pairs = NULL; - -static connection_t *unoriented_connections = NULL; - -/** - * Check if an id was instantiated by assigning to it the current IP address - */ -bool his_id_was_instantiated(const connection_t *c) -{ - if (c->kind != CK_INSTANCE) - { - return FALSE; - } - if (id_is_ipaddr(c->spd.that.id)) - { - identification_t *host; - bool equal; - - host = identification_create_from_sockaddr((sockaddr_t*)&c->spd.that.host_addr); - equal = host->equals(host, c->spd.that.id); - host->destroy(host); - return equal; - } - else - { - return TRUE; - } -} - -/** - * Check to see that IDs of peers match - */ -bool same_peer_ids(const connection_t *c, const connection_t *d, - identification_t *his_id) -{ - return d->spd.this.id->equals(d->spd.this.id, c->spd.this.id) && - d->spd.that.id->equals(d->spd.that.id, - his_id ? his_id : c->spd.that.id); -} - -static struct host_pair *find_host_pair(const ip_address *myaddr, - u_int16_t myport, - const ip_address *hisaddr, - u_int16_t hisport) -{ - struct host_pair *p, *prev; - - /* default hisaddr to an appropriate any */ - if (hisaddr == NULL) - hisaddr = aftoinfo(addrtypeof(myaddr))->any; - - if (nat_traversal_enabled) - { - /** - * port is not relevant in host_pair. with nat_traversal we - * always use pluto_port (500) - */ - myport = pluto_port; - hisport = pluto_port; - } - - for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next) - { - if (sameaddr(&p->me.addr, myaddr) && p->me.port == myport - && sameaddr(&p->him.addr, hisaddr) && p->him.port == hisport) - { - if (prev) - { - prev->next = p->next; /* remove p from list */ - p->next = host_pairs; /* and stick it on front */ - host_pairs = p; - } - break; - } - } - return p; -} - -/* find head of list of connections with this pair of hosts */ -static connection_t *find_host_pair_connections(const ip_address *myaddr, - u_int16_t myport, - const ip_address *hisaddr, - u_int16_t hisport) -{ - struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport); - - if (nat_traversal_enabled && hp && hisaddr) - { - connection_t *c; - - for (c = hp->connections; c != NULL; c = c->hp_next) - { - if (c->spd.this.host_port == myport && c->spd.that.host_port == hisport) - return c; - } - return NULL; - } - return hp == NULL? NULL : hp->connections; -} - -static void connect_to_host_pair(connection_t *c) -{ - if (oriented(*c)) - { - struct host_pair *hp; - - ip_address his_addr = (c->spd.that.allow_any) - ? *aftoinfo(addrtypeof(&c->spd.that.host_addr))->any - : c->spd.that.host_addr; - - hp = find_host_pair(&c->spd.this.host_addr, c->spd.this.host_port - , &his_addr, c->spd.that.host_port); - - if (hp == NULL) - { - /* no suitable host_pair -- build one */ - hp = malloc_thing(struct host_pair); - hp->me.addr = c->spd.this.host_addr; - hp->him.addr = his_addr; - hp->me.port = nat_traversal_enabled ? pluto_port : c->spd.this.host_port; - hp->him.port = nat_traversal_enabled ? pluto_port : c->spd.that.host_port; - hp->initial_connection_sent = FALSE; - hp->connections = NULL; - hp->pending = NULL; - hp->next = host_pairs; - host_pairs = hp; - } - c->host_pair = hp; - c->hp_next = hp->connections; - hp->connections = c; - } - else - { - /* since this connection isn't oriented, we place it - * in the unoriented_connections list instead. - */ - c->host_pair = NULL; - c->hp_next = unoriented_connections; - unoriented_connections = c; - } -} - -/* find a connection by name. - * If strict, don't accept a CK_INSTANCE. - * Move the winner (if any) to the front. - * If none is found, and strict, a diagnostic is logged to whack. - */ -connection_t *con_by_name(const char *nm, bool strict) -{ - connection_t *p, *prev; - - for (prev = NULL, p = connections; ; prev = p, p = p->ac_next) - { - if (p == NULL) - { - if (strict) - whack_log(RC_UNKNOWN_NAME - , "no connection named \"%s\"", nm); - break; - } - if (streq(p->name, nm) - && (!strict || p->kind != CK_INSTANCE)) - { - if (prev) - { - prev->ac_next = p->ac_next; /* remove p from list */ - p->ac_next = connections; /* and stick it on front */ - connections = p; - } - break; - } - } - return p; -} - -void release_connection(connection_t *c, bool relations) -{ - if (c->kind == CK_INSTANCE) - { - /* This does everything we need. - * Note that we will be called recursively by delete_connection, - * but kind will be CK_GOING_AWAY. - */ - delete_connection(c, relations); - } - else - { - flush_pending_by_connection(c); - delete_states_by_connection(c, relations); - unroute_connection(c); - } -} - -/* Delete a connection */ - -#define list_rm(etype, enext, e, ehead) { \ - etype **ep; \ - for (ep = &(ehead); *ep != (e); ep = &(*ep)->enext) \ - passert(*ep != NULL); /* we must not come up empty-handed */ \ - *ep = (e)->enext; \ - } - - -void delete_connection(connection_t *c, bool relations) -{ - modecfg_attribute_t *ca; - connection_t *old_cur_connection; - identification_t *client_id; - - old_cur_connection = cur_connection == c? NULL : cur_connection; -#ifdef DEBUG - lset_t old_cur_debugging = cur_debugging; -#endif - - set_cur_connection(c); - - /* Must be careful to avoid circularity: - * we mark c as going away so it won't get deleted recursively. - */ - passert(c->kind != CK_GOING_AWAY); - if (c->kind == CK_INSTANCE) - { - plog("deleting connection \"%s\" instance with peer %s {isakmp=#%lu/ipsec=#%lu}" - , c->name - , ip_str(&c->spd.that.host_addr) - , c->newest_isakmp_sa, c->newest_ipsec_sa); - c->kind = CK_GOING_AWAY; - } - else - { - plog("deleting connection"); - } - release_connection(c, relations); /* won't delete c */ - - if (c->kind == CK_GROUP) - { - delete_group(c); - } - - /* free up any logging resources */ - perpeer_logfree(c); - - /* find and delete c from connections list */ - list_rm(connection_t, ac_next, c, connections); - cur_connection = old_cur_connection; - - /* find and delete c from the host pair list */ - if (c->host_pair == NULL) - { - if (c->ikev1) - { - list_rm(connection_t, hp_next, c, unoriented_connections); - } - } - else - { - struct host_pair *hp = c->host_pair; - - list_rm(connection_t, hp_next, c, hp->connections); - c->host_pair = NULL; /* redundant, but safe */ - - /* if there are no more connections with this host_pair - * and we haven't even made an initial contact, let's delete - * this guy in case we were created by an attempted DOS attack. - */ - if (hp->connections == NULL - && !hp->initial_connection_sent) - { - passert(hp->pending == NULL); /* ??? must deal with this! */ - list_rm(struct host_pair, next, hp, host_pairs); - free(hp); - } - } - if (c->kind != CK_GOING_AWAY) - { - free(c->spd.that.virt); - } - - client_id = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id; - - /* release virtual IP address lease if any */ - if (c->spd.that.modecfg && c->spd.that.pool && - !c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) - { - hydra->attributes->release_address(hydra->attributes, c->spd.that.pool, - c->spd.that.host_srcip, client_id); - } - - /* release requested attributes if any */ - if (c->requested) - { - c->requested->destroy_function(c->requested, - (void*)modecfg_attribute_destroy); - } - - /* release other attributes if any */ - if (c->attributes) - { - while (c->attributes->remove_last(c->attributes, (void **)&ca) == SUCCESS) - { - hydra->attributes->release(hydra->attributes, ca->handler, - client_id, ca->type, ca->value); - modecfg_attribute_destroy(ca); - } - c->attributes->destroy(c->attributes); - } - - if (c->kind != CK_GOING_AWAY) - { - whack_attr->del_pool(whack_attr, c->name); - } - - /* free internal data */ -#ifdef DEBUG - cur_debugging = old_cur_debugging; -#endif - free(c->name); - DESTROY_IF(c->xauth_identity); - DESTROY_IF(c->spd.this.id); - DESTROY_IF(c->spd.this.ca); - DESTROY_IF(c->spd.this.groups); - DESTROY_IF(c->spd.this.host_srcip); - free(c->spd.this.updown); - free(c->spd.this.pool); - DESTROY_IF(c->spd.that.id); - DESTROY_IF(c->spd.that.ca); - DESTROY_IF(c->spd.that.groups); - DESTROY_IF(c->spd.that.host_srcip); - free(c->spd.that.updown); - free(c->spd.that.pool); - if (c->requested_ca) - { - c->requested_ca->destroy_offset(c->requested_ca, - offsetof(identification_t, destroy)); - } -#ifdef ADNS - gw_delref(&c->gw_info); -#endif - lock_certs_and_keys("delete_connection"); - cert_release(c->spd.this.cert); - scx_release(c->spd.this.sc); - cert_release(c->spd.that.cert); - scx_release(c->spd.that.sc); - unlock_certs_and_keys("delete_connection"); - - alg_info_delref((struct alg_info **)&c->alg_info_esp); - alg_info_delref((struct alg_info **)&c->alg_info_ike); - - free(c); -} - -/* Delete connections with the specified name */ -void delete_connections_by_name(const char *name, bool strict) -{ - connection_t *c = con_by_name(name, strict); - - for (; c != NULL; c = con_by_name(name, FALSE)) - delete_connection(c, FALSE); -} - -void delete_every_connection(void) -{ - while (connections) - { - delete_connection(connections, TRUE); - } -} - -void release_dead_interfaces(void) -{ - struct host_pair *hp; - - for (hp = host_pairs; hp != NULL; hp = hp->next) - { - connection_t **pp - , *p; - - for (pp = &hp->connections; (p = *pp) != NULL; ) - { - if (p->interface->change == IFN_DELETE) - { - /* this connection's interface is going away */ - enum connection_kind k = p->kind; - - release_connection(p, TRUE); - - if (k <= CK_PERMANENT) - { - /* The connection should have survived release: - * move it to the unoriented_connections list. - */ - passert(p == *pp); - - p->interface = NULL; - - *pp = p->hp_next; /* advance *pp */ - p->host_pair = NULL; - p->hp_next = unoriented_connections; - unoriented_connections = p; - } - else - { - /* The connection should have vanished, - * but the previous connection remains. - */ - passert(p != *pp); - } - } - else - { - pp = &p->hp_next; /* advance pp */ - } - } - } -} - -/* adjust orientations of connections to reflect newly added interfaces */ -void check_orientations(void) -{ - /* try to orient all the unoriented connections */ - { - connection_t *c = unoriented_connections; - - unoriented_connections = NULL; - - while (c) - { - connection_t *nxt = c->hp_next; - - (void)orient(c); - connect_to_host_pair(c); - c = nxt; - } - } - - /* Check that no oriented connection has become double-oriented. - * In other words, the far side must not match one of our new interfaces. - */ - { - struct iface *i; - - for (i = interfaces; i != NULL; i = i->next) - { - if (i->change == IFN_ADD) - { - struct host_pair *hp; - - for (hp = host_pairs; hp != NULL; hp = hp->next) - { - if (sameaddr(&hp->him.addr, &i->addr) - && hp->him.port == pluto_port) - { - /* bad news: the whole chain of connections - * hanging off this host pair has both sides - * matching an interface. - * We'll get rid of them, using orient and - * connect_to_host_pair. But we'll be lazy - * and not ditch the host_pair itself (the - * cost of leaving it is slight and cannot - * be induced by a foe). - */ - connection_t *c = hp->connections; - - hp->connections = NULL; - while (c) - { - connection_t *nxt = c->hp_next; - - c->interface = NULL; - (void)orient(c); - connect_to_host_pair(c); - c = nxt; - } - } - } - } - } - } -} - -static err_t default_end(struct end *e, ip_address *dflt_nexthop) -{ - err_t ugh = NULL; - int af = addrtypeof(&e->host_addr); - - if (af != AF_INET && af != AF_INET6) - { - return "unknown address family in default_end"; - } - - /* default ID to IP (but only if not NO_IP -- WildCard) */ - if (e->id->get_type(e->id) == ID_ANY && !isanyaddr(&e->host_addr)) - { - e->id->destroy(e->id); - e->id = identification_create_from_sockaddr((sockaddr_t*)&e->host_addr); - e->has_id_wildcards = FALSE; - } - - /* default nexthop to other side */ - if (isanyaddr(&e->host_nexthop)) - { - e->host_nexthop = *dflt_nexthop; - } - - /* default client to subnet containing only self - * XXX This may mean that the client's address family doesn't match - * tunnel_addr_family. - */ - if (!e->has_client) - { - ugh = addrtosubnet(&e->host_addr, &e->client); - } - return ugh; -} - -/* Format the topology of a connection end, leaving out defaults. - * Largest left end looks like: client === host : port [ host_id ] --- hop - * Note: if that==NULL, skip nexthop - * Returns strlen of formated result (length excludes NUL at end). - */ -size_t format_end(char *buf, size_t buf_len, const struct end *this, - const struct end *that, bool is_left, lset_t policy) -{ - char client[BUF_LEN]; - const char *client_sep = ""; - char protoport[sizeof(":255/65535")]; - const char *host = NULL; - char host_space[ADDRTOT_BUF]; - char host_port[sizeof(":65535")]; - char host_id[BUF_LEN + 2]; - char hop[ADDRTOT_BUF]; - const char *hop_sep = ""; - const char *open_brackets = ""; - const char *close_brackets = ""; - - if (isanyaddr(&this->host_addr)) - { - switch (policy & (POLICY_GROUP | POLICY_OPPO)) - { - case POLICY_GROUP: - host = "%group"; - break; - case POLICY_OPPO: - host = "%opportunistic"; - break; - case POLICY_GROUP | POLICY_OPPO: - host = "%opportunisticgroup"; - break; - default: - host = "%any"; - break; - } - } - - client[0] = '\0'; - - if (is_virtual_end(this) && isanyaddr(&this->host_addr)) - { - host = "%virtual"; - } - - /* [client===] */ - if (this->has_client) - { - ip_address client_net, client_mask; - - networkof(&this->client, &client_net); - maskof(&this->client, &client_mask); - client_sep = "==="; - - /* {client_subnet_wildcard} */ - if (this->has_client_wildcard) - { - open_brackets = "{"; - close_brackets = "}"; - } - - if (isanyaddr(&client_net) && isanyaddr(&client_mask) - && (policy & (POLICY_GROUP | POLICY_OPPO))) - { - client_sep = ""; /* boring case */ - } - else if (subnetisnone(&this->client)) - { - strncpy(client, "?", sizeof(client)); - } - else - { - subnettot(&this->client, 0, client, sizeof(client)); - } - } - else if (this->modecfg && this->host_srcip->is_anyaddr(this->host_srcip)) - { - /* we are mode config client, or a server with a pool */ - client_sep = "==="; - client[0] = '%'; - strncpy(client+1, this->pool ?: "modecfg", sizeof(client)-1); - } - - /* host */ - if (host == NULL) - { - addrtot(&this->host_addr, 0, host_space, sizeof(host_space)); - host = host_space; - } - - host_port[0] = '\0'; - if (this->host_port != IKE_UDP_PORT) - { - snprintf(host_port, sizeof(host_port), ":%u", this->host_port); - } - - /* payload portocol and port */ - protoport[0] = '\0'; - if (this->has_port_wildcard) - { - snprintf(protoport, sizeof(protoport), ":%u/%%any", this->protocol); - } - else if (this->port || this->protocol) - { - snprintf(protoport, sizeof(protoport), ":%u/%u", this->protocol - , this->port); - } - - /* id */ - snprintf(host_id, sizeof(host_id), "[%Y]", this->id); - - /* [---hop] */ - hop[0] = '\0'; - hop_sep = ""; - if (that && !sameaddr(&this->host_nexthop, &that->host_addr)) - { - addrtot(&this->host_nexthop, 0, hop, sizeof(hop)); - hop_sep = "---"; - } - - if (is_left) - { - snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s%s" - , open_brackets, client, close_brackets, client_sep - , this->allow_any? "%":"" - , host, host_port, host_id, protoport - , hop_sep, hop); - } - else - { - snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s%s" - , hop, hop_sep - , this->allow_any? "%":"" - , host, host_port, host_id, protoport, client_sep - , open_brackets, client, close_brackets); - } - return strlen(buf); -} - -/* format topology of a connection. - * Two symmetric ends separated by ... - */ -#define CONNECTION_BUF (2 * (END_BUF - 1) + 4) - -static size_t format_connection(char *buf, size_t buf_len, - const connection_t *c, - struct spd_route *sr) -{ - size_t w = format_end(buf, buf_len, &sr->this, &sr->that, TRUE, LEMPTY); - - w += snprintf(buf + w, buf_len - w, "..."); - return w + format_end(buf + w, buf_len - w, &sr->that, &sr->this, FALSE, c->policy); -} - -static void unshare_connection_strings(connection_t *c) -{ - c->name = clone_str(c->name); - if (c->xauth_identity) - { - c->xauth_identity = c->xauth_identity->clone(c->xauth_identity); - } - c->spd.this.id = c->spd.this.id->clone(c->spd.this.id); - c->spd.this.pool = clone_str(c->spd.this.pool); - c->spd.this.updown = clone_str(c->spd.this.updown); - c->spd.this.host_srcip = c->spd.this.host_srcip->clone(c->spd.this.host_srcip); - scx_share(c->spd.this.sc); - cert_share(c->spd.this.cert); - if (c->spd.this.ca) - { - c->spd.this.ca = c->spd.this.ca->clone(c->spd.this.ca); - } - if (c->spd.this.groups) - { - c->spd.this.groups = c->spd.this.groups->get_ref(c->spd.this.groups); - } - c->spd.that.id = c->spd.that.id->clone(c->spd.that.id); - c->spd.that.pool = clone_str(c->spd.that.pool); - c->spd.that.updown = clone_str(c->spd.that.updown); - c->spd.that.host_srcip = c->spd.that.host_srcip->clone(c->spd.that.host_srcip); - scx_share(c->spd.that.sc); - cert_share(c->spd.that.cert); - if (c->spd.that.ca) - { - c->spd.that.ca = c->spd.that.ca->clone(c->spd.that.ca); - } - if (c->spd.that.groups) - { - c->spd.that.groups = c->spd.that.groups->get_ref(c->spd.that.groups); - } - - /* increment references to algo's */ - alg_info_addref((struct alg_info *)c->alg_info_esp); - alg_info_addref((struct alg_info *)c->alg_info_ike); -} - -static void load_end_certificate(char *filename, struct end *dst) -{ - time_t notBefore, notAfter; - cert_t *cert = NULL; - certificate_t *certificate; - bool cached_cert = FALSE; - - /* initialize end certificate */ - dst->cert = NULL; - - /* initialize smartcard info record */ - dst->sc = NULL; - - if (filename) - { - if (scx_on_smartcard(filename)) - { - /* load cert from smartcard */ - cert = scx_load_cert(filename, &dst->sc, &cached_cert); - } - else - { - /* load cert from file */ - cert = load_host_cert(filename); - } - } - - if (cert) - { - certificate = cert->cert; - - if (dst->id->get_type(dst->id) == ID_ANY || - !certificate->has_subject(certificate, dst->id)) - { - plog( " id '%Y' not confirmed by certificate, defaulting to '%Y'", - dst->id, certificate->get_subject(certificate)); - dst->id->destroy(dst->id); - dst->id = certificate->get_subject(certificate); - dst->id = dst->id->clone(dst->id); - } - - if (cached_cert) - { - dst->cert = cert; - } - else - { - if (!certificate->get_validity(certificate, NULL, ¬Before, ¬After)) - { - plog("certificate is invalid (valid from %T to %T)", - ¬Before, FALSE, ¬After, FALSE); - cert_free(cert); - return; - } - DBG(DBG_CONTROL, - DBG_log("certificate is valid") - ) - add_public_key_from_cert(cert, notAfter, DAL_LOCAL); - dst->cert = cert_add(cert); - } - certificate = dst->cert->cert; - - /* if no CA is defined, use issuer as default */ - if (dst->ca == NULL && certificate->get_type(certificate) == CERT_X509) - { - identification_t *issuer; - - issuer = certificate->get_issuer(certificate); - dst->ca = issuer->clone(issuer); - } - - /* cache the certificate that was last retrieved from the smartcard */ - if (dst->sc) - { - if (!dst->sc->last_cert || - !certificate->equals(certificate, dst->sc->last_cert->cert)) - { - lock_certs_and_keys("load_end_certificates"); - cert_release(dst->sc->last_cert); - dst->sc->last_cert = dst->cert; - cert_share(dst->cert); - unlock_certs_and_keys("load_end_certificates"); - } - time(&dst->sc->last_load); - } - } - scx_share(dst->sc); - cert_share(dst->cert); -} - -static bool extract_end(struct end *dst, const whack_end_t *src, - const char *name, bool is_left) -{ - bool same_ca = FALSE; - - dst->is_left = is_left; - dst->id = identification_create_from_string(src->id); - dst->ca = NULL; - - /* decode CA distinguished name, if any */ - if (src->ca) - { - if streq(src->ca, "%same") - { - same_ca = TRUE; - } - else if (!streq(src->ca, "%any")) - { - dst->ca = identification_create_from_string(src->ca); - if (dst->ca->get_type(dst->ca) != ID_DER_ASN1_DN) - { - plog("bad CA string '%s', ignored", src->ca); - dst->ca->destroy(dst->ca); - dst->ca = NULL; - } - } - } - - /* load local end certificate and extract ID, if any */ - load_end_certificate(src->cert, dst); - - /* does id has wildcards? */ - dst->has_id_wildcards = dst->id->contains_wildcards(dst->id); - - /* decode group attributes, if any */ - if (src->groups) - { - dst->groups = ietf_attributes_create_from_string(src->groups); - } - - /* the rest is simple copying of corresponding fields */ - dst->host_addr = src->host_addr; - dst->host_nexthop = src->host_nexthop; - dst->host_srcip = host_create_from_sockaddr((sockaddr_t*)&src->host_srcip); - dst->has_natip = src->has_natip; - dst->client = src->client; - dst->protocol = src->protocol; - dst->port = src->port; - dst->has_port_wildcard = src->has_port_wildcard; - dst->key_from_DNS_on_demand = src->key_from_DNS_on_demand; - dst->has_client = src->has_client; - dst->has_client_wildcard = src->has_client_wildcard; - dst->modecfg = src->modecfg; - dst->hostaccess = src->hostaccess; - dst->allow_any = src->allow_any; - dst->sendcert = src->sendcert; - dst->updown = clone_str(src->updown); - dst->host_port = src->host_port; - - /* if the sourceip netmask is zero a named pool exists */ - if (src->sourceip_mask == 0) - { - dst->pool = clone_str(src->sourceip); - } - - /* if host sourceip is defined but no client is present - * behind the host then set client to sourceip/32 - */ - if (!dst->host_srcip->is_anyaddr(dst->host_srcip) && - !dst->has_natip && !dst->has_client) - { - ip_address addr; - err_t ugh; - - addr = *(ip_address*)dst->host_srcip->get_sockaddr(dst->host_srcip); - ugh = addrtosubnet(&addr, &dst->client); - - if (ugh) - { - plog("could not assign host sourceip to client subnet"); - } - else - { - dst->has_client = TRUE; - } - } - return same_ca; -} - -static bool check_connection_end(const whack_end_t *this, - const whack_end_t *that, - const whack_message_t *wm) -{ - if (wm->addr_family != addrtypeof(&this->host_addr) - || wm->addr_family != addrtypeof(&this->host_nexthop) - || (this->has_client? wm->tunnel_addr_family : wm->addr_family) - != subnettypeof(&this->client) - || subnettypeof(&this->client) != subnettypeof(&that->client)) - { - /* this should have been diagnosed by whack, so we need not be clear - * !!! overloaded use of RC_CLASH - */ - loglog(RC_CLASH, "address family inconsistency in connection"); - return FALSE; - } - - if (isanyaddr(&that->host_addr)) - { - /* other side is wildcard: we must check if other conditions met */ - if (isanyaddr(&this->host_addr)) - { - loglog(RC_ORIENT, "connection must specify host IP address for our side"); - return FALSE; - } - } - - if (this->virt && (!isanyaddr(&this->host_addr) || this->has_client)) - { - loglog(RC_CLASH, - "virtual IP must only be used with %%any and without client"); - return FALSE; - } - - return TRUE; /* happy */ -} - -connection_t *find_connection_by_reqid(uint32_t reqid) -{ - connection_t *c; - - reqid &= ~3; - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->spd.reqid == reqid) - { - return c; - } - } - - return NULL; -} - -static uint32_t gen_reqid(void) -{ - uint32_t start; - static uint32_t reqid = IPSEC_MANUAL_REQID_MAX & ~3; - - start = reqid; - do { - reqid += 4; - if (reqid == 0) - { - reqid = (IPSEC_MANUAL_REQID_MAX & ~3) + 4; - } - if (!find_connection_by_reqid(reqid)) - { - return reqid; - } - } while (reqid != start); - - exit_log("unable to allocate reqid"); - return 0; /* never reached ... */ -} - -void add_connection(const whack_message_t *wm) -{ - if (con_by_name(wm->name, FALSE) != NULL) - { - loglog(RC_DUPNAME, "attempt to redefine connection \"%s\"", wm->name); - } - else if (wm->right.protocol != wm->left.protocol) - { - /* this should haven been diagnosed by whack - * !!! overloaded use of RC_CLASH - */ - loglog(RC_CLASH, "the protocol must be the same for leftport and rightport"); - } - else if (check_connection_end(&wm->right, &wm->left, wm) - && check_connection_end(&wm->left, &wm->right, wm)) - { - bool same_rightca, same_leftca; - connection_t *c = malloc_thing(connection_t); - - zero(c); - c->name = clone_str(wm->name); - c->ikev1 = wm->ikev1; - c->policy = wm->policy; - - if ((c->policy & POLICY_COMPRESS) && !can_do_IPcomp) - { - loglog(RC_COMMENT - , "ignoring --compress in \"%s\" because kernel does not support IPCOMP" - , c->name); - } - - if (wm->esp) - { - DBG(DBG_CONTROL, - DBG_log("from whack: got --esp=%s", wm->esp ? wm->esp: "NULL") - ) - c->alg_info_esp = alg_info_esp_create_from_str(wm->esp? wm->esp : ""); - - DBG(DBG_CRYPT|DBG_CONTROL, - static char buf[BUF_LEN]="<NULL>"; - - if (c->alg_info_esp) - { - alg_info_snprint(buf, sizeof(buf) - ,(struct alg_info *)c->alg_info_esp); - } - DBG_log("esp proposal: %s", buf); - ) - if (c->alg_info_esp) - { - if (c->alg_info_esp->alg_info_cnt == 0) - { - loglog(RC_LOG_SERIOUS, "got 0 esp transforms"); - } - } - else - { - loglog(RC_LOG_SERIOUS, "syntax error in esp string"); - } - } - - if (wm->ike) - { - DBG(DBG_CONTROL, - DBG_log("from whack: got --ike=%s", wm->ike ? wm->ike: "NULL") - ) - c->alg_info_ike= alg_info_ike_create_from_str(wm->ike? wm->ike : ""); - - DBG(DBG_CRYPT|DBG_CONTROL, - static char buf[BUF_LEN]="<NULL>"; - - if (c->alg_info_ike) - { - alg_info_snprint(buf, sizeof(buf) - , (struct alg_info *)c->alg_info_ike); - } - DBG_log("ike proposal: %s", buf); - ) - if (c->alg_info_ike) - { - if (c->alg_info_ike->alg_info_cnt == 0) - { - loglog(RC_LOG_SERIOUS, "got 0 ike transforms"); - } - } - else - { - loglog(RC_LOG_SERIOUS, "syntax error in ike string"); - } - } - - if (wm->xauth_identity) - { - c->xauth_identity - = identification_create_from_string(wm->xauth_identity); - } - - c->sa_ike_life_seconds = wm->sa_ike_life_seconds; - c->sa_ipsec_life_seconds = wm->sa_ipsec_life_seconds; - c->sa_rekey_margin = wm->sa_rekey_margin; - c->sa_rekey_fuzz = wm->sa_rekey_fuzz; - c->sa_keying_tries = wm->sa_keying_tries; - - /* RFC 3706 DPD */ - c->dpd_delay = wm->dpd_delay; - c->dpd_timeout = wm->dpd_timeout; - c->dpd_action = wm->dpd_action; - - c->addr_family = wm->addr_family; - c->tunnel_addr_family = wm->tunnel_addr_family; - - c->requested_ca = NULL; - same_leftca = extract_end(&c->spd.this, &wm->left, wm->name, TRUE); - same_rightca = extract_end(&c->spd.that, &wm->right, wm->name, FALSE); - - if (same_rightca && c->spd.this.ca) - { - c->spd.that.ca = c->spd.this.ca->clone(c->spd.this.ca); - } - else if (same_leftca && c->spd.that.ca) - { - c->spd.this.ca = c->spd.that.ca->clone(c->spd.that.ca); - } - - default_end(&c->spd.this, &c->spd.that.host_addr); - default_end(&c->spd.that, &c->spd.this.host_addr); - - /* force any wildcard host IP address, any wildcard subnet - * or any wildcard ID to that end - */ - if (isanyaddr(&c->spd.this.host_addr) || c->spd.this.has_client_wildcard - || c->spd.this.has_port_wildcard || c->spd.this.has_id_wildcards - || c->spd.this.allow_any) - { - struct end t = c->spd.this; - - c->spd.this = c->spd.that; - c->spd.that = t; - } - - c->spd.next = NULL; - c->spd.reqid = wm->reqid ?: gen_reqid(); - - c->spd.mark_in.value = wm->mark_in.value; - c->spd.mark_in.mask = wm->mark_in.mask; - c->spd.mark_out.value = wm->mark_out.value; - c->spd.mark_out.mask = wm->mark_out.mask; - - /* set internal fields */ - c->instance_serial = 0; - c->ac_next = connections; - connections = c; - c->interface = NULL; - c->spd.routing = RT_UNROUTED; - c->newest_isakmp_sa = SOS_NOBODY; - c->newest_ipsec_sa = SOS_NOBODY; - c->spd.eroute_owner = SOS_NOBODY; - - if (c->policy & POLICY_GROUP) - { - c->kind = CK_GROUP; - add_group(c); - } - else if ((isanyaddr(&c->spd.that.host_addr) && !NEVER_NEGOTIATE(c->policy)) - || c->spd.that.has_client_wildcard || c->spd.that.has_port_wildcard - || c->spd.that.has_id_wildcards || c->spd.that.allow_any) - { - /* Opportunistic or Road Warrior or wildcard client subnet - * or wildcard ID */ - c->kind = CK_TEMPLATE; - } - else - { - c->kind = CK_PERMANENT; - } - set_policy_prio(c); /* must be after kind is set */ - -#ifdef DEBUG - c->extra_debugging = wm->debugging; -#endif - - c->gw_info = NULL; - - passert(!(wm->left.virt && wm->right.virt)); - if (wm->left.virt || wm->right.virt) - { - passert(isanyaddr(&c->spd.that.host_addr)); - c->spd.that.virt = create_virtual(c, - wm->left.virt ? wm->left.virt : wm->right.virt); - if (c->spd.that.virt) - c->spd.that.has_client = TRUE; - } - - (void)orient(c); - - /* if rightsourceip defines a subnet then create an in-memory pool */ - if (whack_attr->add_pool(whack_attr, c->name, - c->spd.this.is_left ? &wm->right : &wm->left)) - { - c->spd.that.pool = clone_str(c->name); - c->spd.that.modecfg = TRUE; - c->spd.that.has_client = FALSE; - /* reset the host_srcip so that it gets assigned in modecfg */ - DESTROY_IF(c->spd.that.host_srcip); - c->spd.that.host_srcip = host_create_any(AF_INET); - } - - if (c->ikev1) - { - connect_to_host_pair(c); - } - - /* log all about this connection */ - plog("added connection description \"%s\"", c->name); - DBG(DBG_CONTROL, - char topo[BUF_LEN]; - - (void) format_connection(topo, sizeof(topo), c, &c->spd); - - DBG_log("%s", topo); - - /* Make sure that address families can be correctly inferred - * from printed ends. - */ - passert(c->addr_family == addrtypeof(&c->spd.this.host_addr) - && c->addr_family == addrtypeof(&c->spd.this.host_nexthop) - && (c->spd.this.has_client? c->tunnel_addr_family : c->addr_family) - == subnettypeof(&c->spd.this.client) - - && c->addr_family == addrtypeof(&c->spd.that.host_addr) - && c->addr_family == addrtypeof(&c->spd.that.host_nexthop) - && (c->spd.that.has_client? c->tunnel_addr_family : c->addr_family) - == subnettypeof(&c->spd.that.client)); - - DBG_log("ike_life: %lus; ipsec_life: %lus; rekey_margin: %lus;" - " rekey_fuzz: %lu%%; keyingtries: %lu; policy: %s" - , (unsigned long) c->sa_ike_life_seconds - , (unsigned long) c->sa_ipsec_life_seconds - , (unsigned long) c->sa_rekey_margin - , (unsigned long) c->sa_rekey_fuzz - , (unsigned long) c->sa_keying_tries - , prettypolicy(c->policy)); - ); - } -} - -/* Derive a template connection from a group connection and target. - * Similar to instantiate(). Happens at whack --listen. - * Returns name of new connection. May be NULL. - * Caller is responsible for freeing. - */ -char *add_group_instance(connection_t *group, const ip_subnet *target) -{ - char namebuf[100], targetbuf[SUBNETTOT_BUF]; - connection_t *t; - char *name = NULL; - - passert(group->kind == CK_GROUP); - passert(oriented(*group)); - - /* manufacture a unique name for this template */ - subnettot(target, 0, targetbuf, sizeof(targetbuf)); - snprintf(namebuf, sizeof(namebuf), "%s#%s", group->name, targetbuf); - - if (con_by_name(namebuf, FALSE) != NULL) - { - loglog(RC_DUPNAME, "group name + target yields duplicate name \"%s\"" - , namebuf); - } - else - { - t = clone_thing(*group); - t->name = namebuf; - unshare_connection_strings(t); - name = clone_str(t->name); - t->spd.that.client = *target; - t->policy &= ~(POLICY_GROUP | POLICY_GROUTED); - t->kind = isanyaddr(&t->spd.that.host_addr) && !NEVER_NEGOTIATE(t->policy) - ? CK_TEMPLATE : CK_INSTANCE; - - /* reset log file info */ - t->log_file_name = NULL; - t->log_file = NULL; - t->log_file_err = FALSE; - - t->spd.reqid = gen_reqid(); - - if (t->spd.that.virt) - { - DBG_log("virtual_ip not supported in group instance"); - t->spd.that.virt = NULL; - } - - /* add to connections list */ - t->ac_next = connections; - connections = t; - - /* same host_pair as parent: stick after parent on list */ - group->hp_next = t; - - /* route if group is routed */ - if (group->policy & POLICY_GROUTED) - { - if (!trap_connection(t)) - whack_log(RC_ROUTE, "could not route"); - } - } - return name; -} - -/* an old target has disappeared for a group: delete instance */ -void remove_group_instance(const connection_t *group USED_BY_DEBUG, - const char *name) -{ - passert(group->kind == CK_GROUP); - passert(oriented(*group)); - - delete_connections_by_name(name, FALSE); -} - -/* Common part of instantiating a Road Warrior or Opportunistic connection. - * his_id can be used to carry over an ID discovered in Phase 1. - * It must not disagree with the one in c, but if that is unspecified, - * the new connection will use his_id. - * If his_id is NULL, and c.that.id is uninstantiated (ID_ANY), the - * new connection will continue to have an uninstantiated that.id. - * Note: instantiation does not affect port numbers. - * - * Note that instantiate can only deal with a single SPD/eroute. - */ -static connection_t *instantiate(connection_t *c, const ip_address *him, - u_int16_t his_port, identification_t *his_id) -{ - connection_t *d; - - passert(c->kind == CK_TEMPLATE); - passert(c->spd.next == NULL); - - c->instance_serial++; - d = clone_thing(*c); - d->spd.that.allow_any = FALSE; - - if (his_id) - { - d->spd.that.id = his_id; - d->spd.that.has_id_wildcards = FALSE; - } - unshare_connection_strings(d); - if (d->spd.this.groups) - { - d->spd.this.groups = d->spd.this.groups->get_ref(d->spd.this.groups); - } - if (d->spd.that.groups) - { - d->spd.that.groups = d->spd.that.groups->get_ref(d->spd.that.groups); - } - d->kind = CK_INSTANCE; - - passert(oriented(*d)); - d->spd.that.host_addr = *him; - setportof(htons(c->spd.that.port), &d->spd.that.host_addr); - - if (his_port) d->spd.that.host_port = his_port; - - default_end(&d->spd.that, &d->spd.this.host_addr); - - /* We cannot guess what our next_hop should be, but if it was - * explicitly specified as 0.0.0.0, we set it to be him. - * (whack will not allow nexthop to be elided in RW case.) - */ - default_end(&d->spd.this, &d->spd.that.host_addr); - d->spd.next = NULL; - d->spd.reqid = gen_reqid(); - - /* set internal fields */ - d->ac_next = connections; - connections = d; - d->spd.routing = RT_UNROUTED; - d->newest_isakmp_sa = SOS_NOBODY; - d->newest_ipsec_sa = SOS_NOBODY; - d->spd.eroute_owner = SOS_NOBODY; - - /* reset log file info */ - d->log_file_name = NULL; - d->log_file = NULL; - d->log_file_err = FALSE; - - connect_to_host_pair(d); - - if (sameaddr(&d->spd.that.host_addr, &d->spd.this.host_nexthop)) - { - d->spd.this.host_nexthop = *him; - } - return d; -} - -connection_t *rw_instantiate(connection_t *c, const ip_address *him, - u_int16_t his_port, const ip_subnet *his_net, - identification_t *his_id) -{ - connection_t *d = instantiate(c, him, his_port, his_id); - - if (d && his_net && is_virtual_connection(c)) - { - d->spd.that.client = *his_net; - d->spd.that.virt = NULL; - if (subnetishost(his_net) && addrinsubnet(him, his_net)) - d->spd.that.has_client = FALSE; - } - - if (d->policy & POLICY_OPPO) - { - /* This must be before we know the client addresses. - * Fill in one that is impossible. This prevents anyone else from - * trying to use this connection to get to a particular client - */ - d->spd.that.client = *aftoinfo(subnettypeof(&d->spd.that.client))->none; - } - DBG(DBG_CONTROL - , DBG_log("instantiated \"%s\" for %s" , d->name, ip_str(him))); - return d; -} - -#ifdef ADNS - -connection_t *oppo_instantiate(connection_t *c, const ip_address *him, - identification_t *his_id, struct gw_info *gw, - const ip_address *our_client USED_BY_DEBUG, - const ip_address *peer_client) -{ - connection_t *d = instantiate(c, him, 0, his_id); - - passert(d->spd.next == NULL); - - /* fill in our client side */ - if (d->spd.this.has_client) - { - /* there was a client in the abstract connection - * so we demand that the required client is within that subnet. - */ - passert(addrinsubnet(our_client, &d->spd.this.client)); - happy(addrtosubnet(our_client, &d->spd.this.client)); - /* opportunistic connections do not use port selectors */ - setportof(0, &d->spd.this.client.addr); - } - else - { - /* there was no client in the abstract connection - * so we demand that the required client be the host - */ - passert(sameaddr(our_client, &d->spd.this.host_addr)); - } - - /* fill in peer's client side. - * If the client is the peer, excise the client from the connection. - */ - passert((d->policy & POLICY_OPPO) - && addrinsubnet(peer_client, &d->spd.that.client)); - happy(addrtosubnet(peer_client, &d->spd.that.client)); - /* opportunistic connections do not use port selectors */ - setportof(0, &d->spd.that.client.addr); - - if (sameaddr(peer_client, &d->spd.that.host_addr)) - d->spd.that.has_client = FALSE; - - passert(d->gw_info == NULL); - gw_addref(gw); - d->gw_info = gw; - - /* Adjust routing if something is eclipsing c. - * It must be a %hold for us (hard to passert this). - * If there was another instance eclipsing, we'd be using it. - */ - if (c->spd.routing == RT_ROUTED_ECLIPSED) - d->spd.routing = RT_ROUTED_PROSPECTIVE; - - /* Remember if the template is routed: - * if so, this instance applies for initiation - * even if it is created for responding. - */ - if (routed(c->spd.routing)) - d->instance_initiation_ok = TRUE; - - DBG(DBG_CONTROL, - char topo[BUF_LEN]; - - (void) format_connection(topo, sizeof(topo), d, &d->spd); - DBG_log("instantiated \"%s\": %s", d->name, topo); - ); - return d; -} - -#endif /* ADNS */ - -/* priority formatting */ -void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]) -{ - if (pp == BOTTOM_PRIO) - { - snprintf(buf, POLICY_PRIO_BUF, "0"); - } - else - { - snprintf(buf, POLICY_PRIO_BUF, "%lu,%lu" - , pp>>16, (pp & ~(~(policy_prio_t)0 << 16)) >> 8); - } -} - -/* Format any information needed to identify an instance of a connection. - * Fills any needed information into buf which MUST be big enough. - * Road Warrior: peer's IP address - * Opportunistic: [" " myclient "==="] " ..." peer ["===" hisclient] '\0' - */ -static size_t fmt_client(const ip_subnet *client, const ip_address *gw, - const char *prefix, char buf[ADDRTOT_BUF]) -{ - if (subnetisaddr(client, gw)) - { - buf[0] = '\0'; /* compact denotation for "self" */ - } - else - { - char *ap; - - strcpy(buf, prefix); - ap = buf + strlen(prefix); - if (subnetisnone(client)) - strcpy(ap, "?"); /* unknown */ - else - subnettot(client, 0, ap, SUBNETTOT_BUF); - } - return strlen(buf); -} - -void fmt_conn_instance(const connection_t *c, char buf[CONN_INST_BUF]) -{ - char *p = buf; - - *p = '\0'; - - if (c->kind == CK_INSTANCE) - { - if (c->instance_serial != 0) - { - snprintf(p, CONN_INST_BUF, "[%lu]", c->instance_serial); - p += strlen(p); - } - - if (c->policy & POLICY_OPPO) - { - size_t w = fmt_client(&c->spd.this.client, &c->spd.this.host_addr, " ", p); - - p += w; - - strcpy(p, w == 0? " ..." : "=== ..."); - p += strlen(p); - - addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF); - p += strlen(p); - - (void) fmt_client(&c->spd.that.client, &c->spd.that.host_addr, "===", p); - } - else - { - *p++ = ' '; - addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF); -# - if (c->spd.that.host_port != pluto_port) - { - p += strlen(p); - sprintf(p, ":%d", c->spd.that.host_port); - } - } - } -} - -/* Find an existing connection for a trapped outbound packet. - * This is attempted before we bother with gateway discovery. - * + this connection is routed or instance_of_routed_template - * (i.e. approved for on-demand) - * + this subnet contains our_client (or we are our_client) - * + that subnet contains peer_client (or peer is peer_client) - * + don't care about Phase 1 IDs (we don't know) - * Note: result may still need to be instantiated. - * The winner has the highest policy priority. - * - * If there are several with that priority, we give preference to - * the first one that is an instance. - * - * See also build_outgoing_opportunistic_connection. - */ -connection_t *find_connection_for_clients(struct spd_route **srp, - const ip_address *our_client, - const ip_address *peer_client, - int transport_proto) -{ - connection_t *c = connections, *best = NULL; - policy_prio_t best_prio = BOTTOM_PRIO; - struct spd_route *sr; - struct spd_route *best_sr = NULL; - int our_port = ntohs(portof(our_client)); - int peer_port = ntohs(portof(peer_client)); - - passert(!isanyaddr(our_client) && !isanyaddr(peer_client)); -#ifdef DEBUG - if (DBGP(DBG_CONTROL)) - { - char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; - - addrtot(our_client, 0, ocb, sizeof(ocb)); - addrtot(peer_client, 0, pcb, sizeof(pcb)); - DBG_log("find_connection: " - "looking for policy for connection: %s:%d/%d -> %s:%d/%d" - , ocb, transport_proto, our_port, pcb, transport_proto, peer_port); - } -#endif /* DEBUG */ - - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->kind == CK_GROUP) - { - continue; - } - - for (sr = &c->spd; best!=c && sr; sr = sr->next) - { - if ((routed(sr->routing) || c->instance_initiation_ok) - && addrinsubnet(our_client, &sr->this.client) - && addrinsubnet(peer_client, &sr->that.client) - && addrinsubnet(peer_client, &sr->that.client) - && (!sr->this.protocol || transport_proto == sr->this.protocol) - && (!sr->this.port || our_port == sr->this.port) - && (!sr->that.port || peer_port == sr->that.port)) - { - char cib[CONN_INST_BUF]; - char cib2[CONN_INST_BUF]; - - policy_prio_t prio = 8 * (c->prio + (c->kind == CK_INSTANCE)) - + 2 * (sr->this.port == our_port) - + 2 * (sr->that.port == peer_port) - + (sr->this.protocol == transport_proto); - -#ifdef DEBUG - if (DBGP(DBG_CONTROL|DBG_CONTROLMORE)) - { - char c_ocb[SUBNETTOT_BUF], c_pcb[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, c_ocb, sizeof(c_ocb)); - subnettot(&c->spd.that.client, 0, c_pcb, sizeof(c_pcb)); - DBG_log("find_connection: conn \"%s\"%s has compatible peers: %s->%s [pri: %ld]" - , c->name - , (fmt_conn_instance(c, cib), cib) - , c_ocb, c_pcb, prio); - } -#endif /* DEBUG */ - - if (best == NULL) - { - best = c; - best_sr = sr; - best_prio = prio; - } - - DBG(DBG_CONTROLMORE, - DBG_log("find_connection: " - "comparing best \"%s\"%s [pri:%ld]{%p} (child %s) to \"%s\"%s [pri:%ld]{%p} (child %s)" - , best->name - , (fmt_conn_instance(best, cib), cib) - , best_prio - , best - , (best->policy_next ? best->policy_next->name : "none") - , c->name - , (fmt_conn_instance(c, cib2), cib2) - , prio - , c - , (c->policy_next ? c->policy_next->name : "none"))); - - if (prio > best_prio) - { - best = c; - best_sr = sr; - best_prio = prio; - } - } - } - } - - if (best && NEVER_NEGOTIATE(best->policy)) - { - best = NULL; - } - if (srp && best) - { - *srp = best_sr; - } - -#ifdef DEBUG - if (DBGP(DBG_CONTROL)) - { - if (best) - { - char cib[CONN_INST_BUF]; - DBG_log("find_connection: concluding with \"%s\"%s [pri:%ld]{%p} kind=%s" - , best->name - , (fmt_conn_instance(best, cib), cib) - , best_prio - , best - , enum_name(&connection_kind_names, best->kind)); - } else { - DBG_log("find_connection: concluding with empty"); - } - } -#endif /* DEBUG */ - - return best; -} - -#ifdef ADNS - -/* Find and instantiate a connection for an outgoing Opportunistic connection. - * We've already discovered its gateway. - * We look for a the connection such that: - * + this is one of our interfaces - * + this subnet contains our_client (or we are our_client) - * (we will specialize the client). We prefer the smallest such subnet. - * + that subnet contains peer_clent (we will specialize the client). - * We prefer the smallest such subnet. - * + is opportunistic - * + that peer is NO_IP - * + don't care about Phase 1 IDs (probably should be default) - * We could look for a connection that already had the desired peer - * (rather than NO_IP) specified, but it doesn't seem worth the - * bother. - * - * We look for the routed policy applying to the narrowest subnets. - * We only succeed if we find such a policy AND it is satisfactory. - * - * The body of the inner loop is a lot like that in - * find_connection_for_clients. In this case, we know the gateways - * that we need to instantiate an opportunistic connection. - */ -connection_t *build_outgoing_opportunistic_connection(struct gw_info *gw, - const ip_address *our_client, - const ip_address *peer_client) -{ - struct iface *p; - connection_t *best = NULL; - struct spd_route *sr, *bestsr; - char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; - - addrtot(our_client, 0, ocb, sizeof(ocb)); - addrtot(peer_client, 0, pcb, sizeof(pcb)); - - /* for each of our addresses... */ - for (p = interfaces; p != NULL; p = p->next) - { - /* go through those connections with our address and NO_IP as hosts - * We cannot know what port the peer would use, so we assume - * that it is pluto_port (makes debugging easier). - */ - connection_t *c = find_host_pair_connections(&p->addr, pluto_port, - (ip_address *)NULL, pluto_port); - - for (; c != NULL; c = c->hp_next) - { - DBG(DBG_OPPO, - DBG_log("checking %s", c->name)); - if (c->kind == CK_GROUP) - { - continue; - } - - for (sr = &c->spd; best!=c && sr; sr = sr->next) - { - if (routed(sr->routing) - && addrinsubnet(our_client, &sr->this.client) - && addrinsubnet(peer_client, &sr->that.client)) - { - if (best == NULL) - { - best = c; - break; - } - - DBG(DBG_OPPO, - DBG_log("comparing best %s to %s" - , best->name, c->name)); - - for (bestsr = &best->spd; best!=c && bestsr; bestsr=bestsr->next) - { - if (!subnetinsubnet(&bestsr->this.client, &sr->this.client) - || (samesubnet(&bestsr->this.client, &sr->this.client) - && !subnetinsubnet(&bestsr->that.client - , &sr->that.client))) - { - best = c; - } - } - } - } - } - } - - if (best == NULL || NEVER_NEGOTIATE(best->policy) || - (best->policy & POLICY_OPPO) == LEMPTY || best->kind != CK_TEMPLATE) - { - return NULL; - } - else - { - chunk_t encoding = gw->gw_id->get_encoding(gw->gw_id); - id_type_t type = gw->gw_id->get_type(gw->gw_id); - ip_address ip_addr; - - initaddr(encoding.ptr, encoding.len, - (type == ID_IPV4_ADDR) ? AF_INET : AF_INET6, &ip_addr); - - return oppo_instantiate(best, &ip_addr, NULL, gw, our_client, peer_client); - } -} - -#endif /* ADNS */ - -bool orient(connection_t *c) -{ - struct spd_route *sr; - - if (!oriented(*c)) - { - struct iface *p; - - for (sr = &c->spd; sr; sr = sr->next) - { - /* Note: this loop does not stop when it finds a match: - * it continues checking to catch any ambiguity. - */ - for (p = interfaces; p != NULL; p = p->next) - { - if (p->ike_float) - { - continue; - } - - for (;;) - { - /* check if this interface matches this end */ - if (sameaddr(&sr->this.host_addr, &p->addr) - && sr->this.host_port == pluto_port) - { - if (oriented(*c)) - { - if (c->interface == p) - loglog(RC_LOG_SERIOUS - , "both sides of \"%s\" are our interface %s!" - , c->name, p->rname); - else - loglog(RC_LOG_SERIOUS, "two interfaces match \"%s\" (%s, %s)" - , c->name, c->interface->rname, p->rname); - c->interface = NULL; /* withdraw orientation */ - return FALSE; - } - c->interface = p; - } - - /* done with this interface if it doesn't match that end */ - if (!(sameaddr(&sr->that.host_addr, &p->addr) - && sr->that.host_port == pluto_port)) - break; - - /* swap ends and try again. - * It is a little tricky to see that this loop will stop. - * Only continue if the far side matches. - * If both sides match, there is an error-out. - */ - { - struct end t = sr->this; - - sr->this = sr->that; - sr->that = t; - } - } - } - } - } - return oriented(*c); -} - -void initiate_connection(const char *name, int whackfd) -{ - connection_t *c = con_by_name(name, TRUE); - - if (c && c->ikev1) - { - set_cur_connection(c); - if (!oriented(*c)) - { - loglog(RC_ORIENT, "we have no ipsecN interface for either end of this connection"); - } - else if (NEVER_NEGOTIATE(c->policy)) - { - loglog(RC_INITSHUNT - , "cannot initiate an authby=never connection"); - } - else if (c->kind != CK_PERMANENT && !c->spd.that.allow_any) - { - if (isanyaddr(&c->spd.that.host_addr)) - loglog(RC_NOPEERIP, "cannot initiate connection without knowing peer IP address"); - else - loglog(RC_WILDCARD, "cannot initiate connection with ID wildcards"); - } - else - { - /* do we have to prompt for a PIN code? */ - if (c->spd.this.sc && !c->spd.this.sc->valid && whackfd != NULL_FD) - { - scx_get_pin(c->spd.this.sc, whackfd); - } - if (c->spd.this.sc && !c->spd.this.sc->valid) - { - loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN"); - } - else - { - - if (c->spd.that.allow_any) - { - c = instantiate(c, &c->spd.that.host_addr, - c->spd.that.host_port, c->spd.that.id); - } - - /* We will only request an IPsec SA if policy isn't empty - * (ignoring Main Mode items). - * This is a fudge, but not yet important. - * If we are to proceed asynchronously, whackfd will be NULL_FD. - */ - c->policy |= POLICY_UP; - ipsecdoi_initiate(whackfd, c, c->policy, 1, SOS_NOBODY); - whackfd = NULL_FD; /* protect from close */ - } - } - reset_cur_connection(); - } - close_any(whackfd); -} - -/* (Possibly) Opportunistic Initiation: - * Knowing clients (single IP addresses), try to build an tunnel. - * This may involve discovering a gateway and instantiating an - * Opportunistic connection. Called when a packet is caught by - * a %trap, or when whack --oppohere --oppothere is used. - * It may turn out that an existing or non-opporunistic connnection - * can handle the traffic. - * - * Most of the code will be restarted if an ADNS request is made - * to discover the gateway. The only difference between the first - * and second entry is whether gateways_from_dns is NULL or not. - * initiate_opportunistic: initial entrypoint - * continue_oppo: where we pickup when ADNS result arrives - * initiate_opportunistic_body: main body shared by above routines - * cannot_oppo: a helper function to log a diagnostic - * This structure repeats a lot of code when the ADNS result arrives. - * This seems like a waste, but anything learned the first time through - * may no longer be true! - * - * After the first IKE message is sent, the regular state machinery - * carries negotiation forward. - */ - -enum find_oppo_step { - fos_start, - fos_myid_ip_txt, - fos_myid_hostname_txt, - fos_myid_ip_key, - fos_myid_hostname_key, - fos_our_client, - fos_our_txt, -#ifdef USE_KEYRR - fos_our_key, -#endif /* USE_KEYRR */ - fos_his_client, - fos_done -}; - -#ifdef DEBUG -static const char *const oppo_step_name[] = { - "fos_start", - "fos_myid_ip_txt", - "fos_myid_hostname_txt", - "fos_myid_ip_key", - "fos_myid_hostname_key", - "fos_our_client", - "fos_our_txt", -#ifdef USE_KEYRR - "fos_our_key", -#endif /* USE_KEYRR */ - "fos_his_client", - "fos_done" -}; -#endif /* DEBUG */ - -struct find_oppo_bundle { - enum find_oppo_step step; - err_t want; - bool failure_ok; /* if true, continue_oppo should not die on DNS failure */ - ip_address our_client; /* not pointer! */ - ip_address peer_client; - int transport_proto; - bool held; - policy_prio_t policy_prio; - ipsec_spi_t failure_shunt; /* in host order! 0 for delete. */ - int whackfd; -}; - -struct find_oppo_continuation { - struct adns_continuation ac; /* common prefix */ - struct find_oppo_bundle b; -}; - -static void cannot_oppo(connection_t *c, struct find_oppo_bundle *b, err_t ugh) -{ - char pcb[ADDRTOT_BUF]; - char ocb[ADDRTOT_BUF]; - - addrtot(&b->peer_client, 0, pcb, sizeof(pcb)); - addrtot(&b->our_client, 0, ocb, sizeof(ocb)); - - DBG(DBG_DNS | DBG_OPPO, DBG_log("Can't Opportunistically initiate for %s to %s: %s" - , ocb, pcb, ugh)); - - whack_log(RC_OPPOFAILURE - , "Can't Opportunistically initiate for %s to %s: %s" - , ocb, pcb, ugh); - - if (c && c->policy_next) - { - /* there is some policy that comes afterwards */ - struct spd_route *shunt_spd; - connection_t *nc = c->policy_next; - struct state *st; - - passert(c->kind == CK_TEMPLATE); - passert(c->policy_next->kind == CK_PERMANENT); - - DBG(DBG_OPPO, DBG_log("OE failed for %s to %s, but %s overrides shunt" - , ocb, pcb, c->policy_next->name)); - - /* - * okay, here we need add to the "next" policy, which is ought - * to be an instance. - * We will add another entry to the spd_route list for the specific - * situation that we have. - */ - - shunt_spd = clone_thing(nc->spd); - - shunt_spd->next = nc->spd.next; - nc->spd.next = shunt_spd; - - happy(addrtosubnet(&b->peer_client, &shunt_spd->that.client)); - - if (sameaddr(&b->peer_client, &shunt_spd->that.host_addr)) - shunt_spd->that.has_client = FALSE; - - /* - * override the tunnel destination with the one from the secondaried - * policy - */ - shunt_spd->that.host_addr = nc->spd.that.host_addr; - - /* now, lookup the state, and poke it up. - */ - - st = state_with_serialno(nc->newest_ipsec_sa); - - /* XXX what to do if the IPSEC SA has died? */ - passert(st != NULL); - - /* link the new connection instance to the state's list of - * connections - */ - - DBG(DBG_OPPO, DBG_log("installing state: %ld for %s to %s" - , nc->newest_ipsec_sa - , ocb, pcb)); - -#ifdef DEBUG - if (DBGP(DBG_OPPO | DBG_CONTROLMORE)) - { - char state_buf[LOG_WIDTH]; - char state_buf2[LOG_WIDTH]; - time_t n = now(); - - fmt_state(FALSE, st, n - , state_buf, sizeof(state_buf) - , state_buf2, sizeof(state_buf2)); - DBG_log("cannot_oppo, failure SA1: %s", state_buf); - DBG_log("cannot_oppo, failure SA2: %s", state_buf2); - } -#endif /* DEBUG */ - - if (!route_and_eroute(c, shunt_spd, st)) - { - whack_log(RC_OPPOFAILURE - , "failed to instantiate shunt policy %s for %s to %s" - , c->name - , ocb, pcb); - } - return; - } -} - -static void initiate_opportunistic_body(struct find_oppo_bundle *b - , struct adns_continuation *ac, err_t ac_ugh); /* forward */ - -void initiate_opportunistic(const ip_address *our_client, - const ip_address *peer_client, int transport_proto, - bool held, int whackfd) -{ - struct find_oppo_bundle b; - - b.want = (whackfd == NULL_FD ? "whack" : "acquire"); - b.failure_ok = FALSE; - b.our_client = *our_client; - b.peer_client = *peer_client; - b.transport_proto = transport_proto; - b.held = held; - b.policy_prio = BOTTOM_PRIO; - b.failure_shunt = 0; - b.whackfd = whackfd; - b.step = fos_start; - initiate_opportunistic_body(&b, NULL, NULL); -} - -#ifdef ADNS - -static void continue_oppo(struct adns_continuation *acr, err_t ugh) -{ - struct find_oppo_continuation *cr = (void *)acr; /* inherit, damn you! */ - connection_t *c; - bool was_held = cr->b.held; - int whackfd = cr->b.whackfd; - - /* note: cr->id has no resources; cr->sgw_id is ID_ANY: - * neither need freeing. - */ - whack_log_fd = whackfd; - -#ifdef DEBUG - /* if we're going to ignore the error, at least note it in debugging log */ - if (cr->b.failure_ok && ugh) - { - DBG(DBG_CONTROL | DBG_DNS, - { - char ocb[ADDRTOT_BUF]; - char pcb[ADDRTOT_BUF]; - - addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb)); - addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb)); - DBG_log("continuing from failed DNS lookup for %s, %s to %s: %s" - , cr->b.want, ocb, pcb, ugh); - }); - } -#endif - - if (!cr->b.failure_ok && ugh) - { - c = find_connection_for_clients(NULL, &cr->b.our_client, &cr->b.peer_client - , cr->b.transport_proto); - cannot_oppo(c, &cr->b - , builddiag("%s: %s", cr->b.want, ugh)); - } - else if (was_held && !cr->b.held) - { - /* was_held indicates we were started due to a %trap firing - * (as opposed to a "whack --oppohere --oppothere"). - * Since the %hold has gone, we can assume that somebody else - * has beaten us to the punch. We can go home. But lets log it. - */ - char ocb[ADDRTOT_BUF]; - char pcb[ADDRTOT_BUF]; - - addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb)); - addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb)); - - loglog(RC_COMMENT - , "%%hold otherwise handled during DNS lookup for Opportunistic Initiation for %s to %s" - , ocb, pcb); - } - else - { - initiate_opportunistic_body(&cr->b, &cr->ac, ugh); - whackfd = NULL_FD; /* was handed off */ - } - - whack_log_fd = NULL_FD; - close_any(whackfd); -} - -#endif /* ADNS */ - -#ifdef USE_KEYRR -static err_t check_key_recs(enum myid_state try_state, const connection_t *c, - struct adns_continuation *ac) -{ - /* Check if KEY lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - enum myid_state old_myid_state = myid_state; - private_key_t *private; - err_t ugh = NULL; - - myid_state = try_state; - - if (old_myid_state != myid_state && old_myid_state == MYID_SPECIFIED) - { - ugh = "%myid was specified while we were guessing"; - } - else if ((private = get_private_key(c)) == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!same_id(&ac->id, &c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - pubkey_list_t *kr; - - ugh = "no KEY RR found for us"; - for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next) - { - ugh = "all our KEY RRs have the wrong public key"; - if (kr->key->alg == PUBKEY_ALG_RSA - && private->belongs_to(private, &kr->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - if (ugh) - { - myid_state = old_myid_state; - } - return ugh; -} -#endif /* USE_KEYRR */ - -#ifdef ADNS - -static err_t check_txt_recs(enum myid_state try_state, const connection_t *c, - struct adns_continuation *ac) -{ - /* Check if TXT lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - enum myid_state old_myid_state = myid_state; - private_key_t *private; - err_t ugh = NULL; - - myid_state = try_state; - - if (old_myid_state != myid_state - && old_myid_state == MYID_SPECIFIED) - { - ugh = "%myid was specified while we were guessing"; - } - else if ((private = get_private_key(c)) == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!ac->id->equals(ac->id, c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - struct gw_info *gwp; - - ugh = "no TXT RR found for us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - public_key_t *pub_key = gwp->key->public_key; - - ugh = "all our TXT RRs have the wrong public key"; - if (pub_key->get_type(pub_key) == KEY_RSA && - private->belongs_to(private, pub_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - if (ugh) - { - myid_state = old_myid_state; - } - return ugh; -} - -#endif /* ADNS */ - - -/* note: gateways_from_dns must be NULL iff this is the first call */ -static void initiate_opportunistic_body(struct find_oppo_bundle *b, - struct adns_continuation *ac, - err_t ac_ugh) -{ - connection_t *c; - struct spd_route *sr; - - /* What connection shall we use? - * First try for one that explicitly handles the clients. - */ - DBG(DBG_CONTROL, - { - char ours[ADDRTOT_BUF]; - char his[ADDRTOT_BUF]; - int ourport; - int hisport; - - addrtot(&b->our_client, 0, ours, sizeof(ours)); - addrtot(&b->peer_client, 0, his, sizeof(his)); - ourport = ntohs(portof(&b->our_client)); - hisport = ntohs(portof(&b->peer_client)); - DBG_log("initiate on demand from %s:%d to %s:%d proto=%d state: %s because: %s" - , ours, ourport, his, hisport, b->transport_proto - , oppo_step_name[b->step], b->want); - }); - if (isanyaddr(&b->our_client) || isanyaddr(&b->peer_client)) - { - cannot_oppo(NULL, b, "impossible IP address"); - } - else if ((c = find_connection_for_clients(&sr - , &b->our_client - , &b->peer_client - , b->transport_proto)) == NULL) - { - /* No connection explicitly handles the clients and there - * are no Opportunistic connections -- whine and give up. - * The failure policy cannot be gotten from a connection; we pick %pass. - */ - cannot_oppo(NULL, b, "no routed Opportunistic template covers this pair"); - } - else if (c->kind != CK_TEMPLATE) - { - /* We've found a connection that can serve. - * Do we have to initiate it? - * Not if there is currently an IPSEC SA. - * But if there is an IPSEC SA, then the kernel would not - * have generated the acquire. So we assume that there isn't one. - * This may be redundant if a non-opportunistic - * negotiation is already being attempted. - */ - - /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */ - - if(c->kind == CK_INSTANCE) - { - char cib[CONN_INST_BUF]; - /* there is already an instance being negotiated, no nothing */ - DBG(DBG_CONTROL, DBG_log("found existing instance \"%s\"%s, rekeying it" - , c->name - , (fmt_conn_instance(c, cib), cib))); - /* XXX-mcr - return; */ - } - - /* otherwise, there is some kind of static conn that can handle - * this connection, so we initiate it */ - - if (b->held) - { - /* what should we do on failure? */ - (void) assign_hold(c, sr, b->transport_proto, &b->our_client, &b->peer_client); - } - ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY); - b->whackfd = NULL_FD; /* protect from close */ - } -#ifdef ADNS - else - { - /* We are handling an opportunistic situation. - * This involves several DNS lookup steps that require suspension. - * Note: many facts might change while we're suspended. - * Here be dragons. - * - * The first chunk of code handles the result of the previous - * DNS query (if any). It also selects the kind of the next step. - * The second chunk initiates the next DNS query (if any). - */ - enum find_oppo_step next_step = fos_myid_ip_txt; - err_t ugh = ac_ugh; - char mycredentialstr[BUF_LEN]; - char cib[CONN_INST_BUF]; - - DBG(DBG_CONTROL, DBG_log("creating new instance from \"%s\"%s", - c->name, (fmt_conn_instance(c, cib), cib))); - snprintf(mycredentialstr, BUF_LEN, "%Y", sr->this.id); - - /* handle any DNS answer; select next step */ - switch (b->step) - { - case fos_start: - /* just starting out: select first query step */ - next_step = fos_myid_ip_txt; - break; - - case fos_myid_ip_txt: /* TXT for our default IP address as %myid */ - ugh = check_txt_recs(MYID_IP, c, ac); - if (ugh) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our IP (%Y:TXT) as identity: %s", - myids[MYID_IP], ugh)); - if (!logged_myid_ip_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our IP (%Y:TXT) as identity: %s", - myids[MYID_IP], ugh); - logged_myid_ip_txt_warning = TRUE; - } - - next_step = fos_myid_hostname_txt; - ugh = NULL; /* failure can be recovered from */ - } - else - { - /* we can use our IP as OE identity for initiation */ - if (!logged_myid_ip_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "using our IP (%Y:TXT) as identity!", - myids[MYID_IP]); - logged_myid_ip_txt_warning = TRUE; - } - - next_step = fos_our_client; - } - break; - - case fos_myid_hostname_txt: /* TXT for our hostname as %myid */ - ugh = check_txt_recs(MYID_HOSTNAME, c, ac); - if (ugh) - { - /* cannot use our hostname as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our hostname (%Y:TXT) as identity: %s", - myids[MYID_HOSTNAME], ugh)); - if (!logged_myid_fqdn_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our hostname (%Y:TXT) as identity: %s", - myids[MYID_HOSTNAME], ugh); - logged_myid_fqdn_txt_warning = TRUE; - } -#ifdef USE_KEYRR - next_step = fos_myid_ip_key; - ugh = NULL; /* failure can be recovered from */ -#endif - } - else - { - /* we can use our hostname as OE identity for initiation */ - if (!logged_myid_fqdn_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "using our hostname (%Y:TXT) as identity!", - myids[MYID_HOSTNAME]); - logged_myid_fqdn_txt_warning = TRUE; - } - next_step = fos_our_client; - } - break; - -#ifdef USE_KEYRR - case fos_myid_ip_key: /* KEY for our default IP address as %myid */ - ugh = check_key_recs(MYID_IP, c, ac); - if (ugh) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our IP (%Y:KEY) as identity: %s", - myids[MYID_IP], ugh)); - if (!logged_myid_ip_key_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our IP (%Y:KEY) as identity: %s", - myids[MYID_IP], ugh); - logged_myid_ip_key_warning = TRUE; - } - - next_step = fos_myid_hostname_key; - ugh = NULL; /* failure can be recovered from */ - } - else - { - /* we can use our IP as OE identity for initiation */ - if (!logged_myid_ip_key_warning) - { - loglog(RC_LOG_SERIOUS, - "using our IP (%Y:KEY) as identity!", - myids[MYID_IP]); - logged_myid_ip_key_warning = TRUE; - } - next_step = fos_our_client; - } - break; - - case fos_myid_hostname_key: /* KEY for our hostname as %myid */ - ugh = check_key_recs(MYID_HOSTNAME, c, ac); - if (ugh) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our hostname (%Y:KEY) as identity: %s", - myids[MYID_HOSTNAME], ugh)); - if (!logged_myid_fqdn_key_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our hostname (%Y:KEY) as identity: %s", - myids[MYID_HOSTNAME], ugh); - logged_myid_fqdn_key_warning = TRUE; - } - next_step = fos_myid_hostname_key; - ugh = NULL; /* failure can be recovered from */ - } - else - { - /* we can use our IP as OE identity for initiation */ - if (!logged_myid_fqdn_key_warning) - { - loglog(RC_LOG_SERIOUS, - "using our hostname (%Y:KEY) as identity!", - myids[MYID_HOSTNAME]); - logged_myid_fqdn_key_warning = TRUE; - } - next_step = fos_our_client; - } - break; -#endif - - case fos_our_client: /* TXT for our client */ - { - /* Our client is not us: we must check the TXT records. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - private_key_t *private = get_private_key(c); - - next_step = fos_his_client; /* normal situation */ - - if (private == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (sameaddr(&sr->this.host_addr, &b->our_client)) - { - /* this wasn't true when we started -- bail */ - ugh = "our IP address changed underfoot"; - } - else if (!ac->sgw_id->equals(ac->sgw_id, sr->this.id)) - { - /* this wasn't true when we started -- bail */ - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in quick_inI1_outR1_tail - * for checking the other side. - */ - struct gw_info *gwp; - - ugh = "no TXT RR for our client delegates us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "TXT RR for our client has wrong key"; - /* If there is a key from the TXT record, - * we count it as a win if we match the key. - * If there was no key, we have a tentative win: - * we need to check our KEY record to be sure. - */ - if (!gwp->gw_key_present) - { - /* Success, but the TXT had no key - * so we must check our our own KEY records. - */ - next_step = fos_our_txt; - ugh = NULL; /* good! */ - break; - } - if (private->belongs_to(private, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - } - break; - - case fos_our_txt: /* TXT for us */ - { - /* Check if TXT lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - private_key_t *private = get_private_key(c); - - next_step = fos_his_client; /* unless we decide to look for KEY RR */ - - if (private == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!ac->id->equals(ac->id, c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - struct gw_info *gwp; - - ugh = "no TXT RR for us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "TXT RR for us has wrong key"; - if (gwp->gw_key_present && - private->belongs_to(private, gwp->key->public_key)) - { - DBG(DBG_CONTROL, - DBG_log("initiate on demand found TXT with right public key at: %s" - , mycredentialstr)); - ugh = NULL; - break; - } - } -#ifdef USE_KEYRR - if (ugh) - { - /* if no TXT with right key, try KEY */ - DBG(DBG_CONTROL, - DBG_log("will try for KEY RR since initiate on demand found %s: %s" - , ugh, mycredentialstr)); - next_step = fos_our_key; - ugh = NULL; - } -#endif - } - } - break; - -#ifdef USE_KEYRR - case fos_our_key: /* KEY for us */ - { - /* Check if KEY lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - private_key_t *private = get_private_key(c); - - next_step = fos_his_client; /* always */ - - if (private == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!same_id(&ac->id, &c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - pubkey_list_t *kr; - - ugh = "no KEY RR found for us (and no good TXT RR)"; - for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next) - { - ugh = "all our KEY RRs have the wrong public key (and no good TXT RR)"; - if (kr->key->alg == PUBKEY_ALG_RSA - && private->belongs_to(private, kr->key->public_key)) - { - /* do this only once a day */ - if (!logged_txt_warning) - { - loglog(RC_LOG_SERIOUS - , "found KEY RR but not TXT RR for %s. See http://www.freeswan.org/err/txt-change.html." - , mycredentialstr); - logged_txt_warning = TRUE; - } - ugh = NULL; /* good! */ - break; - } - } - } - } - break; -#endif /* USE_KEYRR */ - - case fos_his_client: /* TXT for his client */ - { - /* We've finished last DNS queries: TXT for his client. - * Using the information, try to instantiate a connection - * and start negotiating. - * We now know the peer. The chosing of "c" ignored this, - * so we will disregard its current value. - * !!! We need to randomize the entry in gw that we choose. - */ - next_step = fos_done; /* no more queries */ - - c = build_outgoing_opportunistic_connection(ac->gateways_from_dns - , &b->our_client - , &b->peer_client); - - if (c == NULL) - { - /* We cannot seem to instantiate a suitable connection: - * complain clearly. - */ - char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; - - addrtot(&b->our_client, 0, ocb, sizeof(ocb)); - addrtot(&b->peer_client, 0, pcb, sizeof(pcb)); - loglog(RC_OPPOFAILURE, - "no suitable connection for opportunism " - "between %s and %s with %Y as peer", - ocb, pcb, ac->gateways_from_dns->gw_id); - } - else - { - /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */ - passert(c->kind == CK_INSTANCE); - passert(c->gw_info != NULL); - passert(HAS_IPSEC_POLICY(c->policy)); - passert(LHAS(LELEM(RT_UNROUTED) | LELEM(RT_ROUTED_PROSPECTIVE), c->spd.routing)); - if (b->held) - { - /* what should we do on failure? */ - (void) assign_hold(c, &c->spd - , b->transport_proto - , &b->our_client, &b->peer_client); - } - c->gw_info->key->last_tried_time = now(); - ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY); - b->whackfd = NULL_FD; /* protect from close */ - } - } - break; - - default: - bad_case(b->step); - } - - /* the second chunk: initiate the next DNS query (if any) */ - DBG(DBG_CONTROL, - { - char ours[ADDRTOT_BUF]; - char his[ADDRTOT_BUF]; - - addrtot(&b->our_client, 0, ours, sizeof(ours)); - addrtot(&b->peer_client, 0, his, sizeof(his)); - DBG_log("initiate on demand from %s to %s new state: %s with ugh: %s" - , ours, his, oppo_step_name[b->step], ugh ? ugh : "ok"); - }); - - if (ugh) - { - b->policy_prio = c->prio; - b->failure_shunt = shunt_policy_spi(c, FALSE); - cannot_oppo(c, b, ugh); - } - else if (next_step == fos_done) - { - /* nothing to do */ - } - else - { - /* set up the next query */ - struct find_oppo_continuation *cr = malloc_thing(struct find_oppo_continuation); - identification_t *id; - - b->policy_prio = c->prio; - b->failure_shunt = shunt_policy_spi(c, FALSE); - cr->b = *b; /* copy; start hand off of whackfd */ - cr->b.failure_ok = FALSE; - cr->b.step = next_step; - - for (sr = &c->spd - ; sr!=NULL && !sameaddr(&sr->this.host_addr, &b->our_client) - ; sr = sr->next) - ; - - if (sr == NULL) - sr = &c->spd; - - /* If a %hold shunt has replaced the eroute for this template, - * record this fact. - */ - if (b->held - && sr->routing == RT_ROUTED_PROSPECTIVE && eclipsable(sr)) - { - sr->routing = RT_ROUTED_ECLIPSED; - eclipse_count++; - } - - /* Switch to issue next query. - * A case may turn out to be unnecessary. If so, it falls - * through to the next case. - * Figuring out what %myid can stand for must be done before - * our client credentials are looked up: we must know what - * the client credentials may use to identify us. - * On the other hand, our own credentials should be looked - * up after our clients in case our credentials are not - * needed at all. - * XXX this is a wasted effort if we don't have credentials - * BUT they are not needed. - */ - switch (next_step) - { - case fos_myid_ip_txt: - if (c->spd.this.id->get_type(c->spd.this.id) == ID_MYID - && myid_state != MYID_SPECIFIED) - { - cr->b.failure_ok = TRUE; - cr->b.want = b->want = "TXT record for IP address as %myid"; - ugh = start_adns_query(myids[MYID_IP], myids[MYID_IP], - T_TXT, continue_oppo, &cr->ac); - break; - } - cr->b.step = fos_myid_hostname_txt; - /* fall through */ - - case fos_myid_hostname_txt: - if (c->spd.this.id->get_type(c->spd.this.id) == ID_MYID - && myid_state != MYID_SPECIFIED) - { -#ifdef USE_KEYRR - cr->b.failure_ok = TRUE; -#else - cr->b.failure_ok = FALSE; -#endif - cr->b.want = b->want = "TXT record for hostname as %myid"; - ugh = start_adns_query(myids[MYID_HOSTNAME], - myids[MYID_HOSTNAME], - T_TXT, continue_oppo, &cr->ac); - break; - } - -#ifdef USE_KEYRR - cr->b.step = fos_myid_ip_key; - /* fall through */ - - case fos_myid_ip_key: - if (c->spd.this.id.kind == ID_MYID - && myid_state != MYID_SPECIFIED) - { - cr->b.failure_ok = TRUE; - cr->b.want = b->want = "KEY record for IP address as %myid (no good TXT)"; - ugh = start_adns_query(myids[MYID_IP], NULL, /* security gateway meaningless */ - T_KEY, continue_oppo, &cr->ac); - break; - } - cr->b.step = fos_myid_hostname_key; - /* fall through */ - - case fos_myid_hostname_key: - if (c->spd.this.id.kind == ID_MYID - && myid_state != MYID_SPECIFIED) - { - cr->b.failure_ok = FALSE; /* last attempt! */ - cr->b.want = b->want = "KEY record for hostname as %myid (no good TXT)"; - ugh = start_adns_query(myids[MYID_HOSTNAME], NULL, /* security gateway meaningless */ - T_KEY, continue_oppo, &cr->ac); - break; - } -#endif - cr->b.step = fos_our_client; - /* fall through */ - - case fos_our_client: /* TXT for our client */ - if (!sameaddr(&c->spd.this.host_addr, &b->our_client)) - { - /* Check that at least one TXT(reverse(b->our_client)) is workable. - * Note: {unshare|free}_id_content not needed for id: ephemeral. - */ - cr->b.want = b->want = "our client's TXT record"; - id = identification_create_from_sockaddr((sockaddr_t*)&b->our_client); - ugh = start_adns_query(id, c->spd.this.id, /* we are the security gateway */ - T_TXT, continue_oppo, &cr->ac); - id->destroy(id); - break; - } - cr->b.step = fos_our_txt; - /* fall through */ - - case fos_our_txt: /* TXT for us */ - cr->b.failure_ok = b->failure_ok = TRUE; - cr->b.want = b->want = "our TXT record"; - ugh = start_adns_query(sr->this.id, sr->this.id, /* we are the security gateway */ - T_TXT, continue_oppo, &cr->ac); - break; - -#ifdef USE_KEYRR - case fos_our_key: /* KEY for us */ - cr->b.want = b->want = "our KEY record"; - cr->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(sr->this.id, NULL, /* security gateway meaningless */ - T_KEY, continue_oppo, &cr->ac); - break; -#endif /* USE_KEYRR */ - - case fos_his_client: /* TXT for his client */ - /* note: {unshare|free}_id_content not needed for id: ephemeral */ - cr->b.want = b->want = "target's TXT record"; - cr->b.failure_ok = b->failure_ok = FALSE; - id = identification_create_from_sockaddr((sockaddr_t*)&b->peer_client); - ugh = start_adns_query(id, NULL, /* security gateway unconstrained */ - T_TXT, continue_oppo, &cr->ac); - id->destroy(id); - break; - - default: - bad_case(next_step); - } - - if (ugh == NULL) - b->whackfd = NULL_FD; /* complete hand-off */ - else - cannot_oppo(c, b, ugh); - } - } -#endif /* ADNS */ - close_any(b->whackfd); -} - -void terminate_connection(const char *nm) -{ - /* Loop because more than one may match (master and instances) - * But at least one is required (enforced by con_by_name). - */ - connection_t *c = con_by_name(nm, TRUE); - - if (c == NULL || !c->ikev1) - return; - - do - { - connection_t *n = c->ac_next; /* grab this before c might disappear */ - - if (streq(c->name, nm) - && c->kind >= CK_PERMANENT - && !NEVER_NEGOTIATE(c->policy)) - { - set_cur_connection(c); - plog("terminating SAs using this connection"); - c->policy &= ~POLICY_UP; - flush_pending_by_connection(c); - delete_states_by_connection(c, FALSE); - if (c->kind == CK_INSTANCE) - delete_connection(c, FALSE); - reset_cur_connection(); - } - c = n; - } while (c); -} - -/* an ISAKMP SA has been established. - * Note the serial number, and release any connections with - * the same peer ID but different peer IP address. - */ -bool uniqueIDs = FALSE; /* --uniqueids? */ - -void ISAKMP_SA_established(connection_t *c, so_serial_t serial) -{ - c->newest_isakmp_sa = serial; - - /* the connection is now oriented so that we are able to determine - * whether we are a mode config server with a virtual IP to send. - */ - if (!c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip) && - !c->spd.that.has_natip) - { - c->spd.that.modecfg = TRUE; - } - - if (uniqueIDs) - { - /* for all connections: if the same Phase 1 IDs are used - * for a different IP address, unorient that connection. - */ - connection_t *d; - - for (d = connections; d != NULL; ) - { - connection_t *next = d->ac_next; /* might move underneath us */ - - if (d->kind >= CK_PERMANENT && - c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && - c->spd.that.id->equals(c->spd.that.id, d->spd.that.id) && - !sameaddr(&c->spd.that.host_addr, &d->spd.that.host_addr)) - { - release_connection(d, FALSE); - } - d = next; - } - } -} - -/* Find the connection to connection c's peer's client with the - * largest value of .routing. All other things being equal, - * preference is given to c. If none is routed, return NULL. - * - * If erop is non-null, set *erop to a connection sharing both - * our client subnet and peer's client subnet with the largest value - * of .routing. If none is erouted, set *erop to NULL. - * - * The return value is used to find other connections sharing a route. - * *erop is used to find other connections sharing an eroute. - */ -connection_t *route_owner(connection_t *c, struct spd_route **srp, - connection_t **erop, struct spd_route **esrp) -{ - connection_t *d - , *best_ro = c - , *best_ero = c; - struct spd_route *srd, *src; - struct spd_route *best_sr, *best_esr; - enum routing_t best_routing, best_erouting; - - passert(oriented(*c)); - best_sr = NULL; - best_esr = NULL; - best_routing = c->spd.routing; - best_erouting = best_routing; - - for (d = connections; d != NULL; d = d->ac_next) - { - for (srd = &d->spd; srd; srd = srd->next) - { - if (srd->routing == RT_UNROUTED) - continue; - - for (src = &c->spd; src; src=src->next) - { - if (!samesubnet(&src->that.client, &srd->that.client)) - { - continue; - } - if (src->that.protocol != srd->that.protocol) - { - continue; - } - if (src->that.port != srd->that.port) - { - continue; - } - if (src->mark_out.value != srd->mark_out.value) - { - continue; - } - passert(oriented(*d)); - if (srd->routing > best_routing) - { - best_ro = d; - best_sr = srd; - best_routing = srd->routing; - } - - if (!samesubnet(&src->this.client, &srd->this.client)) - { - continue; - } - if (src->this.protocol != srd->this.protocol) - { - continue; - } - if (src->this.port != srd->this.port) - { - continue; - } - if (src->mark_in.value != srd->mark_in.value) - { - continue; - } - if (srd->routing > best_erouting) - { - best_ero = d; - best_esr = srd; - best_erouting = srd->routing; - } - } - } - } - - DBG(DBG_CONTROL, - { - char cib[CONN_INST_BUF]; - err_t m = builddiag("route owner of \"%s\"%s %s:" - , c->name - , (fmt_conn_instance(c, cib), cib) - , enum_name(&routing_story, c->spd.routing)); - - if (!routed(best_ro->spd.routing)) - m = builddiag("%s NULL", m); - else if (best_ro == c) - m = builddiag("%s self", m); - else - m = builddiag("%s \"%s\"%s %s", m - , best_ro->name - , (fmt_conn_instance(best_ro, cib), cib) - , enum_name(&routing_story, best_ro->spd.routing)); - - if (erop) - { - m = builddiag("%s; eroute owner:", m); - if (!erouted(best_ero->spd.routing)) - m = builddiag("%s NULL", m); - else if (best_ero == c) - m = builddiag("%s self", m); - else - m = builddiag("%s \"%s\"%s %s", m - , best_ero->name - , (fmt_conn_instance(best_ero, cib), cib) - , enum_name(&routing_story, best_ero->spd.routing)); - } - - DBG_log("%s", m); - }); - - if (erop) - { - *erop = erouted(best_erouting)? best_ero : NULL; - } - if (srp) - { - *srp = best_sr; - if (esrp) - { - *esrp = best_esr; - } - } - - return routed(best_routing)? best_ro : NULL; -} - -/* Find a connection that owns the shunt eroute between subnets. - * There ought to be only one. - * This might get to be a bottleneck -- try hashing if it does. - */ -connection_t *shunt_owner(const ip_subnet *ours, const ip_subnet *his) -{ - connection_t *c; - struct spd_route *sr; - - for (c = connections; c != NULL; c = c->ac_next) - { - for (sr = &c->spd; sr; sr = sr->next) - { - if (shunt_erouted(sr->routing) - && samesubnet(ours, &sr->this.client) - && samesubnet(his, &sr->that.client)) - return c; - } - } - return NULL; -} - -/* Find some connection with this pair of hosts. - * We don't know enough to chose amongst those available. - * ??? no longer usefully different from find_host_pair_connections - */ -connection_t *find_host_connection(const ip_address *me, u_int16_t my_port, - const ip_address *him, u_int16_t his_port, - lset_t policy) -{ - connection_t *c = find_host_pair_connections(me, my_port, him, his_port); - - if (policy != LEMPTY) - { - lset_t auth_requested = policy & POLICY_ID_AUTH_MASK; - - /* if we have requirements for the policy, - * choose the first matching connection. - */ - while (c) - { - if (c->policy & auth_requested) - { - break; - } - c = c->hp_next; - } - } - return c; -} - -/* given an up-until-now satisfactory connection, find the best connection - * now that we just got the Phase 1 Id Payload from the peer. - * - * Comments in the code describe the (tricky!) matching criteria. - * Although this routine could handle the initiator case, - * it isn't currently called in this case. - * If it were, it could "upgrade" an Opportunistic Connection - * to a Road Warrior Connection if a suitable Peer ID were found. - * - * In RFC 2409 "The Internet Key Exchange (IKE)", - * in 5.1 "IKE Phase 1 Authenticated With Signatures", describing Main - * Mode: - * - * Initiator Responder - * ----------- ----------- - * HDR, SA --> - * <-- HDR, SA - * HDR, KE, Ni --> - * <-- HDR, KE, Nr - * HDR*, IDii, [ CERT, ] SIG_I --> - * <-- HDR*, IDir, [ CERT, ] SIG_R - * - * In 5.4 "Phase 1 Authenticated With a Pre-Shared Key": - * - * HDR, SA --> - * <-- HDR, SA - * HDR, KE, Ni --> - * <-- HDR, KE, Nr - * HDR*, IDii, HASH_I --> - * <-- HDR*, IDir, HASH_R - * - * refine_host_connection could be called in two case: - * - * - the Responder receives the IDii payload: - * + [PSK] after using PSK to decode this message - * + before sending its IDir payload - * + before using its ID in HASH_R computation - * + [DSig] before using its private key to sign SIG_R - * + before using the Initiator's ID in HASH_I calculation - * + [DSig] before using the Initiator's public key to check SIG_I - * - * - the Initiator receives the IDir payload: - * + [PSK] after using PSK to encode previous message and decode this message - * + after sending its IDii payload - * + after using its ID in HASH_I computation - * + [DSig] after using its private key to sign SIG_I - * + before using the Responder's ID to compute HASH_R - * + [DSig] before using Responder's public key to check SIG_R - * - * refine_host_connection can choose a different connection, as long as - * nothing already used is changed. - * - * In the Initiator case, the particular connection might have been - * specified by whatever provoked Pluto to initiate. For example: - * whack --initiate connection-name - * The advantages of switching connections when we're the Initiator seem - * less important than the disadvantages, so after FreeS/WAN 1.9, we - * don't do this. - */ -#define PRIO_NO_MATCH_FOUND 2048 - -connection_t *refine_host_connection(const struct state *st, - identification_t *peer_id, - identification_t *peer_ca) -{ - connection_t *c = st->st_connection; - connection_t *d; - connection_t *best_found = NULL; - u_int16_t auth = st->st_oakley.auth; - lset_t auth_policy = POLICY_PSK; - const chunk_t *psk = NULL; - bool wcpip; /* wildcard Peer IP? */ - int best_prio = PRIO_NO_MATCH_FOUND; - int our_pathlen, peer_pathlen; - - if (c->spd.that.id->equals(c->spd.that.id, peer_id) && - trusted_ca(peer_ca, c->spd.that.ca, &peer_pathlen) && - peer_pathlen == 0 && - match_requested_ca(c->requested_ca, c->spd.this.ca, &our_pathlen) && - our_pathlen == 0) - { - DBG(DBG_CONTROL, - DBG_log("current connection is a full match" - " -- no need to look further"); - ) - return c; - } - - switch (auth) - { - case OAKLEY_PRESHARED_KEY: - auth_policy = POLICY_PSK; - psk = get_preshared_secret(c); - /* It should be virtually impossible to fail to find PSK: - * we just used it to decode the current message! - */ - if (psk == NULL) - { - return NULL; /* cannot determine PSK! */ - } - break; - case XAUTHInitPreShared: - case XAUTHRespPreShared: - auth_policy = POLICY_XAUTH_PSK; - psk = get_preshared_secret(c); - if (psk == NULL) - { - return NULL; /* cannot determine PSK! */ - } - break; - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - auth_policy = POLICY_PUBKEY; - break; - case XAUTHInitRSA: - case XAUTHRespRSA: - auth_policy = POLICY_XAUTH_RSASIG; - break; - default: - bad_case(auth); - } - - /* The current connection won't do: search for one that will. - * First search for one with the same pair of hosts. - * If that fails, search for a suitable Road Warrior or Opportunistic - * connection (i.e. wildcard peer IP). - * We need to match: - * - peer_id (slightly complicated by instantiation) - * - if PSK auth, the key must not change (we used it to decode message) - * - policy-as-used must be acceptable to new connection - */ - d = c->host_pair->connections; - for (wcpip = FALSE; ; wcpip = TRUE) - { - for (; d != NULL; d = d->hp_next) - { - const char *match_name[] = {"no", "ok"}; - - id_match_t match_level = peer_id->matches(peer_id, d->spd.that.id); - - bool matching_id = match_level > ID_MATCH_NONE; - - bool matching_auth = (d->policy & auth_policy) != LEMPTY; - - bool matching_trust = trusted_ca(peer_ca - , d->spd.that.ca, &peer_pathlen); - bool matching_request = match_requested_ca(c->requested_ca - , d->spd.this.ca, &our_pathlen); - bool match = matching_id && matching_auth && matching_trust; - - int prio = (ID_MATCH_PERFECT) * !matching_request + - ID_MATCH_PERFECT - match_level; - - prio = (X509_MAX_PATH_LEN + 1) * prio + peer_pathlen; - prio = (X509_MAX_PATH_LEN + 1) * prio + our_pathlen; - - DBG(DBG_CONTROLMORE, - DBG_log("%s: %s match (id: %s, auth: %s, trust: %s, request: %s, prio: %4d)" - , d->name - , match ? "full":" no" - , match_name[matching_id] - , match_name[matching_auth] - , match_name[matching_trust] - , match_name[matching_request] - , match ? prio:PRIO_NO_MATCH_FOUND) - ) - - /* do we have a match? */ - if (!match) - { - continue; - } - - /* ignore group connections */ - if (d->policy & POLICY_GROUP) - { - continue; - } - - if (c->spd.that.host_port != d->spd.that.host_port - && d->kind == CK_INSTANCE) - { - continue; - } - - switch (auth) - { - case OAKLEY_PRESHARED_KEY: - case XAUTHInitPreShared: - case XAUTHRespPreShared: - /* secret must match the one we already used */ - { - const chunk_t *dpsk = get_preshared_secret(d); - - if (dpsk == NULL) - { - continue; /* no secret */ - } - if (psk != dpsk) - { - if (psk->len != dpsk->len - || memcmp(psk->ptr, dpsk->ptr, psk->len) != 0) - { - continue; /* different secret */ - } - } - } - break; - - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - case XAUTHInitRSA: - case XAUTHRespRSA: - /* - * We must at least be able to find our private key - .*/ - if (d->spd.this.sc == NULL /* no smartcard */ - && get_private_key(d) == NULL) /* no private key */ - { - continue; - } - break; - - default: - bad_case(auth); - } - - /* d has passed all the tests. - * We'll go with it if the Peer ID was an exact match. - */ - if (prio == 0) - { - return d; - } - - /* We'll remember it as best_found in case an exact - * match doesn't come along. - */ - if (prio < best_prio) - { - best_found = d; - best_prio = prio; - } - } - if (wcpip) - return best_found; /* been around twice already */ - - /* Starting second time around. - * We're willing to settle for a connection that needs Peer IP - * instantiated: Road Warrior or Opportunistic. - * Look on list of connections for host pair with wildcard Peer IP - */ - d = find_host_pair_connections(&c->spd.this.host_addr, c->spd.this.host_port - , (ip_address *)NULL, c->spd.that.host_port); - } -} - -/** - * With virtual addressing, we must not allow someone to use an already - * used (by another id) addr/net. - */ -static bool is_virtual_net_used(const ip_subnet *peer_net, - identification_t *peer_id) -{ - connection_t *d; - - for (d = connections; d != NULL; d = d->ac_next) - { - switch (d->kind) - { - case CK_PERMANENT: - case CK_INSTANCE: - if ((subnetinsubnet(peer_net,&d->spd.that.client) || - subnetinsubnet(&d->spd.that.client,peer_net)) - && !d->spd.that.id->equals(d->spd.that.id, peer_id)) - { - char client[SUBNETTOT_BUF]; - - subnettot(peer_net, 0, client, sizeof(client)); - plog("Virtual IP %s is already used by '%Y'", - client, d->spd.that.id); - plog("Your ID is '%Y'", peer_id); - - return TRUE; /* already used by another one */ - } - break; - case CK_GOING_AWAY: - default: - break; - } - } - return FALSE; /* you can safely use it */ -} - -/* find_client_connection: given a connection suitable for ISAKMP - * (i.e. the hosts match), find a one suitable for IPSEC - * (i.e. with matching clients). - * - * If we don't find an exact match (not even our current connection), - * we try for one that still needs instantiation. Try Road Warrior - * abstract connections and the Opportunistic abstract connections. - * This requires inverse instantiation: abstraction. - * - * After failing to find an exact match, we abstract the peer - * to be NO_IP (the wildcard value). This enables matches with - * Road Warrior and Opportunistic abstract connections. - * - * After failing that search, we also abstract the Phase 1 peer ID - * if possible. If the peer's ID was the peer's IP address, we make - * it NO_ID; instantiation will make it the peer's IP address again. - * - * If searching for a Road Warrior abstract connection fails, - * and conditions are suitable, we search for the best Opportunistic - * abstract connection. - * - * Note: in the end, both Phase 1 IDs must be preserved, after any - * instantiation. They are the IDs that have been authenticated. - */ - -#define PATH_WEIGHT 1 -#define WILD_WEIGHT (X509_MAX_PATH_LEN+1) -#define PRIO_WEIGHT (ID_MATCH_PERFECT+1) * WILD_WEIGHT - -/* fc_try: a helper function for find_client_connection */ -static connection_t *fc_try(const connection_t *c, struct host_pair *hp, - identification_t *peer_id, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t our_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port, - identification_t *peer_ca, - ietf_attributes_t *peer_attributes) -{ - connection_t *d; - connection_t *best = NULL; - policy_prio_t best_prio = BOTTOM_PRIO; - id_match_t match_level; - int pathlen; - - - const bool peer_net_is_host = subnetisaddr(peer_net, &c->spd.that.host_addr); - - for (d = hp->connections; d != NULL; d = d->hp_next) - { - struct spd_route *sr; - - if (d->policy & POLICY_GROUP) - { - continue; - } - - match_level = c->spd.that.id->matches(c->spd.that.id, d->spd.that.id); - - if (!(c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && - (match_level > ID_MATCH_NONE) && - trusted_ca(peer_ca, d->spd.that.ca, &pathlen) && - match_group_membership(peer_attributes, d->name, d->spd.that.groups))) - { - continue; - } - - /* compare protocol and ports */ - if (d->spd.this.protocol != our_protocol - || d->spd.this.port != our_port - || d->spd.that.protocol != peer_protocol - || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard)) - { - continue; - } - - /* non-Opportunistic case: - * our_client must match. - * - * So must peer_client, but the testing is complicated - * by the fact that the peer might be a wildcard - * and if so, the default value of that.client - * won't match the default peer_net. The appropriate test: - * - * If d has a peer client, it must match peer_net. - * If d has no peer client, peer_net must just have peer itself. - */ - - for (sr = &d->spd; best != d && sr != NULL; sr = sr->next) - { - policy_prio_t prio; -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF]; - char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF]; - - subnettot(our_net, 0, s1, sizeof(s1)); - subnettot(peer_net, 0, d1, sizeof(d1)); - subnettot(&sr->this.client, 0, s3, sizeof(s3)); - subnettot(&sr->that.client, 0, d3, sizeof(d3)); - DBG_log(" fc_try trying " - "%s:%s:%d/%d -> %s:%d/%d vs %s:%s:%d/%d -> %s:%d/%d" - , c->name, s1, c->spd.this.protocol, c->spd.this.port - , d1, c->spd.that.protocol, c->spd.that.port - , d->name, s3, sr->this.protocol, sr->this.port - , d3, sr->that.protocol, sr->that.port); - } -#endif /* DEBUG */ - - if (!samesubnet(&sr->this.client, our_net)) - { - continue; - } - if (sr->that.has_client) - { - if (sr->that.has_client_wildcard) - { - if (!subnetinsubnet(peer_net, &sr->that.client)) - { - continue; - } - } - else - { - if (!samesubnet(&sr->that.client, peer_net) && !is_virtual_connection(d)) - { - continue; - } - if (is_virtual_connection(d) - && (!is_virtual_net_allowed(d, peer_net, &c->spd.that.host_addr) - || is_virtual_net_used(peer_net, peer_id?peer_id:c->spd.that.id))) - { - continue; - } - } - } - else - { - host_t *vip = c->spd.that.host_srcip; - - if (!peer_net_is_host && !(sr->that.modecfg && c->spd.that.modecfg && - subnetisaddr(peer_net, (ip_address*)vip->get_sockaddr(vip)))) - { - continue; - } - } - - /* We've run the gauntlet -- success: - * We've got an exact match of subnets. - * The connection is feasible, but we continue looking for the best. - * The highest priority wins, implementing eroute-like rule. - * - a routed connection is preferrred - * - given that, the smallest number of ID wildcards are preferred - * - given that, the shortest CA pathlength is preferred - */ - prio = PRIO_WEIGHT * routed(sr->routing) - + WILD_WEIGHT * match_level - + PATH_WEIGHT * (X509_MAX_PATH_LEN - pathlen) - + 1; - if (prio > best_prio) - { - best = d; - best_prio = prio; - } - } - } - - if (best && NEVER_NEGOTIATE(best->policy)) - { - best = NULL; - } - DBG(DBG_CONTROLMORE, - DBG_log(" fc_try concluding with %s [%ld]" - , (best ? best->name : "none"), best_prio) - ) - return best; -} - -static connection_t *fc_try_oppo(const connection_t *c, - struct host_pair *hp, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t our_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port, - identification_t *peer_ca, - ietf_attributes_t *peer_attributes) -{ - connection_t *d; - connection_t *best = NULL; - policy_prio_t best_prio = BOTTOM_PRIO; - id_match_t match_level; - int pathlen; - - for (d = hp->connections; d != NULL; d = d->hp_next) - { - struct spd_route *sr; - policy_prio_t prio; - - if (d->policy & POLICY_GROUP) - { - continue; - } - match_level = c->spd.that.id->matches(c->spd.that.id, c->spd.that.id); - - if (!(c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && - (match_level > ID_MATCH_NONE) && - trusted_ca(peer_ca, d->spd.that.ca, &pathlen) && - match_group_membership(peer_attributes, d->name, d->spd.that.groups))) - { - continue; - } - - /* compare protocol and ports */ - if (d->spd.this.protocol != our_protocol - || d->spd.this.port != our_port - || d->spd.that.protocol != peer_protocol - || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard)) - { - continue; - } - - /* Opportunistic case: - * our_net must be inside d->spd.this.client - * and peer_net must be inside d->spd.that.client - * Note: this host_pair chain also has shunt - * eroute conns (clear, drop), but they won't - * be marked as opportunistic. - */ - for (sr = &d->spd; sr != NULL; sr = sr->next) - { -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF]; - char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF]; - - subnettot(our_net, 0, s1, sizeof(s1)); - subnettot(peer_net, 0, d1, sizeof(d1)); - subnettot(&sr->this.client, 0, s3, sizeof(s3)); - subnettot(&sr->that.client, 0, d3, sizeof(d3)); - DBG_log(" fc_try_oppo trying %s:%s -> %s vs %s:%s -> %s" - , c->name, s1, d1, d->name, s3, d3); - } -#endif /* DEBUG */ - - if (!subnetinsubnet(our_net, &sr->this.client) - || !subnetinsubnet(peer_net, &sr->that.client)) - { - continue; - } - - /* The connection is feasible, but we continue looking for the best. - * The highest priority wins, implementing eroute-like rule. - * - our smallest client subnet is preferred (longest mask) - * - given that, his smallest client subnet is preferred - * - given that, a routed connection is preferrred - * - given that, the smallest number of ID wildcards are preferred - * - given that, the shortest CA pathlength is preferred - */ - prio = PRIO_WEIGHT * (d->prio + routed(sr->routing)) - + WILD_WEIGHT * match_level - + PATH_WEIGHT * (X509_MAX_PATH_LEN - pathlen); - if (prio > best_prio) - { - best = d; - best_prio = prio; - } - } - } - - /* if the best wasn't opportunistic, we fail: it must be a shunt */ - if (best && (NEVER_NEGOTIATE(best->policy) || - (best->policy & POLICY_OPPO) == LEMPTY)) - { - best = NULL; - } - - DBG(DBG_CONTROLMORE, - DBG_log(" fc_try_oppo concluding with %s [%ld]" - , (best ? best->name : "none"), best_prio) - ) - return best; - -} - -/* - * get the peer's CA and group attributes - */ -void get_peer_ca_and_groups(connection_t *c, - identification_t **peer_ca, - ietf_attributes_t **peer_attributes) -{ - struct state *p1st; - - *peer_ca = NULL; - *peer_attributes = NULL; - - p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); - if (p1st && p1st->st_peer_pubkey && p1st->st_peer_pubkey->issuer) - { - certificate_t *cert; - - cert = ac_get_cert(p1st->st_peer_pubkey->issuer, - p1st->st_peer_pubkey->serial); - if (cert && ac_verify_cert(cert, strict_crl_policy)) - { - ac_t *ac = (ac_t*)cert; - - *peer_attributes = ac->get_groups(ac); - } - else - { - DBG(DBG_CONTROL, - DBG_log("no valid attribute cert found") - ) - } - *peer_ca = p1st->st_peer_pubkey->issuer; - } -} - -connection_t *find_client_connection(connection_t *c, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t our_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port) -{ - connection_t *d; - struct spd_route *sr; - ietf_attributes_t *peer_attributes = NULL; - identification_t *peer_ca; - - get_peer_ca_and_groups(c, &peer_ca, &peer_attributes); - -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF]; - - subnettot(our_net, 0, s1, sizeof(s1)); - subnettot(peer_net, 0, d1, sizeof(d1)); - - DBG_log("find_client_connection starting with %s" - , (c ? c->name : "(none)")); - DBG_log(" looking for %s:%d/%d -> %s:%d/%d" - , s1, our_protocol, our_port - , d1, peer_protocol, peer_port); - } -#endif /* DEBUG */ - - /* give priority to current connection - * but even greater priority to a routed concrete connection - */ - { - connection_t *unrouted = NULL; - int srnum = -1; - - for (sr = &c->spd; unrouted == NULL && sr != NULL; sr = sr->next) - { - srnum++; - -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF]; - - subnettot(&sr->this.client, 0, s2, sizeof(s2)); - subnettot(&sr->that.client, 0, d2, sizeof(d2)); - DBG_log(" concrete checking against sr#%d %s -> %s" - , srnum, s2, d2); - } -#endif /* DEBUG */ - - if (samesubnet(&sr->this.client, our_net) - && samesubnet(&sr->that.client, peer_net) - && sr->this.protocol == our_protocol - && sr->this.port == our_port - && sr->that.protocol == peer_protocol - && sr->that.port == peer_port - && match_group_membership(peer_attributes, c->name, sr->that.groups)) - { - passert(oriented(*c)); - if (routed(sr->routing)) - { - DESTROY_IF(peer_attributes); - return c; - } - unrouted = c; - } - } - - /* exact match? */ - d = fc_try(c, c->host_pair, NULL, our_net, peer_net - , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_attributes); - - DBG(DBG_CONTROLMORE, - DBG_log(" fc_try %s gives %s" - , c->name - , (d ? d->name : "none")) - ) - - if (d == NULL) - { - d = unrouted; - } - } - - if (d == NULL) - { - /* look for an abstract connection to match */ - struct spd_route *sr; - struct host_pair *hp = NULL; - - for (sr = &c->spd; hp==NULL && sr != NULL; sr = sr->next) - { - hp = find_host_pair(&sr->this.host_addr - , sr->this.host_port - , NULL - , sr->that.host_port); -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF]; - - subnettot(&sr->this.client, 0, s2, sizeof(s2)); - subnettot(&sr->that.client, 0, d2, sizeof(d2)); - - DBG_log(" checking hostpair %s -> %s is %s" - , s2, d2 - , (hp ? "found" : "not found")); - } -#endif /* DEBUG */ - } - - if (hp) - { - /* RW match with actual peer_id or abstract peer_id? */ - d = fc_try(c, hp, NULL, our_net, peer_net - , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_attributes); - - if (d == NULL - && subnetishost(our_net) - && subnetishost(peer_net)) - { - /* Opportunistic match? - * Always use abstract peer_id. - * Note that later instantiation will result in the same peer_id. - */ - d = fc_try_oppo(c, hp, our_net, peer_net - , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_attributes); - } - } - } - - DBG(DBG_CONTROLMORE, - DBG_log(" concluding with d = %s" - , (d ? d->name : "none")) - ) - DESTROY_IF(peer_attributes); - return d; -} - -int connection_compare(const connection_t *ca, const connection_t *cb) -{ - int ret; - - /* DBG_log("comparing %s to %s", ca->name, cb->name); */ - - ret = strcasecmp(ca->name, cb->name); - if (ret) - { - return ret; - } - - ret = ca->kind - cb->kind; /* note: enum connection_kind behaves like int */ - if (ret) - { - return ret; - } - - /* same name, and same type */ - switch (ca->kind) - { - case CK_INSTANCE: - return ca->instance_serial < cb->instance_serial ? -1 - : ca->instance_serial > cb->instance_serial ? 1 - : 0; - - default: - return ca->prio < cb->prio ? -1 - : ca->prio > cb->prio ? 1 - : 0; - } -} - -static int connection_compare_qsort(const void *a, const void *b) -{ - return connection_compare(*(const connection_t *const *)a - , *(const connection_t *const *)b); -} - -void show_connections_status(bool all, const char *name) -{ - connection_t *c; - int count, i; - connection_t **array; - - /* make an array of connections, and sort it */ - count = 0; - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->ikev1 && (name == NULL || streq(c->name, name))) - count++; - } - array = malloc(sizeof(connection_t *)*count); - - count=0; - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->ikev1 && (name == NULL || streq(c->name, name))) - array[count++]=c; - } - - /* sort it! */ - qsort(array, count, sizeof(connection_t *), connection_compare_qsort); - - for (i = 0; i < count; i++) - { - const char *ifn; - char instance[1 + 10 + 1]; - char prio[POLICY_PRIO_BUF]; - - c = array[i]; - - ifn = oriented(*c)? c->interface->rname : ""; - - instance[0] = '\0'; - if (c->kind == CK_INSTANCE && c->instance_serial != 0) - snprintf(instance, sizeof(instance), "[%lu]", c->instance_serial); - - /* show topology */ - { - char topo[BUF_LEN]; - struct spd_route *sr = &c->spd; - int num=0; - - while (sr) - { - (void) format_connection(topo, sizeof(topo), c, sr); - whack_log(RC_COMMENT, "\"%s\"%s: %s; %s; eroute owner: #%lu" - , c->name, instance, topo - , enum_name(&routing_story, sr->routing) - , sr->eroute_owner); - sr = sr->next; - num++; - } - } - - if (all) - { - /* show CAs if defined */ - if (c->spd.this.ca && c->spd.that.ca) - { - whack_log(RC_COMMENT, "\"%s\"%s: CAs: \"%Y\"...\"%Y\"", - c->name, instance, c->spd.this.ca, c->spd.that.ca); - } - else if (c->spd.this.ca) - { - whack_log(RC_COMMENT, "\"%s\"%s: CAs: \"%Y\"...%%any", - c->name, instance, c->spd.this.ca); - - } - else if (c->spd.that.ca) - { - whack_log(RC_COMMENT, "\"%s\"%s: CAs: %%any...\"%Y\"", - c->name, instance, c->spd.that.ca); - } - - /* show group attributes if defined */ - if (c->spd.that.groups) - { - whack_log(RC_COMMENT, "\"%s\"%s: groups: %s" - , c->name - , instance - , c->spd.that.groups->get_string(c->spd.that.groups)); - } - - whack_log(RC_COMMENT - , "\"%s\"%s: ike_life: %lus; ipsec_life: %lus;" - " rekey_margin: %lus; rekey_fuzz: %lu%%; keyingtries: %lu" - , c->name - , instance - , (unsigned long) c->sa_ike_life_seconds - , (unsigned long) c->sa_ipsec_life_seconds - , (unsigned long) c->sa_rekey_margin - , (unsigned long) c->sa_rekey_fuzz - , (unsigned long) c->sa_keying_tries); - - /* show DPD parameters if defined */ - - if (c->dpd_action != DPD_ACTION_NONE) - whack_log(RC_COMMENT - , "\"%s\"%s: dpd_action: %N;" - " dpd_delay: %lus; dpd_timeout: %lus;" - , c->name - , instance - , dpd_action_names, c->dpd_action - , (unsigned long) c->dpd_delay - , (unsigned long) c->dpd_timeout); - - if (c->policy_next) - { - whack_log(RC_COMMENT - , "\"%s\"%s: policy_next: %s" - , c->name, instance, c->policy_next->name); - } - - /* Note: we display key_from_DNS_on_demand as if policy [lr]KOD */ - fmt_policy_prio(c->prio, prio); - whack_log(RC_COMMENT - , "\"%s\"%s: policy: %s%s%s; prio: %s; interface: %s; " - , c->name - , instance - , prettypolicy(c->policy) - , c->spd.this.key_from_DNS_on_demand? "+lKOD" : "" - , c->spd.that.key_from_DNS_on_demand? "+rKOD" : "" - , prio - , ifn); - } - - whack_log(RC_COMMENT - , "\"%s\"%s: newest ISAKMP SA: #%ld; newest IPsec SA: #%ld; " - , c->name - , instance - , c->newest_isakmp_sa - , c->newest_ipsec_sa); - - if (all) - { - ike_alg_show_connection(c, instance); - kernel_alg_show_connection(c, instance); - } - } - if (count > 0) - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ - - free(array); -} - -/* struct pending, the structure representing Quick Mode - * negotiations delayed until a Keying Channel has been negotiated. - * Essentially, a pending call to quick_outI1. - */ - -struct pending { - int whack_sock; - struct state *isakmp_sa; - connection_t *connection; - lset_t policy; - unsigned long try; - so_serial_t replacing; - - struct pending *next; -}; - -/* queue a Quick Mode negotiation pending completion of a suitable Main Mode */ -void add_pending(int whack_sock, struct state *isakmp_sa, connection_t *c, - lset_t policy, unsigned long try, so_serial_t replacing) -{ - bool already_queued = FALSE; - struct pending *p = c->host_pair->pending; - - while (p) - { - if (streq(c->name, p->connection->name)) - { - already_queued = TRUE; - break; - } - p = p->next; - } - DBG(DBG_CONTROL, - DBG_log("Queuing pending Quick Mode with %s \"%s\"%s" - , ip_str(&c->spd.that.host_addr) - , c->name - , already_queued? " already done" : "") - ) - if (already_queued) - return; - - p = malloc_thing(struct pending); - p->whack_sock = whack_sock; - p->isakmp_sa = isakmp_sa; - p->connection = c; - p->policy = policy; - p->try = try; - p->replacing = replacing; - p->next = c->host_pair->pending; - c->host_pair->pending = p; -} - -/* Release all the whacks awaiting the completion of this state. - * This is accomplished by closing all the whack socket file descriptors. - * We go to a lot of trouble to tell each whack, but to not tell it twice. - */ -void release_pending_whacks(struct state *st, err_t story) -{ - struct pending *p; - struct stat stst; - - if (st->st_whack_sock == NULL_FD || fstat(st->st_whack_sock, &stst) != 0) - zero(&stst); /* resulting st_dev/st_ino ought to be distinct */ - - release_whack(st); - - for (p = st->st_connection->host_pair->pending; p != NULL; p = p->next) - { - if (p->isakmp_sa == st && p->whack_sock != NULL_FD) - { - struct stat pst; - - if (fstat(p->whack_sock, &pst) == 0 - && (stst.st_dev != pst.st_dev || stst.st_ino != pst.st_ino)) - { - passert(whack_log_fd == NULL_FD); - whack_log_fd = p->whack_sock; - whack_log(RC_COMMENT - , "%s for ISAKMP SA, but releasing whack for pending IPSEC SA" - , story); - whack_log_fd = NULL_FD; - } - close(p->whack_sock); - p->whack_sock = NULL_FD; - } - } -} - -static void delete_pending(struct pending **pp) -{ - struct pending *p = *pp; - - *pp = p->next; - if (p->connection) - { - connection_discard(p->connection); - } - close_any(p->whack_sock); - free(p); -} - -void unpend(struct state *st) -{ - struct pending **pp - , *p; - - for (pp = &st->st_connection->host_pair->pending; (p = *pp) != NULL; ) - { - if (p->isakmp_sa == st) - { - DBG(DBG_CONTROL, DBG_log("unqueuing pending Quick Mode with %s \"%s\"" - , ip_str(&p->connection->spd.that.host_addr) - , p->connection->name)); - (void) quick_outI1(p->whack_sock, st, p->connection, p->policy - , p->try, p->replacing); - p->whack_sock = NULL_FD; /* ownership transferred */ - p->connection = NULL; /* ownership transferred */ - delete_pending(pp); - } - else - { - pp = &p->next; - } - } -} - -/* a Main Mode negotiation has been replaced; update any pending */ -void update_pending(struct state *os, struct state *ns) -{ - struct pending *p; - - for (p = os->st_connection->host_pair->pending; p != NULL; p = p->next) - { - if (p->isakmp_sa == os) - p->isakmp_sa = ns; - if (p->connection->spd.this.host_port != ns->st_connection->spd.this.host_port) - { - p->connection->spd.this.host_port = ns->st_connection->spd.this.host_port; - p->connection->spd.that.host_port = ns->st_connection->spd.that.host_port; - } - } -} - -/* a Main Mode negotiation has failed; discard any pending */ -void flush_pending_by_state(struct state *st) -{ - struct host_pair *hp = st->st_connection->host_pair; - - if (hp) - { - struct pending **pp - , *p; - - for (pp = &hp->pending; (p = *pp) != NULL; ) - { - if (p->isakmp_sa == st) - delete_pending(pp); - else - pp = &p->next; - } - } -} - -/* a connection has been deleted; discard any related pending */ -static void flush_pending_by_connection(connection_t *c) -{ - if (c->host_pair) - { - struct pending **pp - , *p; - - for (pp = &c->host_pair->pending; (p = *pp) != NULL; ) - { - if (p->connection == c) - { - p->connection = NULL; /* prevent delete_pending from releasing */ - delete_pending(pp); - } - else - { - pp = &p->next; - } - } - } -} - -void show_pending_phase2(const struct host_pair *hp, const struct state *st) -{ - const struct pending *p; - - for (p = hp->pending; p != NULL; p = p->next) - { - if (p->isakmp_sa == st) - { - /* connection-name state-number [replacing state-number] */ - char cip[CONN_INST_BUF]; - - fmt_conn_instance(p->connection, cip); - whack_log(RC_COMMENT, "#%lu: pending Phase 2 for \"%s\"%s replacing #%lu" - , p->isakmp_sa->st_serialno - , p->connection->name - , cip - , p->replacing); - } - } -} - -/* Delete a connection if it is an instance and it is no longer in use. - * We must be careful to avoid circularity: - * we don't touch it if it is CK_GOING_AWAY. - */ -void connection_discard(connection_t *c) -{ - if (c->kind == CK_INSTANCE) - { - /* see if it is being used by a pending */ - struct pending *p; - - for (p = c->host_pair->pending; p != NULL; p = p->next) - if (p->connection == c) - return; /* in use, so we're done */ - - if (!states_use_connection(c)) - delete_connection(c, FALSE); - } -} - - -/* A template connection's eroute can be eclipsed by - * either a %hold or an eroute for an instance iff - * the template is a /32 -> /32. This requires some special casing. - */ - -long eclipse_count = 0; - -connection_t *eclipsed(connection_t *c, struct spd_route **esrp) -{ - connection_t *ue; - struct spd_route *sr1 = &c->spd; - - ue = NULL; - - while (sr1 && ue) - { - for (ue = connections; ue != NULL; ue = ue->ac_next) - { - struct spd_route *srue = &ue->spd; - - while (srue && srue->routing == RT_ROUTED_ECLIPSED - && !(samesubnet(&sr1->this.client, &srue->this.client) - && samesubnet(&sr1->that.client, &srue->that.client))) - { - srue = srue->next; - } - if (srue && srue->routing == RT_ROUTED_ECLIPSED) - { - *esrp = srue; - break; - } - } - } - return ue; -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/connections.h b/src/pluto/connections.h deleted file mode 100644 index e3775fcb0..000000000 --- a/src/pluto/connections.h +++ /dev/null @@ -1,366 +0,0 @@ -/* information about connections between hosts and clients - * Copyright (C) 1998-2001 D. Hugh Redelmeier - * Copyright (C) 2009-2010 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CONNECTIONS_H -#define _CONNECTIONS_H - -#include <sys/queue.h> - -#include <utils/host.h> -#include <utils/linked_list.h> -#include <utils/identification.h> -#include <credentials/ietf_attributes/ietf_attributes.h> - -#include "certs.h" -#include "smartcard.h" -#include "whack.h" - -/* There are two kinds of connections: - * - ISAKMP connections, between hosts (for IKE communication) - * - IPsec connections, between clients (for secure IP communication) - * - * An ISAKMP connection looks like: - * host<--->host - * - * An IPsec connection looks like: - * client-subnet<-->host<->nexthop<--->nexthop<->host<-->client-subnet - * - * For the connection to be relevant to this instance of Pluto, - * exactly one of the hosts must be a public interface of our machine - * known to this instance. - * - * The client subnet might simply be the host -- this is a - * representation of "host mode". - * - * Each nexthop defaults to the neighbouring host's IP address. - * The nexthop is a property of the pair of hosts, not each - * individually. It is only needed for IPsec because of the - * way IPsec is mixed into the kernel routing logic. Furthermore, - * only this end's nexthop is actually used. Eventually, nexthop - * will be unnecessary. - * - * Other information represented: - * - each connection has a name: a chunk of uninterpreted text - * that is unique for each connection. - * - security requirements (currently just the "policy" flags from - * the whack command to initiate the connection, but eventually - * much more. Different for ISAKMP and IPsec connections. - * - rekeying parameters: - * + time an SA may live - * + time before SA death that a rekeying should be attempted - * (only by the initiator) - * + number of times to attempt rekeying - * - With the current KLIPS, we must route packets for a client - * subnet through the ipsec interface (ipsec0). Only one - * gateway can get traffic for a specific (client) subnet. - * Furthermore, if the routing isn't in place, packets will - * be sent in the clear. - * "routing" indicates whether the routing has been done for - * this connection. Note that several connections may claim - * the same routing, as long as they agree about where the - * packets are to be sent. - * - With the current KLIPS, only one outbound IPsec SA bundle can be - * used for a particular client. This is due to a limitation - * of using only routing for selection. So only one IPsec state (SA) - * may "own" the eroute. "eroute_owner" is the serial number of - * this state, SOS_NOBODY if there is none. "routing" indicates - * what kind of erouting has been done for this connection, if any. - * - * Details on routing is in constants.h - * - * Operations on Connections: - * - * - add a new connection (with all details) [whack command] - * - delete a connection (by name) [whack command] - * - initiate a connection (by name) [whack command] - * - find a connection (by IP addresses of hosts) - * [response to peer request; finding ISAKMP connection for IPsec connection] - * - * Some connections are templates, missing the address of the peer - * (represented by INADDR_ANY). These are always arranged so that the - * missing end is "that" (there can only be one missing end). These can - * be instantiated (turned into real connections) by Pluto in one of two - * different ways: Road Warrior Instantiation or Opportunistic - * Instantiation. A template connection is marked for Opportunistic - * Instantiation by specifying the peer client as 0.0.0.0/32 (or the IPV6 - * equivalent). Otherwise, it is suitable for Road Warrior Instantiation. - * - * Instantiation creates a new temporary connection, with the missing - * details filled in. The resulting template lasts only as long as there - * is a state that uses it. - */ - -/* connection policy priority: how important this policy is - * - used to implement eroute-like precedence (augmented by a small - * bonus for a routed connection). - * - a whole number - * - larger is more important - * - three subcomponents. In order of decreasing significance: - * + length of source subnet mask (8 bits) - * + length of destination subnet mask (8 bits) - * + bias (8 bit) - * - a bias of 1 is added to allow prio BOTTOM_PRIO to be less than all - * normal priorities - * - other bias values are created on the fly to give mild preference - * to certaion conditions (eg. routedness) - * - priority is inherited -- an instance of a policy has the same priority - * as the original policy, even though its subnets might be smaller. - * - display format: n,m - */ -typedef unsigned long policy_prio_t; -#define BOTTOM_PRIO ((policy_prio_t)0) /* smaller than any real prio */ -#define set_policy_prio(c) { (c)->prio = \ - ((policy_prio_t)(c)->spd.this.client.maskbits << 16) \ - | ((policy_prio_t)(c)->spd.that.client.maskbits << 8) \ - | (policy_prio_t)1; } -#define POLICY_PRIO_BUF (3+1+3+1) -extern void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]); - -struct virtual_t; - -struct end { - identification_t *id; - ip_address host_addr, host_nexthop; - host_t *host_srcip; - ip_subnet client; - - bool is_left; - bool key_from_DNS_on_demand; - bool has_client; - bool has_client_wildcard; - bool has_port_wildcard; - bool has_id_wildcards; - bool has_natip; - char *updown; - u_int16_t host_port; /* host order */ - u_int16_t port; /* host order */ - u_int8_t protocol; - cert_t *cert; /* end certificate */ - identification_t *ca; /* CA distinguished name */ - ietf_attributes_t *groups; /* access control groups */ - smartcard_t *sc; /* smartcard reader and key info */ - struct virtual_t *virt; - bool modecfg; /* this end: request local address from server */ - /* that end: give local addresses to clients */ - char *pool; /* name of an associated virtual IP address pool */ - bool hostaccess; /* allow access to host via iptables INPUT/OUTPUT */ - /* rules if client behind host is a subnet */ - bool allow_any; /* IP address is subject to change */ - certpolicy_t sendcert; /* whether or not to send the certificate */ -}; - -struct spd_route { - struct spd_route *next; - struct end this; - struct end that; - so_serial_t eroute_owner; - enum routing_t routing; /* level of routing in place */ - uint32_t reqid; - mark_t mark_in; - mark_t mark_out; -}; - -typedef struct connection connection_t; - -struct connection { - char *name; - bool ikev1; - - lset_t policy; - time_t sa_ike_life_seconds; - time_t sa_ipsec_life_seconds; - time_t sa_rekey_margin; - unsigned long sa_rekey_fuzz; - unsigned long sa_keying_tries; - - identification_t *xauth_identity; /* XAUTH identity */ - - /* RFC 3706 DPD */ - time_t dpd_delay; - time_t dpd_timeout; - dpd_action_t dpd_action; - - char *log_file_name; /* name of log file */ - FILE *log_file; /* possibly open FILE */ - TAILQ_ENTRY(connection) log_link; /* linked list of open conns */ - bool log_file_err; /* only bitch once */ - - struct spd_route spd; - - /* internal fields: */ - - unsigned long instance_serial; - policy_prio_t prio; - bool instance_initiation_ok; /* this is an instance of a policy that mandates initiate */ - enum connection_kind kind; - const struct iface *interface; /* filled in iff oriented */ - - so_serial_t /* state object serial number */ - newest_isakmp_sa, - newest_ipsec_sa; - - -#ifdef DEBUG - lset_t extra_debugging; -#endif - - /* note: if the client is the gateway, the following must be equal */ - sa_family_t addr_family; /* between gateways */ - sa_family_t tunnel_addr_family; /* between clients */ - - connection_t *policy_next; /* if multiple policies, - next one to apply */ - struct gw_info *gw_info; - struct alg_info_esp *alg_info_esp; - struct alg_info_ike *alg_info_ike; - struct host_pair *host_pair; - connection_t *hp_next; /* host pair list link */ - connection_t *ac_next; /* all connections list link */ - linked_list_t *requested_ca; /* collected certificate requests */ - linked_list_t *requested; /* requested attributes with handlers */ - linked_list_t *attributes; /* configuration attributes with handlers */ - bool got_certrequest; -}; - -#define oriented(c) ((c).interface != NULL) -extern bool orient(connection_t *c); - -extern bool same_peer_ids(const connection_t *c, const connection_t *d, - identification_t *his_id); - -/* Format the topology of a connection end, leaving out defaults. - * Largest left end looks like: client === host : port [ host_id ] --- hop - * Note: if that==NULL, skip nexthop - */ -#define END_BUF (SUBNETTOT_BUF + ADDRTOT_BUF + IDTOA_BUF + ADDRTOT_BUF + 10) -extern size_t format_end(char *buf, size_t buf_len, const struct end *this, - const struct end *that, bool is_left, lset_t policy); - -extern void add_connection(const whack_message_t *wm); -extern void initiate_connection(const char *name, int whackfd); -extern void initiate_opportunistic(const ip_address *our_client, - const ip_address *peer_client, - int transport_proto, bool held, int whackfd); -extern void terminate_connection(const char *nm); -extern void release_connection(connection_t *c, bool relations); -extern void delete_connection(connection_t *c, bool relations); -extern void delete_connections_by_name(const char *name, bool strict); -extern void delete_every_connection(void); -extern char *add_group_instance(connection_t *group, const ip_subnet *target); -extern void remove_group_instance(const connection_t *group, const char *name); -extern void release_dead_interfaces(void); -extern void check_orientations(void); -extern connection_t *route_owner(connection_t *c, struct spd_route **srp, - connection_t **erop, struct spd_route **esrp); -extern connection_t *shunt_owner(const ip_subnet *ours, const ip_subnet *his); - -extern bool uniqueIDs; /* --uniqueids? */ -extern void ISAKMP_SA_established(connection_t *c, so_serial_t serial); - -#define id_is_ipaddr(id) ((id)->get_type(id) == ID_IPV4_ADDR || \ - (id)->get_type(id) == ID_IPV6_ADDR) -extern bool his_id_was_instantiated(const connection_t *c); - -struct state; /* forward declaration of tag (defined in state.h) */ - -extern connection_t* con_by_name(const char *nm, bool strict); -extern connection_t* find_host_connection(const ip_address *me, - u_int16_t my_port, - const ip_address *him, - u_int16_t his_port, lset_t policy); -extern connection_t* refine_host_connection(const struct state *st, - identification_t *id, - identification_t *peer_ca); -extern connection_t* find_client_connection(connection_t *c, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t out_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port); -extern connection_t* find_connection_by_reqid(uint32_t reqid); -extern connection_t* find_connection_for_clients(struct spd_route **srp, - const ip_address *our_client, - const ip_address *peer_client, - int transport_proto); -extern void get_peer_ca_and_groups(connection_t *c, - identification_t **peer_ca, - ietf_attributes_t **peer_attributes); - -/* instantiating routines - * Note: connection_discard() is in state.h because all its work - * is looking through state objects. - */ -struct gw_info; /* forward declaration of tag (defined in dnskey.h) */ -struct alg_info; /* forward declaration of tag (defined in alg_info.h) */ -extern connection_t *rw_instantiate(connection_t *c, - const ip_address *him, - u_int16_t his_port, - const ip_subnet *his_net, - identification_t *his_id); - -extern connection_t *oppo_instantiate(connection_t *c, - const ip_address *him, - identification_t *his_id, - struct gw_info *gw, - const ip_address *our_client, - const ip_address *peer_client); - -extern connection_t - *build_outgoing_opportunistic_connection(struct gw_info *gw, - const ip_address *our_client, - const ip_address *peer_client); - -#define CONN_INST_BUF BUF_LEN - -extern void fmt_conn_instance(const connection_t *c, char buf[CONN_INST_BUF]); - -/* operations on "pending", the structure representing Quick Mode - * negotiations delayed until a Keying Channel has been negotiated. - */ - -struct pending; /* forward declaration (opaque outside connections.c) */ - -extern void add_pending(int whack_sock, struct state *isakmp_sa, - connection_t *c, lset_t policy, unsigned long try, - so_serial_t replacing); - -extern void release_pending_whacks(struct state *st, err_t story); -extern void unpend(struct state *st); -extern void update_pending(struct state *os, struct state *ns); -extern void flush_pending_by_state(struct state *st); -extern void show_pending_phase2(const struct host_pair *hp, const struct state *st); - -extern void connection_discard(connection_t *c); - -/* A template connection's eroute can be eclipsed by - * either a %hold or an eroute for an instance iff - * the template is a /32 -> /32. This requires some special casing. - */ -#define eclipsable(sr) (subnetishost(&(sr)->this.client) && subnetishost(&(sr)->that.client)) -extern long eclipse_count; -extern connection_t *eclipsed(connection_t *c, struct spd_route **); - - -/* print connection status */ - -extern void show_connections_status(bool all, const char *name); -extern int connection_compare(const connection_t *ca - , const connection_t *cb); -extern void update_host_pair(const char *why, connection_t *c - , const ip_address *myaddr, u_int16_t myport - , const ip_address *hisaddr, u_int16_t hisport); - -#endif /* _CONNECTIONS_H */ diff --git a/src/pluto/constants.c b/src/pluto/constants.c deleted file mode 100644 index 73ec0bc54..000000000 --- a/src/pluto/constants.c +++ /dev/null @@ -1,1401 +0,0 @@ -/* tables of names for values defined in constants.h - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * Note that the array sizes are all specified; this is to enable range - * checking by code that only includes constants.h. - */ - -#include <stddef.h> -#include <string.h> -#include <stdio.h> -#include <netinet/in.h> - -#include <freeswan.h> - -#include <attributes/attributes.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "packet.h" - -/* string naming compile-time options that have interop implications */ - -const char compile_time_interop_options[] = "" -#ifdef THREADS - " THREADS" -#endif -#ifdef SMARTCARD - " SMARTCARD" -#endif -#ifdef VENDORID - " VENDORID" -#endif -#ifdef CISCO_QUIRKS - " CISCO_QUIRKS" -#endif -#ifdef USE_KEYRR - " KEYRR" -#endif - ; - -/* version */ - -static const char *const version_name[] = { - "ISAKMP Version 1.0", -}; - -enum_names version_names = - { ISAKMP_MAJOR_VERSION<<ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, - ISAKMP_MAJOR_VERSION<<ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, - version_name, NULL }; - -/* RFC 3706 Dead Peer Detection */ - -ENUM(dpd_action_names, DPD_ACTION_NONE, DPD_ACTION_RESTART, - "none", - "clear", - "hold", - "restart" -); - -/* Timer events */ - -ENUM(timer_event_names, EVENT_NULL, EVENT_LOG_DAILY, - "EVENT_NULL", - "EVENT_REINIT_SECRET", - "EVENT_SO_DISCARD", - "EVENT_RETRANSMIT", - "EVENT_SA_REPLACE", - "EVENT_SA_REPLACE_IF_USED", - "EVENT_SA_EXPIRE", - "EVENT_NAT_T_KEEPALIVE", - "EVENT_DPD", - "EVENT_DPD_TIMEOUT", - "EVENT_LOG_DAILY" -); - -/* Domain of Interpretation */ - -static const char *const doi_name[] = { - "ISAKMP_DOI_ISAKMP", - "ISAKMP_DOI_IPSEC", -}; - -enum_names doi_names = { ISAKMP_DOI_ISAKMP, ISAKMP_DOI_IPSEC, doi_name, NULL }; - -/* debugging settings: a set of selections for reporting - * These would be more naturally situated in log.h, - * but they are shared with whack. - * It turns out that "debug-" is clutter in all contexts this is used, - * so we leave it off. - */ -#ifdef DEBUG -const char *const debug_bit_names[] = { - "raw", - "crypt", - "parsing", - "emitting", - "control", - "lifecycle", - "kernel", - "dns", - "natt", - "oppo", - "controlmore", - - "private", - - "impair-delay-adns-key-answer", - "impair-delay-adns-txt-answer", - "impair-bust-mi2", - "impair-bust-mr2", - - NULL -}; -#endif - -/* State of exchanges */ - -static const char *const state_name[] = { - "STATE_UNDEFINED", - - "STATE_MAIN_R0", - "STATE_MAIN_I1", - "STATE_MAIN_R1", - "STATE_MAIN_I2", - "STATE_MAIN_R2", - "STATE_MAIN_I3", - "STATE_MAIN_R3", - "STATE_MAIN_I4", - - "STATE_QUICK_R0", - "STATE_QUICK_I1", - "STATE_QUICK_R1", - "STATE_QUICK_I2", - "STATE_QUICK_R2", - - "STATE_INFO", - "STATE_INFO_PROTECTED", - - "STATE_XAUTH_I0", - "STATE_XAUTH_R1", - "STATE_XAUTH_I1", - "STATE_XAUTH_R2", - "STATE_XAUTH_I2", - "STATE_XAUTH_R3", - - "STATE_MODE_CFG_R0", - "STATE_MODE_CFG_I1", - "STATE_MODE_CFG_R1", - "STATE_MODE_CFG_I2", - - "STATE_MODE_CFG_I0", - "STATE_MODE_CFG_R3", - "STATE_MODE_CFG_I3", - "STATE_MODE_CFG_R4", - - "STATE_IKE_ROOF" -}; - -enum_names state_names = - { STATE_UNDEFINED, STATE_IKE_ROOF-1, state_name, NULL }; - -/* story for state */ - -const char *const state_story[] = { - "undefined state after error", /* STATE_UNDEFINED */ - "expecting MI1", /* STATE_MAIN_R0 */ - "sent MI1, expecting MR1", /* STATE_MAIN_I1 */ - "sent MR1, expecting MI2", /* STATE_MAIN_R1 */ - "sent MI2, expecting MR2", /* STATE_MAIN_I2 */ - "sent MR2, expecting MI3", /* STATE_MAIN_R2 */ - "sent MI3, expecting MR3", /* STATE_MAIN_I3 */ - "sent MR3, ISAKMP SA established", /* STATE_MAIN_R3 */ - "ISAKMP SA established", /* STATE_MAIN_I4 */ - - "expecting QI1", /* STATE_QUICK_R0 */ - "sent QI1, expecting QR1", /* STATE_QUICK_I1 */ - "sent QR1, inbound IPsec SA installed, expecting QI2", /* STATE_QUICK_R1 */ - "sent QI2, IPsec SA established", /* STATE_QUICK_I2 */ - "IPsec SA established", /* STATE_QUICK_R2 */ - - "got Informational Message in clear", /* STATE_INFO */ - "got encrypted Informational Message", /* STATE_INFO_PROTECTED */ - - "expecting XAUTH request", /* STATE_XAUTH_I0 */ - "sent XAUTH request, expecting reply", /* STATE_XAUTH_R1 */ - "sent XAUTH reply, expecting status", /* STATE_XAUTH_I1 */ - "sent XAUTH status, expecting ack", /* STATE_XAUTH_R2 */ - "sent XAUTH ack, established", /* STATE_XAUTH_I2 */ - "received XAUTH ack, established", /* STATE_XAUTH_R3 */ - - "expecting ModeCfg request", /* STATE_MODE_CFG_R0 */ - "sent ModeCfg request, expecting reply", /* STATE_MODE_CFG_I1 */ - "sent ModeCfg reply, established", /* STATE_MODE_CFG_R1 */ - "received ModeCfg reply, established", /* STATE_MODE_CFG_I2 */ - - "expecting ModeCfg set", /* STATE_MODE_CFG_I0 */ - "sent ModeCfg set, expecting ack", /* STATE_MODE_CFG_R3 */ - "sent ModeCfg ack, established", /* STATE_MODE_CFG_I3 */ - "received ModeCfg ack, established", /* STATE_MODE_CFG_R4 */ -}; - -/* kind of struct connection */ - -static const char *const connection_kind_name[] = { - "CK_GROUP", /* policy group: instantiates to template */ - "CK_TEMPLATE", /* abstract connection, with wildcard */ - "CK_PERMANENT", /* normal connection */ - "CK_INSTANCE", /* instance of template, created for a particular attempt */ - "CK_GOING_AWAY" /* instance being deleted -- don't delete again */ -}; - -enum_names connection_kind_names = - { CK_GROUP, CK_GOING_AWAY, connection_kind_name, NULL }; - -/* routing status names */ - -static const char *const routing_story_strings[] = { - "unrouted", /* RT_UNROUTED: unrouted */ - "unrouted HOLD", /* RT_UNROUTED_HOLD: unrouted, but HOLD shunt installed */ - "eroute eclipsed", /* RT_ROUTED_ECLIPSED: RT_ROUTED_PROSPECTIVE except bare HOLD or instance has eroute */ - "prospective erouted", /* RT_ROUTED_PROSPECTIVE: routed, and prospective shunt installed */ - "erouted HOLD", /* RT_ROUTED_HOLD: routed, and HOLD shunt installed */ - "fail erouted", /* RT_ROUTED_FAILURE: routed, and failure-context shunt eroute installed */ - "erouted", /* RT_ROUTED_TUNNEL: routed, and erouted to an IPSEC SA group */ - "keyed, unrouted", /* RT_UNROUTED_KEYED: was routed+keyed, but it got turned into an outer policy */ -}; - -enum_names routing_story = - { RT_UNROUTED, RT_ROUTED_TUNNEL, routing_story_strings, NULL}; - -/* Payload types (RFC 2408 "ISAKMP" section 3.1) */ - -const char *const payload_name[] = { - "ISAKMP_NEXT_NONE", - "ISAKMP_NEXT_SA", - "ISAKMP_NEXT_P", - "ISAKMP_NEXT_T", - "ISAKMP_NEXT_KE", - "ISAKMP_NEXT_ID", - "ISAKMP_NEXT_CERT", - "ISAKMP_NEXT_CR", - "ISAKMP_NEXT_HASH", - "ISAKMP_NEXT_SIG", - "ISAKMP_NEXT_NONCE", - "ISAKMP_NEXT_N", - "ISAKMP_NEXT_D", - "ISAKMP_NEXT_VID", - "ISAKMP_NEXT_MODECFG", - "ISAKMP_NEXT_15", - "ISAKMP_NEXT_16", - "ISAKMP_NEXT_17", - "ISAKMP_NEXT_18", - "ISAKMP_NEXT_19", - "ISAKMP_NEXT_NAT-D", - "ISAKMP_NEXT_NAT-OA", - NULL -}; - -const char *const payload_name_nat_d[] = { - "ISAKMP_NEXT_NAT-D", - "ISAKMP_NEXT_NAT-OA", NULL -}; - -static enum_names payload_names_nat_d = - { ISAKMP_NEXT_NATD_DRAFTS, ISAKMP_NEXT_NATOA_DRAFTS, payload_name_nat_d, NULL }; - -enum_names payload_names = - { ISAKMP_NEXT_NONE, ISAKMP_NEXT_NATOA_RFC, payload_name, &payload_names_nat_d }; - -/* Exchange types (note: two discontinuous ranges) */ - -static const char *const exchange_name[] = { - "ISAKMP_XCHG_NONE", - "ISAKMP_XCHG_BASE", - "ISAKMP_XCHG_IDPROT", - "ISAKMP_XCHG_AO", - "ISAKMP_XCHG_AGGR", - "ISAKMP_XCHG_INFO", - "ISAKMP_XCHG_MODE_CFG", -}; - -static const char *const exchange_name2[] = { - "ISAKMP_XCHG_QUICK", - "ISAKMP_XCHG_NGRP", - "ISAKMP_XCHG_ACK_INFO", -}; - -static enum_names exchange_desc2 = - { ISAKMP_XCHG_QUICK, ISAKMP_XCHG_ACK_INFO, exchange_name2, NULL }; - -enum_names exchange_names = - { ISAKMP_XCHG_NONE, ISAKMP_XCHG_MODE_CFG, exchange_name, &exchange_desc2 }; - -/* Flag BITS */ -const char *const flag_bit_names[] = { - "ISAKMP_FLAG_ENCRYPTION", - "ISAKMP_FLAG_COMMIT", - NULL -}; - -/* Situation BITS definition for IPsec DOI */ - -const char *const sit_bit_names[] = { - "SIT_IDENTITY_ONLY", - "SIT_SECRECY", - "SIT_INTEGRITY", - NULL -}; - -/* Protocol IDs (RFC 2407 "IPsec DOI" section 4.4.1) */ - -static const char *const protocol_name[] = { - "PROTO_ISAKMP", - "PROTO_IPSEC_AH", - "PROTO_IPSEC_ESP", - "PROTO_IPCOMP", -}; - -enum_names protocol_names = - { PROTO_ISAKMP, PROTO_IPCOMP, protocol_name, NULL }; - -/* IPsec ISAKMP transform values */ - -static const char *const isakmp_transform_name[] = { - "KEY_IKE", -}; - -enum_names isakmp_transformid_names = - { KEY_IKE, KEY_IKE, isakmp_transform_name, NULL }; - -/* IPsec AH transform values */ - -static const char *const ah_transform_name[] = { - "HMAC_MD5", - "HMAC_SHA1", - "DES_MAC", - "HMAC_SHA2_256", - "HMAC_SHA2_384", - "HMAC_SHA2_512", - "HMAC_RIPEMD", - "AES_XCBC_96", - "SIG_RSA", - "AES_128_GMAC", - "AES_192_GMAC", - "AES_256_GMAC" -}; - -static const char *const ah_transform_name_high[] = { - "HMAC_SHA2_256_96" -}; - -enum_names ah_transform_names_high = - { AH_SHA2_256_96, AH_SHA2_256_96, ah_transform_name_high, NULL }; - -enum_names ah_transform_names = - { AH_MD5, AH_AES_256_GMAC, ah_transform_name, &ah_transform_names_high }; - -/* IPsec ESP transform values */ - -static const char *const esp_transform_name[] = { - "DES_IV64", - "DES_CBC", - "3DES_CBC", - "RC5_CBC", - "IDEA_CBC", - "CAST_CBC", - "BLOWFISH_CBC", - "3IDEA", - "DES_IV32", - "RC4", - "NULL", - "AES_CBC", - "AES_CTR", - "AES_CCM_8", - "AES_CCM_12", - "AES_CCM_16", - "UNASSIGNED_17", - "AES_GCM_8", - "AES_GCM_12", - "AES_GCM_16", - "SEED_CBC", - "CAMELLIA_CBC", - "AES_GMAC" -}; - -static const char *const esp_transform_name_high[] = { - "SERPENT_CBC", - "TWOFISH_CBC" -}; - -enum_names esp_transform_names_high = - { ESP_SERPENT, ESP_TWOFISH, esp_transform_name_high, NULL }; - -enum_names esp_transform_names = - { ESP_DES_IV64, ESP_AES_GMAC, esp_transform_name, &esp_transform_names_high }; - -/* IPCOMP transform values */ - -static const char *const ipcomp_transform_name[] = { - "IPCOMP_OUI", - "IPCOMP_DEFLATE", - "IPCOMP_LZS", - "IPCOMP_LZJH", -}; - -enum_names ipcomp_transformid_names = - { IPCOMP_OUI, IPCOMP_LZJH, ipcomp_transform_name, NULL }; - -/* Identification type values */ - -static const char *const ident_name[] = { - "ID_IPV4_ADDR", - "ID_FQDN", - "ID_USER_FQDN", - "ID_IPV4_ADDR_SUBNET", - "ID_IPV6_ADDR", - "ID_IPV6_ADDR_SUBNET", - "ID_IPV4_ADDR_RANGE", - "ID_IPV6_ADDR_RANGE", - "ID_DER_ASN1_DN", - "ID_DER_ASN1_GN", - "ID_KEY_ID", -}; - -enum_names ident_names = - { ID_IPV4_ADDR, ID_KEY_ID, ident_name, NULL }; - -/* Certificate type values */ - -static const char *const cert_type_name[] = { - "CERT_NONE", - "CERT_PKCS7_WRAPPED_X509", - "CERT_PGP", - "CERT_DNS_SIGNED_KEY", - "CERT_X509_SIGNATURE", - "CERT_X509_KEY_EXCHANGE", - "CERT_KERBEROS_TOKENS", - "CERT_CRL", - "CERT_ARL", - "CERT_SPKI", - "CERT_X509_ATTRIBUTE", -}; - -enum_names cert_type_names = - { CERT_NONE, CERT_X509_ATTRIBUTE, cert_type_name, NULL }; - -/* Certificate policy names */ - -ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND, - "ALWAYS_SEND", - "SEND_IF_ASKED", - "NEVER_SEND", -); - -/* Goal BITs for establishing an SA - * Note: we drop the POLICY_ prefix so that logs are more concise. - */ - -const char *const sa_policy_bit_names[] = { - "PSK", - "PUBKEY", - "ENCRYPT", - "AUTHENTICATE", - "COMPRESS", - "TUNNEL", - "PFS", - "DISABLEARRIVALCHECK", - "SHUNT0", - "SHUNT1", - "FAILSHUNT0", - "FAILSHUNT1", - "DONTREKEY", - "OPPORTUNISTIC", - "GROUP", - "GROUTED", - "UP", - "MODECFGPUSH", - "XAUTHPSK", - "XAUTHRSASIG", - "XAUTHSERVER", - "DONTREAUTH", - "BEET", - "MOBIKE", - "PROXY", - NULL -}; - -const char *const policy_shunt_names[4] = { - "TRAP", - "PASS", - "DROP", - "REJECT", -}; - -const char *const policy_fail_names[4] = { - "NONE", - "PASS", - "DROP", - "REJECT", -}; - -/* Oakley transform attributes - * oakley_attr_bit_names does double duty: it is used for enum names - * and bit names. - */ - -const char *const oakley_attr_bit_names[] = { - "OAKLEY_ENCRYPTION_ALGORITHM", - "OAKLEY_HASH_ALGORITHM", - "OAKLEY_AUTHENTICATION_METHOD", - "OAKLEY_GROUP_DESCRIPTION", - "OAKLEY_GROUP_TYPE", - "OAKLEY_GROUP_PRIME", - "OAKLEY_GROUP_GENERATOR_ONE", - "OAKLEY_GROUP_GENERATOR_TWO", - "OAKLEY_GROUP_CURVE_A", - "OAKLEY_GROUP_CURVE_B", - "OAKLEY_LIFE_TYPE", - "OAKLEY_LIFE_DURATION", - "OAKLEY_PRF", - "OAKLEY_KEY_LENGTH", - "OAKLEY_FIELD_SIZE", - "OAKLEY_GROUP_ORDER", - "OAKLEY_BLOCK_SIZE", - NULL -}; - -static const char *const oakley_var_attr_name[] = { - "OAKLEY_GROUP_PRIME (variable length)", - "OAKLEY_GROUP_GENERATOR_ONE (variable length)", - "OAKLEY_GROUP_GENERATOR_TWO (variable length)", - "OAKLEY_GROUP_CURVE_A (variable length)", - "OAKLEY_GROUP_CURVE_B (variable length)", - NULL, - "OAKLEY_LIFE_DURATION (variable length)", - NULL, - NULL, - NULL, - "OAKLEY_GROUP_ORDER (variable length)", -}; - -static enum_names oakley_attr_desc_tv = { - OAKLEY_ENCRYPTION_ALGORITHM + ISAKMP_ATTR_AF_TV, - OAKLEY_GROUP_ORDER + ISAKMP_ATTR_AF_TV, oakley_attr_bit_names, NULL }; - -enum_names oakley_attr_names = { - OAKLEY_GROUP_PRIME, OAKLEY_GROUP_ORDER, - oakley_var_attr_name, &oakley_attr_desc_tv }; - -/* for each Oakley attribute, which enum_names describes its values? */ -enum_names *oakley_attr_val_descs[] = { - NULL, /* (none) */ - &oakley_enc_names, /* OAKLEY_ENCRYPTION_ALGORITHM */ - &oakley_hash_names, /* OAKLEY_HASH_ALGORITHM */ - &oakley_auth_names, /* OAKLEY_AUTHENTICATION_METHOD */ - &oakley_group_names, /* OAKLEY_GROUP_DESCRIPTION */ - &oakley_group_type_names,/* OAKLEY_GROUP_TYPE */ - NULL, /* OAKLEY_GROUP_PRIME */ - NULL, /* OAKLEY_GROUP_GENERATOR_ONE */ - NULL, /* OAKLEY_GROUP_GENERATOR_TWO */ - NULL, /* OAKLEY_GROUP_CURVE_A */ - NULL, /* OAKLEY_GROUP_CURVE_B */ - &oakley_lifetime_names, /* OAKLEY_LIFE_TYPE */ - NULL, /* OAKLEY_LIFE_DURATION */ - &oakley_prf_names, /* OAKLEY_PRF */ - NULL, /* OAKLEY_KEY_LENGTH */ - NULL, /* OAKLEY_FIELD_SIZE */ - NULL, /* OAKLEY_GROUP_ORDER */ -}; - -/* IPsec DOI attributes (RFC 2407 "IPsec DOI" section 4.5) */ - -static const char *const ipsec_attr_name[] = { - "SA_LIFE_TYPE", - "SA_LIFE_DURATION", - "GROUP_DESCRIPTION", - "ENCAPSULATION_MODE", - "AUTH_ALGORITHM", - "KEY_LENGTH", - "KEY_ROUNDS", - "COMPRESS_DICT_SIZE", - "COMPRESS_PRIVATE_ALG", -}; - -static const char *const ipsec_var_attr_name[] = { - "SA_LIFE_DURATION (variable length)", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "COMPRESS_PRIVATE_ALG (variable length)", -}; - -static enum_names ipsec_attr_desc_tv = { - SA_LIFE_TYPE + ISAKMP_ATTR_AF_TV, - COMPRESS_PRIVATE_ALG + ISAKMP_ATTR_AF_TV, - ipsec_attr_name, NULL }; - -enum_names ipsec_attr_names = { - SA_LIFE_DURATION, COMPRESS_PRIVATE_ALG, - ipsec_var_attr_name, &ipsec_attr_desc_tv }; - -/* for each IPsec attribute, which enum_names describes its values? */ -enum_names *ipsec_attr_val_descs[] = { - NULL, /* (none) */ - &sa_lifetime_names, /* SA_LIFE_TYPE */ - NULL, /* SA_LIFE_DURATION */ - &oakley_group_names, /* GROUP_DESCRIPTION */ - &enc_mode_names, /* ENCAPSULATION_MODE */ - &auth_alg_names, /* AUTH_ALGORITHM */ - NULL, /* KEY_LENGTH */ - NULL, /* KEY_ROUNDS */ - NULL, /* COMPRESS_DICT_SIZE */ - NULL, /* COMPRESS_PRIVATE_ALG */ -}; - -/* SA Lifetime Type attribute */ - -static const char *const sa_lifetime_name[] = { - "SA_LIFE_TYPE_SECONDS", - "SA_LIFE_TYPE_KBYTES", -}; - -enum_names sa_lifetime_names = - { SA_LIFE_TYPE_SECONDS, SA_LIFE_TYPE_KBYTES, sa_lifetime_name, NULL }; - -/* Encapsulation Mode attribute */ - -static const char *const enc_mode_name[] = { - "ENCAPSULATION_MODE_TUNNEL", - "ENCAPSULATION_MODE_TRANSPORT", - "ENCAPSULATION_MODE_UDP_TUNNEL", - "ENCAPSULATION_MODE_UDP_TRANSPORT", -}; - -static const char *const enc_udp_mode_name[] = { - "ENCAPSULATION_MODE_UDP_TUNNEL", - "ENCAPSULATION_MODE_UDP_TRANSPORT", - }; - -static enum_names enc_udp_mode_names = - { ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS, ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS, enc_udp_mode_name, NULL }; - -enum_names enc_mode_names = - { ENCAPSULATION_MODE_TUNNEL, ENCAPSULATION_MODE_UDP_TRANSPORT_RFC, enc_mode_name, &enc_udp_mode_names }; - -/* Auth Algorithm attribute */ - -static const char *const auth_alg_name[] = { - "AUTH_NONE", - "HMAC_MD5", - "HMAC_SHA1", - "DES_MAC", - "KPDK", - "HMAC_SHA2_256", - "HMAC_SHA2_384", - "HMAC_SHA2_512", - "HMAC_RIPEMD", - "AES_XCBC_96", - "SIG_RSA" -}; - -static const char *const extended_auth_alg_name[] = { - "NULL", - "HMAC_SHA2_256_96" -}; - -enum_names extended_auth_alg_names = - { AUTH_ALGORITHM_NULL, AUTH_ALGORITHM_HMAC_SHA2_256_96, - extended_auth_alg_name, NULL }; - -enum_names auth_alg_names = - { AUTH_ALGORITHM_NONE, AUTH_ALGORITHM_SIG_RSA, - auth_alg_name, &extended_auth_alg_names }; - -/* From draft-beaulieu-ike-xauth */ -static const char *const xauth_type_name[] = { - "Generic", - "RADIUS-CHAP", - "OTP", - "S/KEY", -}; - -enum_names xauth_type_names = - { XAUTH_TYPE_GENERIC, XAUTH_TYPE_SKEY, xauth_type_name, NULL}; - -/* From draft-beaulieu-ike-xauth */ -static const char *const xauth_attr_tv_name[] = { - "XAUTH_TYPE", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "XAUTH_STATUS", -}; - -enum_names xauth_attr_tv_names = { - XAUTH_TYPE + ISAKMP_ATTR_AF_TV, - XAUTH_STATUS + ISAKMP_ATTR_AF_TV, xauth_attr_tv_name, NULL }; - -static const char *const unity_attr_name[] = { - "UNITY_BANNER", - "UNITY_SAVE_PASSWD", - "UNITY_DEF_DOMAIN", - "UNITY_SPLITDNS_NAME", - "UNITY_SPLIT_INCLUDE", - "UNITY_NATT_PORT", - "UNITY_LOCAL_LAN", - "UNITY_PFS", - "UNITY_FW_TYPE", - "UNITY_BACKUP_SERVERS", - "UNITY_DDNS_HOSTNAME", -}; - -enum_names unity_attr_names = - { UNITY_BANNER , UNITY_DDNS_HOSTNAME, unity_attr_name , &xauth_attr_tv_names }; - -static const char *const microsoft_attr_name[] = { - "INTERNAL_IP4_SERVER", - "INTERNAL_IP6_SERVER", -}; - -enum_names microsoft_attr_names = - { INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER, microsoft_attr_name , &unity_attr_names }; - -static const char *const xauth_attr_name[] = { - "XAUTH_USER_NAME", - "XAUTH_USER_PASSWORD", - "XAUTH_PASSCODE", - "XAUTH_MESSAGE", - "XAUTH_CHALLENGE", - "XAUTH_DOMAIN", - "XAUTH_STATUS (wrong TLV syntax, should be TV)", - "XAUTH_NEXT_PIN", - "XAUTH_ANSWER", -}; - -enum_names xauth_attr_names = - { XAUTH_USER_NAME , XAUTH_ANSWER, xauth_attr_name , µsoft_attr_names }; - -static const char *const modecfg_attr_name[] = { - "INTERNAL_IP4_ADDRESS", - "INTERNAL_IP4_NETMASK", - "INTERNAL_IP4_DNS", - "INTERNAL_IP4_NBNS", - "INTERNAL_ADDRESS_EXPIRY", - "INTERNAL_IP4_DHCP", - "APPLICATION_VERSION", - "INTERNAL_IP6_ADDRESS", - "INTERNAL_IP6_NETMASK", - "INTERNAL_IP6_DNS", - "INTERNAL_IP6_NBNS", - "INTERNAL_IP6_DHCP", - "INTERNAL_IP4_SUBNET", - "SUPPORTED_ATTRIBUTES", - "INTERNAL_IP6_SUBNET", -}; - -enum_names modecfg_attr_names = - { INTERNAL_IP4_ADDRESS, INTERNAL_IP6_SUBNET, modecfg_attr_name , &xauth_attr_names }; - -/* Oakley Lifetime Type attribute */ - -static const char *const oakley_lifetime_name[] = { - "OAKLEY_LIFE_SECONDS", - "OAKLEY_LIFE_KILOBYTES", -}; - -enum_names oakley_lifetime_names = - { OAKLEY_LIFE_SECONDS, OAKLEY_LIFE_KILOBYTES, oakley_lifetime_name, NULL }; - -/* Oakley PRF attribute (none defined) */ - -enum_names oakley_prf_names = - { 1, 0, NULL, NULL }; - -/* Oakley Encryption Algorithm attribute */ - -static const char *const oakley_enc_name[] = { - "DES_CBC", - "IDEA_CBC", - "BLOWFISH_CBC", - "RC5_R16_B64_CBC", - "3DES_CBC", - "CAST_CBC", - "AES_CBC", - "CAMELLIA_CBC" -}; - -#ifdef NO_EXTRA_IKE -enum_names oakley_enc_names = - { OAKLEY_DES_CBC, OAKLEY_CAMELLIA_CBC, oakley_enc_name, NULL }; -#else -static const char *const oakley_enc_name_draft_aes_cbc_02[] = { - "MARS_CBC" /* 65001 */, - "RC6_CBC" /* 65002 */, - "ID_65003" /* 65003 */, - "SERPENT_CBC" /* 65004 */, - "TWOFISH_CBC" /* 65005 */, -}; - -static const char *const oakley_enc_name_ssh[] = { - "TWOFISH_CBC_SSH", -}; - -enum_names oakley_enc_names_ssh = - { OAKLEY_TWOFISH_CBC_SSH, OAKLEY_TWOFISH_CBC_SSH, oakley_enc_name_ssh - , NULL }; - -enum_names oakley_enc_names_draft_aes_cbc_02 = - { OAKLEY_MARS_CBC, OAKLEY_TWOFISH_CBC, oakley_enc_name_draft_aes_cbc_02 - , &oakley_enc_names_ssh }; - -enum_names oakley_enc_names = - { OAKLEY_DES_CBC, OAKLEY_CAMELLIA_CBC, oakley_enc_name - , &oakley_enc_names_draft_aes_cbc_02 }; -#endif - -/* Oakley Hash Algorithm attribute */ - -static const char *const oakley_hash_name[] = { - "HMAC_MD5", - "HMAC_SHA1", - "HMAC_TIGER", - "HMAC_SHA2_256", - "HMAC_SHA2_384", - "HMAC_SHA2_512", -}; - -enum_names oakley_hash_names = - { OAKLEY_MD5, OAKLEY_SHA2_512, oakley_hash_name, NULL }; - -/* Oakley Authentication Method attribute */ - -static const char *const oakley_auth_name1[] = { - "pre-shared key", - "DSS signature", - "RSA signature", - "RSA encryption", - "RSA encryption revised", - "ElGamal encryption", - "ELGamal encryption revised", - "ECDSA signature", - "ECDSA-256 signature", - "ECDSA-384 signature", - "ECDSA-521-signature", -}; - -static const char *const oakley_auth_name2[] = { - "HybridInitRSA", - "HybridRespRSA", - "HybridInitDSS", - "HybridRespDSS", -}; - -static const char *const oakley_auth_name3[] = { - "XAUTHInitPreShared", - "XAUTHRespPreShared", - "XAUTHInitDSS", - "XAUTHRespDSS", - "XAUTHInitRSA", - "XAUTHRespRSA", - "XAUTHInitRSAEncryption", - "XAUTHRespRSAEncryption", - "XAUTHInitRSARevisedEncryption", - "XAUTHRespRSARevisedEncryption", -}; - -static enum_names oakley_auth_names1 = - { OAKLEY_PRESHARED_KEY, OAKLEY_ECDSA_521 - , oakley_auth_name1, NULL }; - -static enum_names oakley_auth_names2 = - { HybridInitRSA, HybridRespDSS - , oakley_auth_name2, &oakley_auth_names1 }; - -enum_names oakley_auth_names = - { XAUTHInitPreShared, XAUTHRespRSARevisedEncryption - , oakley_auth_name3, &oakley_auth_names2 }; - -/* Oakley Group Description attribute */ - -static const char *const oakley_group_name[] = { - "MODP_768", - "MODP_1024", - "GP_155", - "GP_185", - "MODP_1536", -}; - -static const char *const oakley_group_name_rfc3526[] = { - "MODP_2048", - "MODP_3072", - "MODP_4096", - "MODP_6144", - "MODP_8192" -}; - -static const char *const oakley_group_name_rfc4753[] = { - "ECP_256", - "ECP_384", - "ECP_521" -}; - -static const char *const oakley_group_name_rfc5114[] = { - "MODP_1024_160", - "MODP_2048_224", - "MODP_2048_256", - "ECP_192", - "ECP_224" -}; - -enum_names oakley_group_names_rfc5114 = - { MODP_1024_160, ECP_224_BIT, - oakley_group_name_rfc5114, NULL }; - -enum_names oakley_group_names_rfc4753 = - { ECP_256_BIT, ECP_521_BIT, - oakley_group_name_rfc4753, &oakley_group_names_rfc5114 }; - -enum_names oakley_group_names_rfc3526 = - { MODP_2048_BIT, MODP_8192_BIT, - oakley_group_name_rfc3526, &oakley_group_names_rfc4753 }; - -enum_names oakley_group_names = - { MODP_768_BIT, MODP_1536_BIT, - oakley_group_name, &oakley_group_names_rfc3526 }; - -/* Oakley Group Type attribute */ - -static const char *const oakley_group_type_name[] = { - "OAKLEY_GROUP_TYPE_MODP", - "OAKLEY_GROUP_TYPE_ECP", - "OAKLEY_GROUP_TYPE_EC2N", -}; - -enum_names oakley_group_type_names = - { OAKLEY_GROUP_TYPE_MODP, OAKLEY_GROUP_TYPE_EC2N, oakley_group_type_name, NULL }; - -/* Notify messages -- error types */ - -static const char *const notification_name[] = { - "INVALID_PAYLOAD_TYPE", - "DOI_NOT_SUPPORTED", - "SITUATION_NOT_SUPPORTED", - "INVALID_COOKIE", - "INVALID_MAJOR_VERSION", - "INVALID_MINOR_VERSION", - "INVALID_EXCHANGE_TYPE", - "INVALID_FLAGS", - "INVALID_MESSAGE_ID", - "INVALID_PROTOCOL_ID", - "INVALID_SPI", - "INVALID_TRANSFORM_ID", - "ATTRIBUTES_NOT_SUPPORTED", - "NO_PROPOSAL_CHOSEN", - "BAD_PROPOSAL_SYNTAX", - "PAYLOAD_MALFORMED", - "INVALID_KEY_INFORMATION", - "INVALID_ID_INFORMATION", - "INVALID_CERT_ENCODING", - "INVALID_CERTIFICATE", - "CERT_TYPE_UNSUPPORTED", - "INVALID_CERT_AUTHORITY", - "INVALID_HASH_INFORMATION", - "AUTHENTICATION_FAILED", - "INVALID_SIGNATURE", - "ADDRESS_NOTIFICATION", - "NOTIFY_SA_LIFETIME", - "CERTIFICATE_UNAVAILABLE", - "UNSUPPORTED_EXCHANGE_TYPE", - "UNEQUAL_PAYLOAD_LENGTHS", -}; - -static const char *const notification_status_name[] = { - "CONNECTED", -}; - -static const char *const ipsec_notification_name[] = { - "IPSEC_RESPONDER_LIFETIME", - "IPSEC_REPLAY_STATUS", - "IPSEC_INITIAL_CONTACT", -}; - -static const char *const notification_dpd_name[] = { - "R_U_THERE", - "R_U_THERE_ACK", -}; - -static const char *const notification_juniper_name[] = { - "NS_NHTB_INFORM", -}; - -enum_names notification_juniper_names = - { NS_NHTB_INFORM, NS_NHTB_INFORM, - notification_juniper_name, NULL }; - -enum_names notification_dpd_names = - { R_U_THERE, R_U_THERE_ACK, - notification_dpd_name, ¬ification_juniper_names }; - -enum_names ipsec_notification_names = - { IPSEC_RESPONDER_LIFETIME, IPSEC_INITIAL_CONTACT, - ipsec_notification_name, ¬ification_dpd_names }; - -enum_names notification_status_names = - { ISAKMP_CONNECTED, ISAKMP_CONNECTED, - notification_status_name, &ipsec_notification_names }; - -enum_names notification_names = - { ISAKMP_INVALID_PAYLOAD_TYPE, ISAKMP_UNEQUAL_PAYLOAD_LENGTHS, - notification_name, ¬ification_status_names }; - -/* MODECFG - * From draft-dukes-ike-mode-cfg - */ -const char *const attr_msg_type_name[] = { - "ISAKMP_CFG_RESERVED", - "ISAKMP_CFG_REQUEST", - "ISAKMP_CFG_REPLY", - "ISAKMP_CFG_SET", - "ISAKMP_CFG_ACK", - NULL -}; - -enum_names attr_msg_type_names = - { 0 , ISAKMP_CFG_ACK, attr_msg_type_name , NULL }; - -/* socket address family info */ - -static const char *const af_inet_name[] = { - "AF_INET", -}; - -static const char *const af_inet6_name[] = { - "AF_INET6", -}; - -static enum_names af_names6 = { AF_INET6, AF_INET6, af_inet6_name, NULL }; - -enum_names af_names = { AF_INET, AF_INET, af_inet_name, &af_names6 }; - -static ip_address ipv4_any, ipv6_any; -static ip_subnet ipv4_wildcard, ipv6_wildcard; -static ip_subnet ipv4_all, ipv6_all; - -const struct af_info af_inet4_info = { - AF_INET, - "AF_INET", - sizeof(struct in_addr), - sizeof(struct sockaddr_in), - 32, - ID_IPV4_ADDR, ID_IPV4_ADDR_SUBNET, ID_IPV4_ADDR_RANGE, - &ipv4_any, &ipv4_wildcard, &ipv4_all, -}; - -const struct af_info af_inet6_info = { - AF_INET6, - "AF_INET6", - sizeof(struct in6_addr), - sizeof(struct sockaddr_in6), - 128, - ID_IPV6_ADDR, ID_IPV6_ADDR_SUBNET, ID_IPV6_ADDR_RANGE, - &ipv6_any, &ipv6_wildcard, &ipv6_all, -}; - -const struct af_info * -aftoinfo(int af) -{ - switch (af) - { - case AF_INET: - return &af_inet4_info; - case AF_INET6: - return &af_inet6_info; - default: - return NULL; - } -} - -bool subnetisnone(const ip_subnet *sn) -{ - ip_address base; - - networkof(sn, &base); - return isanyaddr(&base) && subnetishost(sn); -} - -#ifdef ADNS - -/* BIND enumerated types */ - -#include <arpa/nameser.h> - -static const char *const rr_type_name[] = { - "T_A", /* 1 host address */ - "T_NS", /* 2 authoritative server */ - "T_MD", /* 3 mail destination */ - "T_MF", /* 4 mail forwarder */ - "T_CNAME", /* 5 canonical name */ - "T_SOA", /* 6 start of authority zone */ - "T_MB", /* 7 mailbox domain name */ - "T_MG", /* 8 mail group member */ - "T_MR", /* 9 mail rename name */ - "T_NULL", /* 10 null resource record */ - "T_WKS", /* 11 well known service */ - "T_PTR", /* 12 domain name pointer */ - "T_HINFO", /* 13 host information */ - "T_MINFO", /* 14 mailbox information */ - "T_MX", /* 15 mail routing information */ - "T_TXT", /* 16 text strings */ - "T_RP", /* 17 responsible person */ - "T_AFSDB", /* 18 AFS cell database */ - "T_X25", /* 19 X_25 calling address */ - "T_ISDN", /* 20 ISDN calling address */ - "T_RT", /* 21 router */ - "T_NSAP", /* 22 NSAP address */ - "T_NSAP_PTR", /* 23 reverse NSAP lookup (deprecated) */ - "T_SIG", /* 24 security signature */ - "T_KEY", /* 25 security key */ - "T_PX", /* 26 X.400 mail mapping */ - "T_GPOS", /* 27 geographical position (withdrawn) */ - "T_AAAA", /* 28 IP6 Address */ - "T_LOC", /* 29 Location Information */ - "T_NXT", /* 30 Next Valid Name in Zone */ - "T_EID", /* 31 Endpoint identifier */ - "T_NIMLOC", /* 32 Nimrod locator */ - "T_SRV", /* 33 Server selection */ - "T_ATMA", /* 34 ATM Address */ - "T_NAPTR", /* 35 Naming Authority PoinTeR */ - NULL -}; - -enum_names rr_type_names = { T_A, T_NAPTR, rr_type_name, NULL }; - -/* Query type values which do not appear in resource records */ -static const char *const rr_qtype_name[] = { - "T_IXFR", /* 251 incremental zone transfer */ - "T_AXFR", /* 252 transfer zone of authority */ - "T_MAILB", /* 253 transfer mailbox records */ - "T_MAILA", /* 254 transfer mail agent records */ - "T_ANY", /* 255 wildcard match */ - NULL -}; - -enum_names rr_qtype_names = { T_IXFR, T_ANY, rr_qtype_name, &rr_type_names }; - -static const char *const rr_class_name[] = { - "C_IN", /* 1 the arpa internet */ - NULL -}; - -enum_names rr_class_names = { C_IN, C_IN, rr_class_name, NULL }; - -#endif /* ADNS */ - -/* - * NAT-Traversal defines for nat_traveral type from nat_traversal.h - * - */ -const char *const natt_type_bitnames[] = { - "draft-ietf-ipsec-nat-t-ike-00/01", /* 0 */ - "draft-ietf-ipsec-nat-t-ike-02/03", - "RFC 3947", - "3", /* 3 */ - "4", "5", "6", "7", - "8", "9", "10", "11", - "12", "13", "14", "15", - "16", "17", "18", "19", - "20", "21", "22", "23", - "24", "25", "26", "27", - "28", "29", - "nat is behind me", - "nat is behind peer" -}; - -/* look up enum names in an enum_names */ - -const char* enum_name(enum_names *ed, unsigned long val) -{ - enum_names *p; - - for (p = ed; p != NULL; p = p->en_next_range) - { - if (p->en_first <= val && val <= p->en_last) - return p->en_names[val - p->en_first]; - } - return NULL; -} - -/* find or construct a string to describe an enum value - * Result may be in STATIC buffer! - */ -const char * -enum_show(enum_names *ed, unsigned long val) -{ - const char *p = enum_name(ed, val); - - if (p == NULL) - { - static char buf[12]; /* only one! I hope that it is big enough */ - - snprintf(buf, sizeof(buf), "%lu??", val); - p = buf; - } - return p; -} - - -static char bitnamesbuf[200]; /* only one! I hope that it is big enough! */ - -int -enum_search(enum_names *ed, const char *str) -{ - enum_names *p; - const char *ptr; - unsigned en; - - for (p = ed; p != NULL; p = p->en_next_range) - { - for (en = p->en_first; en <= p->en_last ;en++) - { - ptr = p->en_names[en - p->en_first]; - if (ptr == 0) - { - continue; - } - if (streq(ptr, str)) - { - return en; - } - } - } - return -1; -} - -/* construct a string to name the bits on in a set - * Result may be in STATIC buffer! - * Note: prettypolicy depends on internal details. - */ -const char* bitnamesof(const char *const table[], lset_t val) -{ - char *p = bitnamesbuf; - lset_t bit; - const char *const *tp; - - if (val == 0) - return "none"; - - for (tp = table, bit = 01; val != 0; bit <<= 1) - { - if (val & bit) - { - const char *n = *tp; - size_t nl; - - if (n == NULL || *n == '\0') - { - /* no name for this bit, so use hex */ - static char flagbuf[sizeof("0x80000000")]; - - snprintf(flagbuf, sizeof(flagbuf), "0x%llx", bit); - n = flagbuf; - } - - nl = strlen(n); - - if (p != bitnamesbuf && p < bitnamesbuf+sizeof(bitnamesbuf) - 1) - *p++ = '+'; - - if (bitnamesbuf+sizeof(bitnamesbuf) - p > (ptrdiff_t)nl) - { - strcpy(p, n); - p += nl; - } - val -= bit; - } - if (*tp != NULL) - tp++; /* move on, but not past end */ - } - *p = '\0'; - return bitnamesbuf; -} - -/* print a policy: like bitnamesof, but it also does the non-bitfields. - * Suppress the shunt and fail fields if 0. - */ -const char* prettypolicy(lset_t policy) -{ - const char *bn = bitnamesof(sa_policy_bit_names - , policy & ~(POLICY_SHUNT_MASK | POLICY_FAIL_MASK)); - size_t len; - lset_t shunt = (policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT; - lset_t fail = (policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT; - - if (bn != bitnamesbuf) - bitnamesbuf[0] = '\0'; - len = strlen(bitnamesbuf); - if (shunt != 0) - { - snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+%s" - , policy_shunt_names[shunt]); - len += strlen(bitnamesbuf + len); - } - if (fail != 0) - { - snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+failure%s" - , policy_fail_names[fail]); - len += strlen(bitnamesbuf + len); - } - if (NEVER_NEGOTIATE(policy)) - { - snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+NEVER_NEGOTIATE"); - len += strlen(bitnamesbuf + len); - } - return bitnamesbuf; -} - -/* test a set by seeing if all bits have names */ - -bool testset(const char *const table[], lset_t val) -{ - lset_t bit; - const char *const *tp; - - for (tp = table, bit = 01; val != 0; bit <<= 1, tp++) - { - const char *n = *tp; - - if (n == NULL || ((val & bit) && *n == '\0')) - return FALSE; - val &= ~bit; - } - return TRUE; -} - - -const char sparse_end[] = "end of sparse names"; - -/* look up enum names in a sparse_names */ -const char *sparse_name(sparse_names sd, unsigned long val) -{ - const struct sparse_name *p; - - for (p = sd; p->name != sparse_end; p++) - if (p->val == val) - return p->name; - return NULL; -} - -/* find or construct a string to describe an sparse value - * Result may be in STATIC buffer! - */ -const char* sparse_val_show(sparse_names sd, unsigned long val) -{ - const char *p = sparse_name(sd, val); - - if (p == NULL) - { - static char buf[12]; /* only one! I hope that it is big enough */ - - snprintf(buf, sizeof(buf), "%lu??", val); - p = buf; - } - return p; -} - -void init_constants(void) -{ - happy(anyaddr(AF_INET, &ipv4_any)); - happy(anyaddr(AF_INET6, &ipv6_any)); - - happy(addrtosubnet(&ipv4_any, &ipv4_wildcard)); - happy(addrtosubnet(&ipv6_any, &ipv6_wildcard)); - - happy(initsubnet(&ipv4_any, 0, '0', &ipv4_all)); - happy(initsubnet(&ipv6_any, 0, '0', &ipv6_all)); -} - -u_char secret_of_the_day[HASH_SIZE_SHA1]; - - diff --git a/src/pluto/constants.h b/src/pluto/constants.h deleted file mode 100644 index c931f1782..000000000 --- a/src/pluto/constants.h +++ /dev/null @@ -1,1099 +0,0 @@ -/* manifest constants - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CONSTANTS_H -#define _CONSTANTS_H - -#include <freeswan.h> - -#include <kernel/kernel_ipsec.h> - -#include <utils.h> -#include <utils/identification.h> -#include <crypto/hashers/hasher.h> - -extern const char compile_time_interop_options[]; - -extern void init_constants(void); - -/* - * NOTE:For debugging purposes, constants.c has tables to map numbers back to names. - * Any changes here should be reflected there. - */ - -/* Many routines return only success or failure, but wish to describe - * the failure in a message. We use the convention that they return - * a NULL on success and a pointer to constant string on failure. - * The fact that the string is a constant is limiting, but it - * avoids storage management issues: the recipient is allowed to assume - * that the string will live "long enough" (usually forever). - * <freeswan.h> defines err_t for this return type. - */ - -#define NULL_FD (-1) /* NULL file descriptor */ -#define dup_any(fd) ((fd) == NULL_FD? NULL_FD : dup(fd)) -#define close_any(fd) { if ((fd) != NULL_FD) { close(fd); (fd) = NULL_FD; } } - -/* set type with room for at least 64 elements for ALG opts (was 32 in stock FS) */ - -typedef unsigned long long lset_t; -#define LEMPTY 0ULL -#define LELEM(opt) (1ULL << (opt)) -#define LRANGE(lwb, upb) LRANGES(LELEM(lwb), LELEM(upb)) -#define LRANGES(first, last) (last - first + last) -#define LHAS(set, elem) ((LELEM(elem) & (set)) != LEMPTY) -#define LIN(subset, set) (((subset) & (set)) == (subset)) -#define LDISJOINT(a, b) (((a) & (b)) == LEMPTY) - -/* Control and lock pathnames */ -#ifndef IPSEC_PIDDIR -# define IPSEC_PIDDIR "/var/run" -#endif -#ifndef DEFAULT_CTLBASE -# define DEFAULT_CTLBASE IPSEC_PIDDIR "/pluto" -#endif - -#define CTL_SUFFIX ".ctl" /* for UNIX domain socket pathname */ -#define LOCK_SUFFIX ".pid" /* for pluto's lock */ -#define INFO_SUFFIX ".info" /* for UNIX domain socket for apps */ - -/* Routines to check and display values. - * - * An enum_names describes an enumeration. - * enum_name() returns the name of an enum value, or NULL if invalid. - * enum_show() is like enum_name, except it formats a numeric representation - * for any invalid value (in a static area!) - * - * bitnames() formats a display of a set of named bits (in a static area) - */ - -struct enum_names { - unsigned long en_first; /* first value in range */ - unsigned long en_last; /* last value in range (inclusive) */ - const char *const *en_names; - const struct enum_names *en_next_range; /* descriptor of next range */ -}; - -typedef const struct enum_names enum_names; - -extern const char *enum_name(enum_names *ed, unsigned long val); -extern const char *enum_show(enum_names *ed, unsigned long val); -extern int enum_search(enum_names *ed, const char *string); - -extern bool testset(const char *const table[], lset_t val); -extern const char *bitnamesof(const char *const table[], lset_t val); - -/* sparse_names is much like enum_names, except values are - * not known to be contiguous or ordered. - * The array of names is ended with one with the name sparse_end - * (this avoids having to reserve a value to signify the end). - * Often appropriate for enums defined by others. - */ -struct sparse_name { - unsigned long val; - const char *const name; -}; -typedef const struct sparse_name sparse_names[]; - -extern const char *sparse_name(sparse_names sd, unsigned long val); -extern const char *sparse_val_show(sparse_names sd, unsigned long val); -extern const char sparse_end[]; - -#define FULL_INET_ADDRESS_SIZE 6 - -/* limits on nonce sizes. See RFC2409 "The internet key exchange (IKE)" 5 */ -#define MINIMUM_NONCE_SIZE 8 /* bytes */ -#define DEFAULT_NONCE_SIZE 16 /* bytes */ -#define MAXIMUM_NONCE_SIZE 256 /* bytes */ - -#define COOKIE_SIZE 8 -#define MAX_ISAKMP_SPI_SIZE 16 - -#define DES_CBC_BLOCK_SIZE (64 / BITS_PER_BYTE) - -/* Maximum is required for SHA2_512 */ -#define MAX_DIGEST_LEN HASH_SIZE_SHA512 - -/* RFC 2404 "HMAC-SHA-1-96" section 3 */ -#define HMAC_SHA1_KEY_LEN HASH_SIZE_SHA1 - -/* RFC 2403 "HMAC-MD5-96" section 3 */ -#define HMAC_MD5_KEY_LEN HASH_SIZE_MD5 - -#define IKE_UDP_PORT 500 - -/* IPsec AH transform values - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.3 - * and in http://www.iana.org/assignments/isakmp-registry - */ -enum ipsec_authentication_algo { - AH_NONE = 0, - AH_MD5 = 2, - AH_SHA = 3, - AH_DES = 4, - AH_SHA2_256 = 5, - AH_SHA2_384 = 6, - AH_SHA2_512 = 7, - AH_RIPEMD = 8, - AH_AES_XCBC_MAC = 9, - AH_RSA = 10, - AH_AES_128_GMAC = 11, - AH_AES_192_GMAC = 12, - AH_AES_256_GMAC = 13, - AH_SHA2_256_96 = 252 -}; - -extern enum_names ah_transform_names; - -/* IPsec ESP transform values - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.4 - * and from http://www.iana.org/assignments/isakmp-registry - */ - -enum ipsec_cipher_algo { - ESP_NONE = 0, - ESP_DES_IV64 = 1, - ESP_DES = 2, - ESP_3DES = 3, - ESP_RC5 = 4, - ESP_IDEA = 5, - ESP_CAST = 6, - ESP_BLOWFISH = 7, - ESP_3IDEA = 8, - ESP_DES_IV32 = 9, - ESP_RC4 = 10, - ESP_NULL = 11, - ESP_AES = 12, - ESP_AES_CTR = 13, - ESP_AES_CCM_8 = 14, - ESP_AES_CCM_12 = 15, - ESP_AES_CCM_16 = 16, - ESP_UNASSIGNED_17 = 17, - ESP_AES_GCM_8 = 18, - ESP_AES_GCM_12 = 19, - ESP_AES_GCM_16 = 20, - ESP_SEED_CBC = 21, - ESP_CAMELLIA = 22, - ESP_AES_GMAC = 23, - ESP_SERPENT = 252, - ESP_TWOFISH = 253 -}; - -extern enum_names esp_transform_names; - -/* IPCOMP transform values - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.5 - * now defined in kernel/kernel_ipsec.h - */ - -extern enum_names ipcomp_transformid_names; - -/* Certificate type values - * RFC 2408 ISAKMP, chapter 3.9 - */ -enum ipsec_cert_type { - CERT_NONE= 0, - CERT_PKCS7_WRAPPED_X509= 1, - CERT_PGP= 2, - CERT_DNS_SIGNED_KEY= 3, - CERT_X509_SIGNATURE= 4, - CERT_X509_KEY_EXCHANGE= 5, - CERT_KERBEROS_TOKENS= 6, - CERT_CRL= 7, - CERT_ARL= 8, - CERT_SPKI= 9, - CERT_X509_ATTRIBUTE= 10, - CERT_RAW_RSA_KEY= 11 -}; - -/* RFC 2560 OCSP - certificate status */ - -typedef enum { - CERT_GOOD = 0, - CERT_REVOKED = 1, - CERT_UNKNOWN = 2, - CERT_UNDEFINED = 3 -} cert_status_t; - -/* RFC 3706 Dead Peer Detection */ - -extern enum_name_t *dpd_action_names; - -typedef enum { - DPD_ACTION_NONE = 0, - DPD_ACTION_CLEAR = 1, - DPD_ACTION_HOLD = 2, - DPD_ACTION_RESTART = 3, - DPD_ACTION_UNKNOWN = 4 -} dpd_action_t; - -/* Timer events */ - -extern enum_name_t *timer_event_names; - -enum event_type { - EVENT_NULL, /* non-event */ - EVENT_REINIT_SECRET, /* Refresh cookie secret */ - EVENT_SO_DISCARD, /* discard unfinished state object */ - EVENT_RETRANSMIT, /* Retransmit packet */ - EVENT_SA_REPLACE, /* SA replacement event */ - EVENT_SA_REPLACE_IF_USED, /* SA replacement event */ - EVENT_SA_EXPIRE, /* SA expiration event */ - EVENT_NAT_T_KEEPALIVE, /* NAT Traversal Keepalive */ - EVENT_DPD, /* dead peer detection */ - EVENT_DPD_TIMEOUT, /* dead peer detection timeout */ - EVENT_LOG_DAILY /* reset certain log events/stats */ -}; - -#define EVENT_REINIT_SECRET_DELAY 3600 /* 1 hour */ -#define EVENT_RETRANSMIT_DELAY_0 10 /* 10 seconds */ - -/* Misc. stuff */ - -#define MAXIMUM_RETRANSMISSIONS 2 -#define MAXIMUM_RETRANSMISSIONS_INITIAL 20 - -#define MAX_INPUT_UDP_SIZE 65536 -#define MAX_OUTPUT_UDP_SIZE 65536 - -/* Version numbers */ - -#define ISAKMP_MAJOR_VERSION 0x1 -#define ISAKMP_MINOR_VERSION 0x0 - -extern enum_names version_names; - -/* Domain of Interpretation */ - -extern enum_names doi_names; - -#define ISAKMP_DOI_ISAKMP 0 -#define ISAKMP_DOI_IPSEC 1 - -/* IPsec DOI things */ - -#define IPSEC_DOI_SITUATION_LENGTH 4 -#define IPSEC_DOI_LDI_LENGTH 4 -#define IPSEC_DOI_SPI_SIZE 4 - -/* SPI value 0 is invalid and values 1-255 are reserved to IANA. - * ESP: RFC 2402 2.4; AH: RFC 2406 2.1 - * IPComp RFC 2393 substitutes a CPI in the place of an SPI. - * see also draft-shacham-ippcp-rfc2393bis-05.txt. - * We (FreeS/WAN) reserve 0x100 to 0xFFF for manual keying, so - * Pluto won't generate these values. - */ -#define IPSEC_DOI_SPI_MIN 0x100 -#define IPSEC_DOI_SPI_OUR_MIN 0x1000 - -/* debugging settings: a set of selections for reporting - * These would be more naturally situated in log.h, - * but they are shared with whack. - * IMPAIR_* actually change behaviour, usually badly, - * to aid in testing. Naturally, these are not included in ALL. - * - * NOTE: changes here must be done in concert with changes to DBGOPT_* - * in whack.c. A change to WHACK_MAGIC in whack.h will be required too. - */ -#ifdef DEBUG -extern const char *const debug_bit_names[]; -#endif - -#define DBG_RAW LELEM(0) /* raw packet I/O */ -#define DBG_CRYPT LELEM(1) /* encryption/decryption of messages */ -#define DBG_PARSING LELEM(2) /* show decoding of messages */ -#define DBG_EMITTING LELEM(3) /* show encoding of messages */ -#define DBG_CONTROL LELEM(4) /* control flow within Pluto */ -#define DBG_LIFECYCLE LELEM(5) /* SA lifecycle */ -#define DBG_KERNEL LELEM(6) /* messages to kernel */ -#define DBG_DNS LELEM(7) /* DNS activity */ -#define DBG_NATT LELEM(8) /* NAT-T */ -#define DBG_OPPO LELEM(9) /* opportunism */ -#define DBG_CONTROLMORE LELEM(10) /* more detailed debugging */ - -#define DBG_PRIVATE LELEM(11) /* private information: DANGER! */ - -#define IMPAIR0 12 /* first bit for IMPAIR_* */ - -#define IMPAIR_DELAY_ADNS_KEY_ANSWER LELEM(IMPAIR0+0) /* sleep before answering */ -#define IMPAIR_DELAY_ADNS_TXT_ANSWER LELEM(IMPAIR0+1) /* sleep before answering */ -#define IMPAIR_BUST_MI2 LELEM(IMPAIR0+2) /* make MI2 really large */ -#define IMPAIR_BUST_MR2 LELEM(IMPAIR0+3) /* make MI2 really large */ - -#define DBG_NONE 0 /* no options on, including impairments */ -#define DBG_ALL LRANGES(DBG_RAW, DBG_CONTROLMORE) /* all logging options on EXCEPT DBG_PRIVATE */ - -/* State of exchanges - * - * The name of the state describes the last message sent, not the - * message currently being input or output (except during retry). - * In effect, the state represents the last completed action. - * - * Messages are named [MQ][IR]n where - * - M stands for Main Mode (Phase 1); - * Q stands for Quick Mode (Phase 2) - * - I stands for Initiator; - * R stands for Responder - * - n, a digit, stands for the number of the message - * - * It would be more convenient if each state accepted a message - * and produced one. This is the case for states at the start - * or end of an exchange. To fix this, we pretend that there are - * MR0 and QR0 messages before the MI1 and QR1 messages. Similarly, - * we pretend that there are MR4 and QR2 messages. - * - * STATE_MAIN_R0 and STATE_QUICK_R0 are intermediate states (not - * retained between messages) representing the state that accepts the - * first message of an exchange has been read but not processed. - * - * state_microcode state_microcode_table in demux.c describes - * other important details. - */ - -extern enum_names state_names; -extern const char *const state_story[]; - -enum state_kind { - STATE_UNDEFINED, /* 0 -- most likely accident */ - - /* IKE states */ - - STATE_MAIN_R0, - STATE_MAIN_I1, - STATE_MAIN_R1, - STATE_MAIN_I2, - STATE_MAIN_R2, - STATE_MAIN_I3, - STATE_MAIN_R3, - STATE_MAIN_I4, - - STATE_QUICK_R0, - STATE_QUICK_I1, - STATE_QUICK_R1, - STATE_QUICK_I2, - STATE_QUICK_R2, - - STATE_INFO, - STATE_INFO_PROTECTED, - - /* XAUTH states */ - - STATE_XAUTH_I0, /* initiator state (client) */ - STATE_XAUTH_R1, /* responder state (server) */ - STATE_XAUTH_I1, - STATE_XAUTH_R2, - STATE_XAUTH_I2, - STATE_XAUTH_R3, - - /* Mode Config pull states */ - - STATE_MODE_CFG_R0, /* responder state (server) */ - STATE_MODE_CFG_I1, /* initiator state (client) */ - STATE_MODE_CFG_R1, - STATE_MODE_CFG_I2, - - /* Mode Config push states */ - - STATE_MODE_CFG_I0, /* initiator state (client) */ - STATE_MODE_CFG_R3, /* responder state (server) */ - STATE_MODE_CFG_I3, - STATE_MODE_CFG_R4, - - STATE_IKE_ROOF -}; - -#define STATE_IKE_FLOOR STATE_MAIN_R0 - -#define PHASE1_INITIATOR_STATES (LELEM(STATE_MAIN_I1) | LELEM(STATE_MAIN_I2) \ - | LELEM(STATE_MAIN_I3) | LELEM(STATE_MAIN_I4)) -#define ISAKMP_SA_ESTABLISHED_STATES ( \ - LELEM(STATE_MAIN_R3) | LELEM(STATE_MAIN_I4) \ - | LELEM(STATE_XAUTH_R1) | LELEM(STATE_XAUTH_R2) | LELEM(STATE_XAUTH_R3) \ - | LELEM(STATE_XAUTH_I1) | LELEM(STATE_XAUTH_I2) \ - | LELEM(STATE_MODE_CFG_I1) | LELEM(STATE_MODE_CFG_R1) | LELEM(STATE_MODE_CFG_I2) \ - | LELEM(STATE_MODE_CFG_R3) | LELEM(STATE_MODE_CFG_I3) | LELEM(STATE_MODE_CFG_R4)) - -#define IS_PHASE1(s) ((STATE_MAIN_R0 <= (s) && (s) <= STATE_MAIN_I4) \ - || (STATE_XAUTH_I0 <= (s) && (s) <= STATE_XAUTH_R3) \ - || (STATE_MODE_CFG_R0 <= (s) && (s) <= STATE_MODE_CFG_R4)) - -#define IS_QUICK(s) (STATE_QUICK_R0 <= (s) && (s) <= STATE_QUICK_R2) -#define IS_ISAKMP_ENCRYPTED(s) (STATE_MAIN_I2 <= (s)) - -#define IS_ISAKMP_SA_ESTABLISHED(s) ( \ - (s) == STATE_MAIN_R3 \ - || (s) == STATE_MAIN_I4 \ - || (s) == STATE_XAUTH_I2 \ - || (s) == STATE_XAUTH_R3 \ - || (s) == STATE_MODE_CFG_R1 \ - || (s) == STATE_MODE_CFG_I2 \ - || (s) == STATE_MODE_CFG_I3 \ - || (s) == STATE_MODE_CFG_R4) - -#define IS_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_I2 || (s) == STATE_QUICK_R2) -#define IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_R1) - -/* kind of struct connection - * Ordered (mostly) by concreteness. Order is exploited. - */ - -extern enum_names connection_kind_names; - -enum connection_kind { - CK_GROUP, /* policy group: instantiates to template */ - CK_TEMPLATE, /* abstract connection, with wildcard */ - CK_PERMANENT, /* normal connection */ - CK_INSTANCE, /* instance of template, created for a particular attempt */ - CK_GOING_AWAY /* instance being deleted -- don't delete again */ -}; - - -/* routing status. - * Note: routing ignores source address, but erouting does not! - * Note: a connection can only be routed if it is NEVER_NEGOTIATE - * or HAS_IPSEC_POLICY. - */ - -extern enum_names routing_story; - -/* note that this is assumed to be ordered! */ -enum routing_t { - RT_UNROUTED, /* unrouted */ - RT_UNROUTED_HOLD, /* unrouted, but HOLD shunt installed */ - RT_ROUTED_ECLIPSED, /* RT_ROUTED_PROSPECTIVE except bare HOLD or instance has eroute */ - RT_ROUTED_PROSPECTIVE, /* routed, and prospective shunt installed */ - RT_ROUTED_HOLD, /* routed, and HOLD shunt installed */ - RT_ROUTED_FAILURE, /* routed, and failure-context shunt installed */ - RT_ROUTED_TUNNEL, /* routed, and erouted to an IPSEC SA group */ - RT_UNROUTED_KEYED /* keyed, but not routed, on purpose */ -}; - -#define routed(rs) ((rs) > RT_UNROUTED_HOLD) -#define erouted(rs) ((rs) != RT_UNROUTED) -#define shunt_erouted(rs) (erouted(rs) && (rs) != RT_ROUTED_TUNNEL) - -/* Payload types - * RFC2408 Internet Security Association and Key Management Protocol (ISAKMP) - * section 3.1 - * - * RESERVED 14-127 - * Private USE 128-255 - */ - -extern enum_names payload_names; -extern const char *const payload_name[]; - -#define ISAKMP_NEXT_NONE 0 /* No other payload following */ -#define ISAKMP_NEXT_SA 1 /* Security Association */ -#define ISAKMP_NEXT_P 2 /* Proposal */ -#define ISAKMP_NEXT_T 3 /* Transform */ -#define ISAKMP_NEXT_KE 4 /* Key Exchange */ -#define ISAKMP_NEXT_ID 5 /* Identification */ -#define ISAKMP_NEXT_CERT 6 /* Certificate */ -#define ISAKMP_NEXT_CR 7 /* Certificate Request */ -#define ISAKMP_NEXT_HASH 8 /* Hash */ -#define ISAKMP_NEXT_SIG 9 /* Signature */ -#define ISAKMP_NEXT_NONCE 10 /* Nonce */ -#define ISAKMP_NEXT_N 11 /* Notification */ -#define ISAKMP_NEXT_D 12 /* Delete */ -#define ISAKMP_NEXT_VID 13 /* Vendor ID */ -#define ISAKMP_NEXT_ATTR 14 /* Mode config Attribute */ - -#define ISAKMP_NEXT_NATD_RFC 20 /* NAT-Traversal: NAT-D (rfc) */ -#define ISAKMP_NEXT_NATOA_RFC 21 /* NAT-Traversal: NAT-OA (rfc) */ -#define ISAKMP_NEXT_ROOF 22 /* roof on payload types */ - -#define ISAKMP_NEXT_NATD_DRAFTS 130 /* NAT-Traversal: NAT-D (drafts) */ -#define ISAKMP_NEXT_NATOA_DRAFTS 131 /* NAT-Traversal: NAT-OA (drafts) */ - -/* These values are to be used within the Type field of an Attribute (14) - * ISAKMP payload. - */ -#define ISAKMP_CFG_REQUEST 1 -#define ISAKMP_CFG_REPLY 2 -#define ISAKMP_CFG_SET 3 -#define ISAKMP_CFG_ACK 4 - -extern enum_names attr_msg_type_names; - -extern enum_names modecfg_attr_names; - -/* XAUTH authentication types */ -#define XAUTH_TYPE_GENERIC 0 -#define XAUTH_TYPE_CHAP 1 -#define XAUTH_TYPE_OTP 2 -#define XAUTH_TYPE_SKEY 3 - -/* Values for XAUTH_STATUS */ -#define XAUTH_STATUS_FAIL 0 -#define XAUTH_STATUS_OK 1 - -extern enum_names xauth_type_names; - -/* Exchange types - * RFC2408 "Internet Security Association and Key Management Protocol (ISAKMP)" - * section 3.1 - * - * ISAKMP Future Use 6 - 31 - * DOI Specific Use 32 - 239 - * Private Use 240 - 255 - * - * Note: draft-ietf-ipsec-dhless-enc-mode-00.txt Appendix A - * defines "DHless RSA Encryption" as 6. - */ - -extern enum_names exchange_names; - -#define ISAKMP_XCHG_NONE 0 -#define ISAKMP_XCHG_BASE 1 -#define ISAKMP_XCHG_IDPROT 2 /* ID Protection */ -#define ISAKMP_XCHG_AO 3 /* Authentication Only */ -#define ISAKMP_XCHG_AGGR 4 /* Aggressive */ -#define ISAKMP_XCHG_INFO 5 /* Informational */ -#define ISAKMP_XCHG_MODE_CFG 6 /* Mode Config */ - -/* Extra exchange types, defined by Oakley - * RFC2409 "The Internet Key Exchange (IKE)", near end of Appendix A - */ -#define ISAKMP_XCHG_QUICK 32 /* Oakley Quick Mode */ -#define ISAKMP_XCHG_NGRP 33 /* Oakley New Group Mode */ -/* added in draft-ietf-ipsec-ike-01.txt, near end of Appendix A */ -#define ISAKMP_XCHG_ACK_INFO 34 /* Oakley Acknowledged Informational */ - -/* Flag bits */ - -extern const char *const flag_bit_names[]; - -#define ISAKMP_FLAG_ENCRYPTION 0x1 -#define ISAKMP_FLAG_COMMIT 0x2 - -/* Situation definition for IPsec DOI */ - -extern const char *const sit_bit_names[]; - -#define SIT_IDENTITY_ONLY 0x01 -#define SIT_SECRECY 0x02 -#define SIT_INTEGRITY 0x04 - -/* Protocol IDs - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.1 - */ - -extern enum_names protocol_names; - -#define PROTO_ISAKMP 1 -#define PROTO_IPSEC_AH 2 -#define PROTO_IPSEC_ESP 3 -#define PROTO_IPCOMP 4 - -/* warning: trans_show uses enum_show, so same static buffer is used */ -#define trans_show(p, t) \ - ((p)==PROTO_IPSEC_AH ? enum_show(&ah_transformid_names, (t)) \ - : (p)==PROTO_IPSEC_ESP ? enum_show(&esp_transformid_names, (t)) \ - : (p)==PROTO_IPCOMP ? enum_show(&ipcomp_transformid_names, (t)) \ - : "??") - -#define KEY_IKE 1 - -extern enum_names isakmp_transformid_names; - -/* the following are from RFC 2393/draft-shacham-ippcp-rfc2393bis-05.txt 3.3 */ -typedef u_int16_t cpi_t; -#define IPCOMP_CPI_SIZE 2 -#define IPCOMP_FIRST_NEGOTIATED 256 -#define IPCOMP_LAST_NEGOTIATED 61439 - -/* Identification type values - * RFC 2407 The Internet IP security Domain of Interpretation for ISAKMP 4.6.2.1 - */ - -extern enum_names ident_names; -extern enum_names cert_type_names; - -extern enum_name_t *cert_policy_names; - -typedef enum certpolicy { - CERT_ALWAYS_SEND = 0, - CERT_SEND_IF_ASKED = 1, - CERT_NEVER_SEND = 2, - - CERT_YES_SEND = 3, /* synonym for CERT_ALWAYS_SEND */ - CERT_NO_SEND = 4 /* synonym for CERT_NEVER_SEND */ -} certpolicy_t; - -/* Policies for establishing an SA - * - * These are used to specify attributes (eg. encryption) and techniques - * (eg PFS) for an SA. - * Note: certain CD_ definitions in whack.c parallel these -- keep them - * in sync! - */ - -extern const char *const sa_policy_bit_names[]; -extern const char *prettypolicy(lset_t policy); - -/* ISAKMP auth techniques (none means never negotiate) */ -#define POLICY_PSK LELEM(0) -#define POLICY_PUBKEY LELEM(1) - -#define POLICY_ISAKMP_SHIFT 0 /* log2(POLICY_PSK) */ -#define POLICY_ID_AUTH_MASK (POLICY_PSK | POLICY_PUBKEY | POLICY_XAUTH_PSK | POLICY_XAUTH_RSASIG) -#define POLICY_ISAKMP_MASK POLICY_ID_AUTH_MASK /* all so far */ - -/* Quick Mode (IPSEC) attributes */ -#define POLICY_ENCRYPT LELEM(2) /* must be first of IPSEC policies */ -#define POLICY_AUTHENTICATE LELEM(3) /* must be second */ -#define POLICY_COMPRESS LELEM(4) /* must be third */ -#define POLICY_TUNNEL LELEM(5) -#define POLICY_PFS LELEM(6) -#define POLICY_DISABLEARRIVALCHECK LELEM(7) /* suppress tunnel egress address checking */ - -#define POLICY_IPSEC_SHIFT 2 /* log2(POLICY_ENCRYPT) */ -#define POLICY_IPSEC_MASK LRANGES(POLICY_ENCRYPT, POLICY_DISABLEARRIVALCHECK) - -/* shunt attributes: what to do when routed without tunnel (2 bits) */ -#define POLICY_SHUNT_SHIFT 8 /* log2(POLICY_SHUNT_PASS) */ -#define POLICY_SHUNT_MASK (03ul << POLICY_SHUNT_SHIFT) - -#define POLICY_SHUNT_TRAP (0ul << POLICY_SHUNT_SHIFT) /* default: negotiate */ -#define POLICY_SHUNT_PASS (1ul << POLICY_SHUNT_SHIFT) -#define POLICY_SHUNT_DROP (2ul << POLICY_SHUNT_SHIFT) -#define POLICY_SHUNT_REJECT (3ul << POLICY_SHUNT_SHIFT) - -/* fail attributes: what to do with failed negotiation (2 bits) */ - -#define POLICY_FAIL_SHIFT 10 /* log2(POLICY_FAIL_PASS) */ -#define POLICY_FAIL_MASK (03ul << POLICY_FAIL_SHIFT) - -#define POLICY_FAIL_NONE (0ul << POLICY_FAIL_SHIFT) /* default */ -#define POLICY_FAIL_PASS (1ul << POLICY_FAIL_SHIFT) -#define POLICY_FAIL_DROP (2ul << POLICY_FAIL_SHIFT) -#define POLICY_FAIL_REJECT (3ul << POLICY_FAIL_SHIFT) - -/* connection policy - * Other policies could vary per state object. These live in connection. - */ -#define POLICY_DONT_REKEY LELEM(12) /* don't rekey state either Phase */ -#define POLICY_OPPO LELEM(13) /* is this opportunistic? */ -#define POLICY_GROUP LELEM(14) /* is this a group template? */ -#define POLICY_GROUTED LELEM(15) /* do we want this group routed? */ -#define POLICY_UP LELEM(16) /* do we want this up? */ -#define POLICY_MODECFG_PUSH LELEM(17) /* is modecfg pushed by server? */ -#define POLICY_XAUTH_PSK LELEM(18) /* do we support XAUTH????PreShared? */ -#define POLICY_XAUTH_RSASIG LELEM(19) /* do we support XAUTH????RSA? */ -#define POLICY_XAUTH_SERVER LELEM(20) /* are we an XAUTH server? */ -#define POLICY_DONT_REAUTH LELEM(21) /* don't reauthenticate on rekeying, IKEv2 only */ -#define POLICY_BEET LELEM(22) /* bound end2end tunnel, IKEv2 */ -#define POLICY_MOBIKE LELEM(23) /* enable MOBIKE for IKEv2 */ -#define POLICY_FORCE_ENCAP LELEM(24) /* force UDP encapsulation (IKEv2) */ -#define POLICY_PROXY LELEM(25) /* proxy transport mode (MIPv6) */ - -/* Any IPsec policy? If not, a connection description - * is only for ISAKMP SA, not IPSEC SA. (A pun, I admit.) - * Note: a connection can only be routed if it is NEVER_NEGOTIATE - * or HAS_IPSEC_POLICY. - */ -#define HAS_IPSEC_POLICY(p) (((p) & POLICY_IPSEC_MASK) != 0) - -/* Don't allow negotiation? */ -#define NEVER_NEGOTIATE(p) (LDISJOINT((p), POLICY_ID_AUTH_MASK)) - - -/* Oakley transform attributes - * draft-ietf-ipsec-ike-01.txt appendix A - */ - -extern enum_names oakley_attr_names; -extern const char *const oakley_attr_bit_names[]; - -#define OAKLEY_ENCRYPTION_ALGORITHM 1 -#define OAKLEY_HASH_ALGORITHM 2 -#define OAKLEY_AUTHENTICATION_METHOD 3 -#define OAKLEY_GROUP_DESCRIPTION 4 -#define OAKLEY_GROUP_TYPE 5 -#define OAKLEY_GROUP_PRIME 6 /* B/V */ -#define OAKLEY_GROUP_GENERATOR_ONE 7 /* B/V */ -#define OAKLEY_GROUP_GENERATOR_TWO 8 /* B/V */ -#define OAKLEY_GROUP_CURVE_A 9 /* B/V */ -#define OAKLEY_GROUP_CURVE_B 10 /* B/V */ -#define OAKLEY_LIFE_TYPE 11 -#define OAKLEY_LIFE_DURATION 12 /* B/V */ -#define OAKLEY_PRF 13 -#define OAKLEY_KEY_LENGTH 14 -#define OAKLEY_FIELD_SIZE 15 -#define OAKLEY_GROUP_ORDER 16 /* B/V */ -#define OAKLEY_BLOCK_SIZE 17 - -/* for each Oakley attribute, which enum_names describes its values? */ -extern enum_names *oakley_attr_val_descs[]; - -/* IPsec DOI attributes - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.5 - */ - -extern enum_names ipsec_attr_names; - -#define SA_LIFE_TYPE 1 -#define SA_LIFE_DURATION 2 /* B/V */ -#define GROUP_DESCRIPTION 3 -#define ENCAPSULATION_MODE 4 -#define AUTH_ALGORITHM 5 -#define KEY_LENGTH 6 -#define KEY_ROUNDS 7 -#define COMPRESS_DICT_SIZE 8 -#define COMPRESS_PRIVATE_ALG 9 /* B/V */ - -/* for each IPsec attribute, which enum_names describes its values? */ -extern enum_names *ipsec_attr_val_descs[]; - -/* SA Lifetime Type attribute - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.5 - * Default time specified in 4.5 - * - * There are two defaults for IPSEC SA lifetime, SA_LIFE_DURATION_DEFAULT, - * and PLUTO_SA_LIFE_DURATION_DEFAULT. - * SA_LIFE_DURATION_DEFAULT is specified in RFC2407 "The Internet IP - * Security Domain of Interpretation for ISAKMP" 4.5. It applies when - * an ISAKMP negotiation does not explicitly specify a life duration. - * PLUTO_SA_LIFE_DURATION_DEFAULT is specified in pluto(8). It applies - * when a connection description does not specify --ipseclifetime. - * The value of SA_LIFE_DURATION_MAXIMUM is our local policy. - */ - -extern enum_names sa_lifetime_names; - -#define SA_LIFE_TYPE_SECONDS 1 -#define SA_LIFE_TYPE_KBYTES 2 - -#define SA_LIFE_DURATION_DEFAULT 28800 /* eight hours (RFC2407 4.5) */ -#define PLUTO_SA_LIFE_DURATION_DEFAULT 3600 /* one hour (pluto(8)) */ -#define SA_LIFE_DURATION_MAXIMUM 86400 /* one day */ - -#define SA_REPLACEMENT_MARGIN_DEFAULT 540 /* (IPSEC & IKE) nine minutes */ -#define SA_REPLACEMENT_FUZZ_DEFAULT 100 /* (IPSEC & IKE) 100% of MARGIN */ -#define SA_REPLACEMENT_RETRIES_DEFAULT 3 /* (IPSEC & IKE) */ - -#define SA_LIFE_DURATION_K_DEFAULT 0xFFFFFFFFlu - -/* Encapsulation Mode attribute */ - -extern enum_names enc_mode_names; - -#define ENCAPSULATION_MODE_UNSPECIFIED 0 /* not legal -- used internally */ -#define ENCAPSULATION_MODE_TUNNEL 1 -#define ENCAPSULATION_MODE_TRANSPORT 2 - -#define ENCAPSULATION_MODE_UDP_TUNNEL_RFC 3 -#define ENCAPSULATION_MODE_UDP_TRANSPORT_RFC 4 - -#define ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS 61443 -#define ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS 61444 - -/* Auth Algorithm attribute */ - -extern enum_names auth_alg_names, extended_auth_alg_names; - -#define AUTH_ALGORITHM_NONE 0 /* our private designation */ -#define AUTH_ALGORITHM_HMAC_MD5 1 -#define AUTH_ALGORITHM_HMAC_SHA1 2 -#define AUTH_ALGORITHM_DES_MAC 3 -#define AUTH_ALGORITHM_KPDK 4 -#define AUTH_ALGORITHM_HMAC_SHA2_256 5 -#define AUTH_ALGORITHM_HMAC_SHA2_384 6 -#define AUTH_ALGORITHM_HMAC_SHA2_512 7 -#define AUTH_ALGORITHM_HMAC_RIPEMD 8 -#define AUTH_ALGORITHM_AES_XCBC_MAC 9 -#define AUTH_ALGORITHM_SIG_RSA 10 -#define AUTH_ALGORITHM_AES_128_GMAC 11 -#define AUTH_ALGORITHM_AES_192_GMAC 12 -#define AUTH_ALGORITHM_AES_256_GMAC 13 -#define AUTH_ALGORITHM_NULL 251 -#define AUTH_ALGORITHM_HMAC_SHA2_256_96 252 - -/* Oakley Lifetime Type attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * As far as I can see, there is not specification for - * OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT. This could lead to interop problems! - * For no particular reason, we chose three hours. - * The value of OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM is our local policy. - */ -extern enum_names oakley_lifetime_names; - -#define OAKLEY_LIFE_SECONDS 1 -#define OAKLEY_LIFE_KILOBYTES 2 - -#define OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT 10800 /* three hours */ -#define OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM 86400 /* one day */ - -/* Oakley PRF attribute (none defined) - * draft-ietf-ipsec-ike-01.txt appendix A - */ -extern enum_names oakley_prf_names; - -/* HMAC (see rfc2104.txt) */ - -#define HMAC_IPAD 0x36 -#define HMAC_OPAD 0x5C - -/* Oakley Encryption Algorithm attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * and from http://www.isi.edu/in-notes/iana/assignments/ipsec-registry - */ - -extern enum_names oakley_enc_names; - -#define OAKLEY_DES_CBC 1 -#define OAKLEY_IDEA_CBC 2 -#define OAKLEY_BLOWFISH_CBC 3 -#define OAKLEY_RC5_R16_B64_CBC 4 -#define OAKLEY_3DES_CBC 5 -#define OAKLEY_CAST_CBC 6 -#define OAKLEY_AES_CBC 7 -#define OAKLEY_CAMELLIA_CBC 8 - -#define OAKLEY_MARS_CBC 65001 -#define OAKLEY_RC6_CBC 65002 -#define OAKLEY_ID_65003 65003 -#define OAKLEY_SERPENT_CBC 65004 -#define OAKLEY_TWOFISH_CBC 65005 - -#define OAKLEY_TWOFISH_CBC_SSH 65289 - -#define OAKLEY_ENCRYPT_MAX 65535 /* pretty useless :) */ - -/* Oakley Hash Algorithm attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * and from http://www.isi.edu/in-notes/iana/assignments/ipsec-registry - */ - -extern enum_names oakley_hash_names; - -#define OAKLEY_MD5 1 -#define OAKLEY_SHA 2 -#define OAKLEY_TIGER 3 -#define OAKLEY_SHA2_256 4 -#define OAKLEY_SHA2_384 5 -#define OAKLEY_SHA2_512 6 - -#define OAKLEY_HASH_MAX 7 - -/* Oakley Authentication Method attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * Goofy Hybrid extensions from draft-ietf-ipsec-isakmp-hybrid-auth-05.txt - * Goofy XAUTH extensions from draft-ietf-ipsec-isakmp-xauth-06.txt - */ - -extern enum_names oakley_auth_names; - -#define OAKLEY_PRESHARED_KEY 1 -#define OAKLEY_DSS_SIG 2 -#define OAKLEY_RSA_SIG 3 -#define OAKLEY_RSA_ENC 4 -#define OAKLEY_RSA_ENC_REV 5 -#define OAKLEY_ELGAMAL_ENC 6 -#define OAKLEY_ELGAMAL_ENC_REV 7 -#define OAKLEY_ECDSA_SIG 8 -#define OAKLEY_ECDSA_256 9 -#define OAKLEY_ECDSA_384 10 -#define OAKLEY_ECDSA_521 11 - -#define OAKLEY_AUTH_ROOF 12 /* roof on auth values THAT WE SUPPORT */ - -#define HybridInitRSA 64221 -#define HybridRespRSA 64222 -#define HybridInitDSS 64223 -#define HybridRespDSS 64224 - -#define XAUTHInitPreShared 65001 -#define XAUTHRespPreShared 65002 -#define XAUTHInitDSS 65003 -#define XAUTHRespDSS 65004 -#define XAUTHInitRSA 65005 -#define XAUTHRespRSA 65006 -#define XAUTHInitRSAEncryption 65007 -#define XAUTHRespRSAEncryption 65008 -#define XAUTHInitRSARevisedEncryption 65009 -#define XAUTHRespRSARevisedEncryption 65010 - -/* Oakley Group Description attribute - * draft-ietf-ipsec-ike-01.txt appendix A - */ -extern enum_names oakley_group_names; - -/* you must also touch: constants.c, crypto.c */ - -/* Oakley Group Type attribute - * draft-ietf-ipsec-ike-01.txt appendix A - */ -extern enum_names oakley_group_type_names; - -#define OAKLEY_GROUP_TYPE_MODP 1 -#define OAKLEY_GROUP_TYPE_ECP 2 -#define OAKLEY_GROUP_TYPE_EC2N 3 - - -/* Notify messages -- error types - * See RFC2408 ISAKMP 3.14.1 - */ - -extern enum_names notification_names; -extern enum_names ipsec_notification_names; - -typedef enum { - ISAKMP_NOTHING_WRONG = 0, /* unofficial! */ - - ISAKMP_INVALID_PAYLOAD_TYPE = 1, - ISAKMP_DOI_NOT_SUPPORTED = 2, - ISAKMP_SITUATION_NOT_SUPPORTED = 3, - ISAKMP_INVALID_COOKIE = 4, - ISAKMP_INVALID_MAJOR_VERSION = 5, - ISAKMP_INVALID_MINOR_VERSION = 6, - ISAKMP_INVALID_EXCHANGE_TYPE = 7, - ISAKMP_INVALID_FLAGS = 8, - ISAKMP_INVALID_MESSAGE_ID = 9, - ISAKMP_INVALID_PROTOCOL_ID = 10, - ISAKMP_INVALID_SPI = 11, - ISAKMP_INVALID_TRANSFORM_ID = 12, - ISAKMP_ATTRIBUTES_NOT_SUPPORTED = 13, - ISAKMP_NO_PROPOSAL_CHOSEN = 14, - ISAKMP_BAD_PROPOSAL_SYNTAX = 15, - ISAKMP_PAYLOAD_MALFORMED = 16, - ISAKMP_INVALID_KEY_INFORMATION = 17, - ISAKMP_INVALID_ID_INFORMATION = 18, - ISAKMP_INVALID_CERT_ENCODING = 19, - ISAKMP_INVALID_CERTIFICATE = 20, - ISAKMP_CERT_TYPE_UNSUPPORTED = 21, - ISAKMP_INVALID_CERT_AUTHORITY = 22, - ISAKMP_INVALID_HASH_INFORMATION = 23, - ISAKMP_AUTHENTICATION_FAILED = 24, - ISAKMP_INVALID_SIGNATURE = 25, - ISAKMP_ADDRESS_NOTIFICATION = 26, - ISAKMP_NOTIFY_SA_LIFETIME = 27, - ISAKMP_CERTIFICATE_UNAVAILABLE = 28, - ISAKMP_UNSUPPORTED_EXCHANGE_TYPE = 29, - ISAKMP_UNEQUAL_PAYLOAD_LENGTHS = 30, - - /* ISAKMP status type */ - ISAKMP_CONNECTED = 16384, - - /* IPSEC DOI additions; status types (RFC2407 IPSEC DOI 4.6.3) - * These must be sent under the protection of an ISAKMP SA. - */ - IPSEC_RESPONDER_LIFETIME = 24576, - IPSEC_REPLAY_STATUS = 24577, - IPSEC_INITIAL_CONTACT = 24578, - - /* RFC 3706 DPD */ - R_U_THERE = 36136, - R_U_THERE_ACK = 36137, - - /* Juniper SRX private use */ - NS_NHTB_INFORM = 40001 - - } notification_t; - - -/* Public key algorithm number - * Same numbering as used in DNSsec - * See RFC 2535 DNSsec 3.2 The KEY Algorithm Number Specification. - * Also found in BIND 8.2.2 include/isc/dst.h as DST algorithm codes. - */ - -enum pubkey_alg -{ - PUBKEY_ALG_RSA = 1, - PUBKEY_ALG_DSA = 3, -}; - -/* Limits on size of RSA moduli. - * The upper bound matches that of DNSsec (see RFC 2537). - * The lower bound must be more than 11 octets for certain - * the encoding to work, but it must be much larger for any - * real security. For now, we require 512 bits. - */ - -#define RSA_MIN_OCTETS_RFC 12 - -#define RSA_MIN_OCTETS (512 / BITS_PER_BYTE) -#define RSA_MIN_OCTETS_UGH "RSA modulus too small for security: less than 512 bits" - -#define RSA_MAX_OCTETS (8192 / BITS_PER_BYTE) -#define RSA_MAX_OCTETS_UGH "RSA modulus too large: more than 8192 bits" - -/* Note: RFC 2537 encoding adds a few bytes. If you use a small - * modulus like 3, the overhead is only 2 bytes - */ -#define RSA_MAX_ENCODING_BYTES (RSA_MAX_OCTETS + 2) - -/* socket address family info */ - -struct af_info -{ - int af; - const char *name; - size_t ia_sz; - size_t sa_sz; - int mask_cnt; - u_int8_t id_addr, id_subnet, id_range; - const ip_address *any; - const ip_subnet *none; /* 0.0.0.0/32 or IPv6 equivalent */ - const ip_subnet *all; /* 0.0.0.0/0 or IPv6 equivalent */ -}; - -extern const struct af_info - af_inet4_info, - af_inet6_info; - -extern const struct af_info *aftoinfo(int af); - -extern enum_names af_names; - -#define subnetisaddr(sn, a) (subnetishost(sn) && addrinsubnet((a), (sn))) -extern bool subnetisnone(const ip_subnet *sn); - -/* BIND enumerated types */ - -extern enum_names - rr_qtype_names, - rr_type_names, - rr_class_names; - -/* How authenticated is info that might have come from DNS? - * In order of increasing confidence. - */ -enum dns_auth_level { - DAL_UNSIGNED, /* AD in response, but no signature: no authentication */ - DAL_NOTSEC, /* no AD in response: authentication impossible */ - DAL_SIGNED, /* AD and signature in response: authentic */ - DAL_LOCAL /* locally provided (pretty good) */ -}; - -/* - * define a macro for use in error messages - */ - -#ifdef USE_KEYRR -#define RRNAME "TXT or KEY" -#else -#define RRNAME "TXT" -#endif - -/* natt traversal types */ -extern const char *const natt_type_bitnames[]; - -/* secret value for responder cookies */ -extern u_char secret_of_the_day[HASH_SIZE_SHA1]; - -#endif /* _CONSTANTS_H */ diff --git a/src/pluto/cookie.c b/src/pluto/cookie.c deleted file mode 100644 index 00c863f18..000000000 --- a/src/pluto/cookie.c +++ /dev/null @@ -1,73 +0,0 @@ -/* cookie generation/verification routines. - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> - -#include <freeswan.h> - -#include <library.h> -#include <crypto/rngs/rng.h> - -#include "constants.h" -#include "defs.h" -#include "cookie.h" - -const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */ - -/* Generate a cookie. - * First argument is true if we're to create an Initiator cookie. - * Length SHOULD be a multiple of sizeof(u_int32_t). - */ -void get_cookie(bool initiator, u_int8_t *cookie, int length, ip_address *addr) -{ - hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - u_char buffer[HASH_SIZE_SHA1]; - - do { - if (initiator) - { - rng_t *rng; - - rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - rng->get_bytes(rng, length, cookie); - rng->destroy(rng); - } - else /* Responder cookie */ - { - chunk_t addr_chunk, secret_chunk, counter_chunk; - size_t addr_len; - static u_int32_t counter = 0; - unsigned char addr_buf[ - sizeof(union {struct in_addr A; struct in6_addr B;})]; - - addr_len = addrbytesof(addr, addr_buf, sizeof(addr_buf)); - addr_chunk = chunk_create(addr_buf, addr_len); - secret_chunk = chunk_create(secret_of_the_day, HASH_SIZE_SHA1); - counter++; - counter_chunk = chunk_create((void *) &counter, sizeof(counter)); - hasher->get_hash(hasher, addr_chunk, NULL); - hasher->get_hash(hasher, secret_chunk, NULL); - hasher->get_hash(hasher, counter_chunk, buffer); - memcpy(cookie, buffer, length); - } - } while (is_zero_cookie(cookie)); /* probably never loops */ - - hasher->destroy(hasher); -} diff --git a/src/pluto/cookie.h b/src/pluto/cookie.h deleted file mode 100644 index 809d66491..000000000 --- a/src/pluto/cookie.h +++ /dev/null @@ -1,22 +0,0 @@ -/* cookie generation/verification routines. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <freeswan.h> - -extern const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */ - -extern void get_cookie(bool initiator, u_int8_t *cookie, int length, - ip_address *addr); - -#define is_zero_cookie(cookie) all_zero((cookie), COOKIE_SIZE) diff --git a/src/pluto/crl.c b/src/pluto/crl.c deleted file mode 100644 index c49b09e19..000000000 --- a/src/pluto/crl.c +++ /dev/null @@ -1,541 +0,0 @@ -/* Support of X.509 certificate revocation lists (CRLs) - * Copyright (C) 2000-2009 Andreas Steffen - * - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <dirent.h> -#include <time.h> -#include <sys/types.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "crl.h" -#include "ca.h" -#include "certs.h" -#include "keys.h" -#include "whack.h" -#include "fetch.h" -#include "builder.h" - - -/* chained lists of X.509 crls */ - -static x509crl_t *x509crls = NULL; - -/** - * Get the X.509 CRL with a given issuer - */ -static x509crl_t* get_x509crl(identification_t *issuer, chunk_t keyid) -{ - x509crl_t *x509crl = x509crls; - x509crl_t *prev_crl = NULL; - - while (x509crl != NULL) - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - identification_t *crl_issuer = cert_crl->get_issuer(cert_crl); - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - - if ((keyid.ptr && authKeyID.ptr)? same_keyid(keyid, authKeyID) : - issuer->equals(issuer, crl_issuer)) - { - if (x509crl != x509crls) - { - /* bring the CRL up front */ - prev_crl->next = x509crl->next; - x509crl->next = x509crls; - x509crls = x509crl; - } - return x509crl; - } - prev_crl = x509crl; - x509crl = x509crl->next; - } - return NULL; -} - -/** - * Free the dynamic memory used to store CRLs - */ -void free_crl(x509crl_t *crl) -{ - DESTROY_IF(crl->crl); - crl->distributionPoints->destroy_function(crl->distributionPoints, free); - free(crl); -} - -static void free_first_crl(void) -{ - x509crl_t *crl = x509crls; - - x509crls = crl->next; - free_crl(crl); -} - -void free_crls(void) -{ - lock_crl_list("free_crls"); - - while (x509crls != NULL) - { - free_first_crl(); - } - - unlock_crl_list("free_crls"); -} - -/** - * Insert X.509 CRL into chained list - */ -bool insert_crl(x509crl_t *x509crl, char *crl_uri, bool cache_crl) -{ - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - identification_t *issuer = cert_crl->get_issuer(cert_crl); - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - cert_t *issuer_cert; - x509crl_t *oldcrl; - time_t now, nextUpdate; - bool valid_sig; - - /* add distribution point */ - add_distribution_point(x509crl->distributionPoints, crl_uri); - - lock_authcert_list("insert_crl"); - - /* get the issuer cacert */ - issuer_cert = get_authcert(issuer, authKeyID, X509_CA); - if (issuer_cert == NULL) - { - plog("crl issuer cacert not found"); - free_crl(x509crl); - unlock_authcert_list("insert_crl"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("crl issuer cacert found") - ) - - /* check the issuer's signature of the crl */ - valid_sig = cert_crl->issued_by(cert_crl, issuer_cert->cert); - unlock_authcert_list("insert_crl"); - - if (!valid_sig) - { - free_crl(x509crl); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("crl signature is valid") - ) - - /* note the current time */ - time(&now); - - lock_crl_list("insert_crl"); - oldcrl = get_x509crl(issuer, authKeyID); - - if (oldcrl != NULL) - { - certificate_t *old_cert_crl = oldcrl->crl; - - if (crl_is_newer((crl_t*)cert_crl, (crl_t*)old_cert_crl)) - { - /* keep any known CRL distribution points */ - add_distribution_points(x509crl->distributionPoints, - oldcrl->distributionPoints); - - /* now delete the old CRL */ - free_first_crl(); - DBG(DBG_CONTROL, - DBG_log("thisUpdate is newer - existing crl deleted") - ) - } - else - { - unlock_crl_list("insert_crls"); - DBG(DBG_CONTROL, - DBG_log("thisUpdate is not newer - existing crl not replaced"); - ) - free_crl(x509crl); - old_cert_crl->get_validity(old_cert_crl, &now, NULL, &nextUpdate); - return nextUpdate - now > 2*crl_check_interval; - } - } - - /* insert new CRL */ - x509crl->next = x509crls; - x509crls = x509crl; - - unlock_crl_list("insert_crl"); - - /* If crl caching is enabled then the crl is saved locally. - * Only http or ldap URIs are cached but not local file URIs. - * The CRL's authorityKeyIdentifier is used as a unique filename - */ - if (cache_crl && strncasecmp(crl_uri, "file", 4) != 0) - { - char buf[BUF_LEN]; - chunk_t hex, encoding; - - hex = chunk_to_hex(crl->get_authKeyIdentifier(crl), NULL, FALSE); - snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_PATH, hex.ptr); - free(hex.ptr); - - if (cert_crl->get_encoding(cert_crl, CERT_ASN1_DER, &encoding)) - { - chunk_write(encoding, buf, "crl", 022, TRUE); - free(encoding.ptr); - } - } - - /* is the fetched crl valid? */ - cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate); - return nextUpdate - now > 2*crl_check_interval; -} - -/** - * Loads CRLs - */ -void load_crls(void) -{ - struct dirent **filelist; - u_char buf[BUF_LEN]; - u_char *save_dir; - int n; - - /* change directory to specified path */ - save_dir = getcwd(buf, BUF_LEN); - if (chdir(CRL_PATH)) - { - plog("Could not change to directory '%s'", CRL_PATH); - } - else - { - plog("Changing to directory '%s'", CRL_PATH); - n = scandir(CRL_PATH, &filelist, file_select, alphasort); - - if (n < 0) - plog(" scandir() error"); - else - { - while (n--) - { - char *filename = filelist[n]->d_name; - x509crl_t *x509crl; - - x509crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, - CERT_PLUTO_CRL, - BUILD_FROM_FILE, filename, BUILD_END); - if (x509crl) - { - char crl_uri[BUF_LEN]; - - plog(" loaded crl from '%s'", filename); - snprintf(crl_uri, BUF_LEN, "file://%s/%s", CRL_PATH, filename); - insert_crl(x509crl, crl_uri, FALSE); - } - free(filelist[n]); - } - free(filelist); - } - } - /* restore directory path */ - ignore_result(chdir(save_dir)); -} - - -/* Checks if the current certificate is revoked. It goes through the - * list of revoked certificates of the corresponding crl. Either the - * status CERT_GOOD or CERT_REVOKED is returned - */ -static cert_status_t check_revocation(crl_t *crl, chunk_t cert_serial, - time_t *revocationDate, - crl_reason_t *revocationReason) -{ - enumerator_t *enumerator; - cert_status_t status; - chunk_t serial; - - DBG(DBG_CONTROL, - DBG_log("serial number: %#B", &cert_serial) - ) - *revocationDate = UNDEFINED_TIME; - *revocationReason = CRL_REASON_UNSPECIFIED; - status = CERT_GOOD; - - enumerator = crl->create_enumerator(crl); - while (enumerator->enumerate(enumerator, &serial, - revocationDate, revocationReason)) - { - if (chunk_equals(serial, cert_serial)) - { - status = CERT_REVOKED; - break; - } - } - enumerator->destroy(enumerator); - return status; -} - -/* - * check if any crls are about to expire - */ -void check_crls(void) -{ - x509crl_t *x509crl; - time_t now, nextUpdate, time_left; - - lock_crl_list("check_crls"); - time(&now); - x509crl = x509crls; - - while (x509crl != NULL) - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - identification_t *issuer = cert_crl->get_issuer(cert_crl); - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - - cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate); - time_left = nextUpdate - now; - - DBG(DBG_CONTROL, - DBG_log("issuer: '%Y'", issuer); - if (authKeyID.ptr) - { - DBG_log("authkey: %#B", &authKeyID); - } - DBG_log("%ld seconds left", time_left) - ) - if (time_left < 2*crl_check_interval) - { - fetch_req_t *req = build_crl_fetch_request(issuer, authKeyID, - x509crl->distributionPoints); - add_crl_fetch_request(req); - } - x509crl = x509crl->next; - } - unlock_crl_list("check_crls"); -} - -/* - * verify if a cert hasn't been revoked by a crl - */ -cert_status_t verify_by_crl(cert_t *cert, time_t *until, time_t *revocationDate, - crl_reason_t *revocationReason) -{ - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *issuer = certificate->get_issuer(certificate); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - x509crl_t *x509crl; - ca_info_t *ca; - enumerator_t *enumerator; - x509_cdp_t *cdp; - - ca = get_ca_info(issuer, authKeyID); - - *revocationDate = UNDEFINED_TIME; - *revocationReason = CRL_REASON_UNSPECIFIED; - - lock_crl_list("verify_by_crl"); - x509crl = get_x509crl(issuer, authKeyID); - - if (x509crl == NULL) - { - linked_list_t *crluris; - - unlock_crl_list("verify_by_crl"); - plog("crl not found"); - - crluris = linked_list_create(); - if (ca) - { - add_distribution_points(crluris, ca->crluris); - } - - enumerator = x509->create_crl_uri_enumerator(x509); - while (enumerator->enumerate(enumerator, &cdp)) - { - add_distribution_point(crluris, cdp->uri); - } - enumerator->destroy(enumerator); - - if (crluris->get_count(crluris) > 0) - { - fetch_req_t *req; - - req = build_crl_fetch_request(issuer, authKeyID, crluris); - crluris->destroy_function(crluris, free); - add_crl_fetch_request(req); - wake_fetch_thread("verify_by_crl"); - return CERT_UNKNOWN; - } - else - { - crluris->destroy(crluris); - return CERT_UNDEFINED; - } - } - else - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - cert_t *issuer_cert; - bool trusted, valid; - - DBG(DBG_CONTROL, - DBG_log("crl found") - ) - - if (ca) - { - add_distribution_points(x509crl->distributionPoints, ca->crluris); - } - - enumerator = x509->create_crl_uri_enumerator(x509); - while (enumerator->enumerate(enumerator, &cdp)) - { - add_distribution_point(x509crl->distributionPoints, cdp->uri); - } - enumerator->destroy(enumerator); - - lock_authcert_list("verify_by_crl"); - - issuer_cert = get_authcert(issuer, authKeyID, X509_CA); - trusted = issuer_cert ? cert_crl->issued_by(cert_crl, issuer_cert->cert) - : FALSE; - - unlock_authcert_list("verify_by_crl"); - - if (trusted) - { - cert_status_t status; - - DBG(DBG_CONTROL, - DBG_log("crl signature is valid") - ) - - /* return the expiration date */ - valid = cert_crl->get_validity(cert_crl, NULL, NULL, until); - - /* has the certificate been revoked? */ - status = check_revocation(crl, x509->get_serial(x509), revocationDate - , revocationReason); - - if (valid) - { - unlock_crl_list("verify_by_crl"); - DBG(DBG_CONTROL, - DBG_log("crl is valid: until %T", until, FALSE) - ) - } - else - { - fetch_req_t *req; - - DBG(DBG_CONTROL, - DBG_log("crl is stale: since %T", until, FALSE) - ) - - /* try to fetch a crl update */ - req = build_crl_fetch_request(issuer, authKeyID, - x509crl->distributionPoints); - unlock_crl_list("verify_by_crl"); - - add_crl_fetch_request(req); - wake_fetch_thread("verify_by_crl"); - } - return status; - } - else - { - unlock_crl_list("verify_by_crl"); - plog("crl signature is invalid"); - return CERT_UNKNOWN; - } - } -} - -/* - * list all X.509 crls in the chained list - */ -void list_crls(bool utc, bool strict) -{ - x509crl_t *x509crl; - - lock_crl_list("list_crls"); - x509crl = x509crls; - - if (x509crl) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 CRLs:"); - } - - while (x509crl) - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - chunk_t serial, authKeyID; - time_t thisUpdate, nextUpdate; - u_int revoked = 0; - enumerator_t *enumerator; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " issuer: \"%Y\"", - cert_crl->get_issuer(cert_crl)); - serial = chunk_skip_zero(crl->get_serial(crl)); - if (serial.ptr) - { - whack_log(RC_COMMENT, " serial: %#B", &serial); - } - - /* count number of revoked certificates in CRL */ - enumerator = crl->create_enumerator(crl); - while (enumerator->enumerate(enumerator, NULL, NULL, NULL)) - { - revoked++; - } - enumerator->destroy(enumerator); - whack_log(RC_COMMENT, " revoked: %d certificates", revoked); - - list_distribution_points(x509crl->distributionPoints); - - cert_crl->get_validity(cert_crl, NULL, &thisUpdate, &nextUpdate); - whack_log(RC_COMMENT, " updates: this %T", &thisUpdate, utc); - whack_log(RC_COMMENT, " next %T %s", &nextUpdate, utc, - check_expiry(nextUpdate, CRL_WARNING_INTERVAL, strict)); - authKeyID = crl->get_authKeyIdentifier(crl); - if (authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &authKeyID); - } - - x509crl = x509crl->next; - } - unlock_crl_list("list_crls"); -} - diff --git a/src/pluto/crl.h b/src/pluto/crl.h deleted file mode 100644 index 43bafe145..000000000 --- a/src/pluto/crl.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Support of X.509 certificate revocation lists (CRLs) - * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "constants.h" - -#include <utils/linked_list.h> -#include <credentials/certificates/certificate.h> -#include <credentials/certificates/crl.h> - -/* storage structure for an X.509 CRL */ - -typedef struct x509crl x509crl_t; - -struct x509crl { - certificate_t *crl; - x509crl_t *next; - linked_list_t *distributionPoints; -}; - -/* apply a strict CRL policy - * flag set in plutomain.c and used in ipsec_doi.c and rcv_whack.c - */ -extern bool strict_crl_policy; - -/* - * cache the retrieved CRLs by storing them locally as a file - */ -extern bool cache_crls; - -/* - * check periodically for expired crls - */ -extern long crl_check_interval; -extern void load_crls(void); -extern void check_crls(void); -extern bool insert_crl(x509crl_t *crl, char *crl_uri, bool cache_crl); -extern cert_status_t verify_by_crl(cert_t *cert, time_t *until, - time_t *revocationDate, - crl_reason_t *revocationReason); -extern void list_crls(bool utc, bool strict); -extern void free_crls(void); -extern void free_crl(x509crl_t *crl); diff --git a/src/pluto/crypto.c b/src/pluto/crypto.c deleted file mode 100644 index a4f678222..000000000 --- a/src/pluto/crypto.c +++ /dev/null @@ -1,698 +0,0 @@ -/* crypto interfaces - * - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2007-2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * Copyright (C) 1998-2001 D. Hugh Redelmeier - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "crypto.h" -#include "log.h" - -static struct encrypt_desc encrypt_desc_3des = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_3DES_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: DES_BLOCK_SIZE, - keydeflen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, - keyminlen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, - keymaxlen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, -}; - -#define AES_KEY_MIN_LEN 128 -#define AES_KEY_DEF_LEN 128 -#define AES_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_aes = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_AES_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: AES_BLOCK_SIZE, - keyminlen: AES_KEY_MIN_LEN, - keydeflen: AES_KEY_DEF_LEN, - keymaxlen: AES_KEY_MAX_LEN, -}; - -#define CAMELLIA_KEY_MIN_LEN 128 -#define CAMELLIA_KEY_DEF_LEN 128 -#define CAMELLIA_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_camellia = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_CAMELLIA_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: CAMELLIA_BLOCK_SIZE, - keyminlen: CAMELLIA_KEY_MIN_LEN, - keydeflen: CAMELLIA_KEY_DEF_LEN, - keymaxlen: CAMELLIA_KEY_MAX_LEN, -}; - -#define BLOWFISH_KEY_MIN_LEN 128 -#define BLOWFISH_KEY_MAX_LEN 448 - -static struct encrypt_desc encrypt_desc_blowfish = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_BLOWFISH_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: BLOWFISH_BLOCK_SIZE, - keyminlen: BLOWFISH_KEY_MIN_LEN, - keydeflen: BLOWFISH_KEY_MIN_LEN, - keymaxlen: BLOWFISH_KEY_MAX_LEN, -}; - -#define SERPENT_KEY_MIN_LEN 128 -#define SERPENT_KEY_DEF_LEN 128 -#define SERPENT_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_serpent = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_SERPENT_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: SERPENT_BLOCK_SIZE, - keyminlen: SERPENT_KEY_MIN_LEN, - keydeflen: SERPENT_KEY_DEF_LEN, - keymaxlen: SERPENT_KEY_MAX_LEN, -}; - -#define TWOFISH_KEY_MIN_LEN 128 -#define TWOFISH_KEY_DEF_LEN 128 -#define TWOFISH_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_twofish = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_TWOFISH_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: TWOFISH_BLOCK_SIZE, - keydeflen: TWOFISH_KEY_MIN_LEN, - keyminlen: TWOFISH_KEY_DEF_LEN, - keymaxlen: TWOFISH_KEY_MAX_LEN, -}; - -static struct encrypt_desc encrypt_desc_twofish_ssh = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_TWOFISH_CBC_SSH, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: TWOFISH_BLOCK_SIZE, - keydeflen: TWOFISH_KEY_MIN_LEN, - keyminlen: TWOFISH_KEY_DEF_LEN, - keymaxlen: TWOFISH_KEY_MAX_LEN, -}; - -static struct hash_desc hash_desc_md5 = -{ - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_MD5, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_MD5, -}; - -static struct hash_desc hash_desc_sha1 = -{ - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA1, -}; - -static struct hash_desc hash_desc_sha2_256 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_256, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA256, -}; - -static struct hash_desc hash_desc_sha2_384 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_384, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA384, -}; - -static struct hash_desc hash_desc_sha2_512 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_512, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA512, -}; - -const struct dh_desc unset_group = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_NONE, - plugin_name: NULL, - algo_next: NULL, - ke_size: 0 -}; - -static struct dh_desc dh_desc_modp_1024 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_1024_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 1024 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_1536 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_1536_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 1536 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_2048 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_2048_BIT, - algo_next: NULL, - ke_size: 2048 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_3072 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_3072_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 3072 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_4096 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_4096_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 4096 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_6144 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_6144_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 6144 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_8192 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_8192_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 8192 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_256 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_256_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*256 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_384 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_384_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*384 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_521 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_521_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*528 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_1024_160 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_1024_160, - plugin_name: NULL, - algo_next: NULL, - ke_size: 1024 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_2048_224 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_2048_224, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2048 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_2048_256 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_2048_256, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2048 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_192 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_192_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*192 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_224 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_224_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*224 / BITS_PER_BYTE -}; - -bool init_crypto(void) -{ - enumerator_t *enumerator; - encryption_algorithm_t encryption_alg; - hash_algorithm_t hash_alg; - diffie_hellman_group_t dh_group; - const char *plugin_name; - bool no_md5 = TRUE; - bool no_sha1 = TRUE; - - enumerator = lib->crypto->create_hasher_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &hash_alg, &plugin_name)) - { - const struct hash_desc *desc; - - switch (hash_alg) - { - case HASH_SHA1: - desc = &hash_desc_sha1; - no_sha1 = FALSE; - break; - case HASH_SHA256: - desc = &hash_desc_sha2_256; - break; - case HASH_SHA384: - desc = &hash_desc_sha2_384; - break; - case HASH_SHA512: - desc = &hash_desc_sha2_512; - break; - case HASH_MD5: - desc = &hash_desc_md5; - no_md5 = FALSE; - break; - default: - continue; - } - ike_alg_add((struct ike_alg *)desc, plugin_name); - } - enumerator->destroy(enumerator); - - if (no_sha1 || no_md5) - { - plog("pluto cannot run without a %s%s%s hasher", - (no_sha1) ? "SHA-1" : "", - (no_sha1 && no_md5) ? " and " : "", - (no_md5) ? "MD5" : ""); - return FALSE; - } - - enumerator = lib->crypto->create_crypter_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &encryption_alg, &plugin_name)) - { - const struct encrypt_desc *desc; - - switch (encryption_alg) - { - case ENCR_3DES: - desc = &encrypt_desc_3des; - break; - case ENCR_BLOWFISH: - desc = &encrypt_desc_blowfish; - break; - case ENCR_AES_CBC: - desc = &encrypt_desc_aes; - break; - case ENCR_CAMELLIA_CBC: - desc = &encrypt_desc_camellia; - break; - case ENCR_TWOFISH_CBC: - desc = &encrypt_desc_twofish; - ike_alg_add((struct ike_alg *)&encrypt_desc_twofish_ssh, - plugin_name); - break; - case ENCR_SERPENT_CBC: - desc = &encrypt_desc_serpent; - break; - default: - continue; - } - ike_alg_add((struct ike_alg *)desc, plugin_name); - } - enumerator->destroy(enumerator); - - enumerator = lib->crypto->create_dh_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &dh_group, &plugin_name)) - { - const struct dh_desc *desc; - - switch (dh_group) - { - case MODP_1024_BIT: - desc = &dh_desc_modp_1024; - break; - case MODP_1536_BIT: - desc = &dh_desc_modp_1536; - break; - case MODP_2048_BIT: - desc = &dh_desc_modp_2048; - break; - case MODP_3072_BIT: - desc = &dh_desc_modp_3072; - break; - case MODP_4096_BIT: - desc = &dh_desc_modp_4096; - break; - case MODP_6144_BIT: - desc = &dh_desc_modp_6144; - break; - case MODP_8192_BIT: - desc = &dh_desc_modp_8192; - break; - case ECP_256_BIT: - desc = &dh_desc_ecp_256; - break; - case ECP_384_BIT: - desc = &dh_desc_ecp_384; - break; - case ECP_521_BIT: - desc = &dh_desc_ecp_521; - break; - case MODP_1024_160: - desc = &dh_desc_modp_1024_160; - break; - case MODP_2048_224: - desc = &dh_desc_modp_2048_224; - break; - case MODP_2048_256: - desc = &dh_desc_modp_2048_256; - break; - case ECP_192_BIT: - desc = &dh_desc_ecp_192; - break; - case ECP_224_BIT: - desc = &dh_desc_ecp_224; - break; - default: - continue; - } - ike_alg_add((struct ike_alg *)desc, plugin_name); - } - enumerator->destroy(enumerator); - return TRUE; -} - -void free_crypto(void) -{ - /* currently nothing to do */ -} - -/** - * Converts IKEv1 encryption algorithm name to crypter name - */ -encryption_algorithm_t oakley_to_encryption_algorithm(int alg) -{ - switch (alg) - { - case OAKLEY_DES_CBC: - return ENCR_DES; - case OAKLEY_IDEA_CBC: - return ENCR_IDEA; - case OAKLEY_BLOWFISH_CBC: - return ENCR_BLOWFISH; - case OAKLEY_RC5_R16_B64_CBC: - return ENCR_RC5; - case OAKLEY_3DES_CBC: - return ENCR_3DES; - case OAKLEY_CAST_CBC: - return ENCR_CAST; - case OAKLEY_AES_CBC: - return ENCR_AES_CBC; - case OAKLEY_CAMELLIA_CBC: - return ENCR_CAMELLIA_CBC; - case OAKLEY_SERPENT_CBC: - return ENCR_SERPENT_CBC; - case OAKLEY_TWOFISH_CBC: - case OAKLEY_TWOFISH_CBC_SSH: - return ENCR_TWOFISH_CBC; - default: - return ENCR_UNDEFINED; - } -} - -/** - * Converts IKEv1 hash algorithm name to hasher name - */ -hash_algorithm_t oakley_to_hash_algorithm(int alg) -{ - switch (alg) - { - case OAKLEY_MD5: - return HASH_MD5; - case OAKLEY_SHA: - return HASH_SHA1; - case OAKLEY_SHA2_256: - return HASH_SHA256; - case OAKLEY_SHA2_384: - return HASH_SHA384; - case OAKLEY_SHA2_512: - return HASH_SHA512; - default: - return HASH_UNKNOWN; - } -} - -/** - * Converts IKEv1 hash algorithm name to IKEv2 prf name - */ -pseudo_random_function_t oakley_to_prf(int alg) -{ - switch (alg) - { - case OAKLEY_MD5: - return PRF_HMAC_MD5; - case OAKLEY_SHA: - return PRF_HMAC_SHA1; - case OAKLEY_SHA2_256: - return PRF_HMAC_SHA2_256; - case OAKLEY_SHA2_384: - return PRF_HMAC_SHA2_384; - case OAKLEY_SHA2_512: - return PRF_HMAC_SHA2_512; - default: - return PRF_UNDEFINED; - } -} - -/** - * Maps IKEv1 authentication method to IKEv2 signature scheme - */ -signature_scheme_t oakley_to_signature_scheme(int method) -{ - switch (method) - { - case OAKLEY_RSA_SIG: - case XAUTHInitRSA: - case XAUTHRespRSA: - return SIGN_RSA_EMSA_PKCS1_NULL; - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - return SIGN_ECDSA_WITH_NULL; - default: - return SIGN_UNKNOWN; - } -} - -/** - * Table to map IKEv2 encryption algorithms to IKEv1 (or IKEv1 ESP) and back - */ -struct { - encryption_algorithm_t alg; - int oakley; - int esp; -} encr_map[] = { - {ENCR_DES, OAKLEY_DES_CBC, ESP_DES }, - {ENCR_3DES, OAKLEY_3DES_CBC, ESP_3DES }, - {ENCR_RC5, OAKLEY_RC5_R16_B64_CBC, ESP_RC5 }, - {ENCR_IDEA, OAKLEY_IDEA_CBC, ESP_IDEA }, - {ENCR_CAST, OAKLEY_CAST_CBC, ESP_CAST }, - {ENCR_BLOWFISH, OAKLEY_BLOWFISH_CBC, ESP_BLOWFISH }, - {ENCR_AES_CBC, OAKLEY_AES_CBC, ESP_AES }, - {ENCR_CAMELLIA_CBC, OAKLEY_CAMELLIA_CBC, ESP_CAMELLIA }, - {ENCR_SERPENT_CBC, OAKLEY_SERPENT_CBC, ESP_SERPENT }, - {ENCR_TWOFISH_CBC, OAKLEY_TWOFISH_CBC, ESP_TWOFISH }, - {ENCR_NULL, 0, ESP_NULL }, - {ENCR_AES_CTR, 0, ESP_AES_CTR }, - {ENCR_AES_CCM_ICV8, 0, ESP_AES_CCM_8 }, - {ENCR_AES_CCM_ICV12, 0, ESP_AES_CCM_12}, - {ENCR_AES_CCM_ICV16, 0, ESP_AES_CCM_16}, - {ENCR_AES_GCM_ICV8, 0, ESP_AES_GCM_8 }, - {ENCR_AES_GCM_ICV12, 0, ESP_AES_GCM_12}, - {ENCR_AES_GCM_ICV16, 0, ESP_AES_GCM_16}, - {ENCR_NULL_AUTH_AES_GMAC, 0, ESP_AES_GMAC }, -}; - -/** - * Converts IKEv2 encryption to IKEv1 encryption algorithm - */ -int oakley_from_encryption_algorithm(encryption_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(encr_map); i++) - { - if (encr_map[i].alg == alg) - { - return encr_map[i].oakley; - } - } - return 0; -} - -/** - * Converts IKEv2 encryption to IKEv1 ESP encryption algorithm - */ -int esp_from_encryption_algorithm(encryption_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(encr_map); i++) - { - if (encr_map[i].alg == alg) - { - return encr_map[i].esp; - } - } - return 0; -} - -/** - * Converts IKEv1 ESP encryption to IKEv2 algorithm - */ -encryption_algorithm_t encryption_algorithm_from_esp(int esp) -{ - int i; - for (i = 0; i < countof(encr_map); i++) - { - if (encr_map[i].esp == esp) - { - return encr_map[i].alg; - } - } - return 0; -} - -/** - * Table to map IKEv2 integrity algorithms to IKEv1 (or IKEv1 ESP) and back - */ -struct { - integrity_algorithm_t alg; - int oakley; - int esp; -} auth_map[] = { - {AUTH_HMAC_MD5_96, OAKLEY_MD5, AUTH_ALGORITHM_HMAC_MD5 }, - {AUTH_HMAC_SHA1_96, OAKLEY_SHA, AUTH_ALGORITHM_HMAC_SHA1 }, - {AUTH_HMAC_SHA2_256_96, 0, AUTH_ALGORITHM_HMAC_SHA2_256_96}, - {AUTH_HMAC_SHA2_256_128, OAKLEY_SHA2_256, AUTH_ALGORITHM_HMAC_SHA2_256 }, - {AUTH_HMAC_SHA2_384_192, OAKLEY_SHA2_384, AUTH_ALGORITHM_HMAC_SHA2_384 }, - {AUTH_HMAC_SHA2_512_256, OAKLEY_SHA2_512, AUTH_ALGORITHM_HMAC_SHA2_512 }, - {AUTH_AES_XCBC_96, 0, AUTH_ALGORITHM_AES_XCBC_MAC }, - {AUTH_AES_128_GMAC, 0, AUTH_ALGORITHM_AES_128_GMAC }, - {AUTH_AES_192_GMAC, 0, AUTH_ALGORITHM_AES_192_GMAC }, - {AUTH_AES_256_GMAC, 0, AUTH_ALGORITHM_AES_256_GMAC }, -}; - - -/** - * Converts IKEv2 integrity to IKEv1 hash algorithm - */ -int oakley_from_integrity_algorithm(integrity_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(auth_map); i++) - { - if (auth_map[i].alg == alg) - { - return auth_map[i].oakley; - } - } - return 0; -} - -/** - * Converts IKEv2 integrity to IKEv1 ESP authentication algorithm - */ -int esp_from_integrity_algorithm(integrity_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(auth_map); i++) - { - if (auth_map[i].alg == alg) - { - return auth_map[i].esp; - } - } - return 0; -} - -/** - * Converts IKEv1 ESP authentication to IKEv2 integrity algorithm - */ -integrity_algorithm_t integrity_algorithm_from_esp(int esp) -{ - int i; - for (i = 0; i < countof(auth_map); i++) - { - if (auth_map[i].esp == esp) - { - return auth_map[i].alg; - } - } - return 0; -} - diff --git a/src/pluto/crypto.h b/src/pluto/crypto.h deleted file mode 100644 index 16ad12780..000000000 --- a/src/pluto/crypto.h +++ /dev/null @@ -1,64 +0,0 @@ -/* crypto interfaces - * - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * Copyright (C) 1998, 1999 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <crypto/crypters/crypter.h> -#include <crypto/signers/signer.h> -#include <crypto/hashers/hasher.h> -#include <crypto/prfs/prf.h> -#include <credentials/keys/public_key.h> - -#include "ike_alg.h" - -extern bool init_crypto(void); -extern void free_crypto(void); - -extern const struct dh_desc unset_group; /* magic signifier */ - -/* unification of cryptographic encoding/decoding algorithms - * The IV is taken from and returned to st->st_new_iv. - * This allows the old IV to be retained. - * Use update_iv to commit to the new IV (for example, once a packet has - * been validated). - */ - -#define MAX_OAKLEY_KEY_LEN0 (3 * DES_CBC_BLOCK_SIZE) -#define MAX_OAKLEY_KEY_LEN (256/BITS_PER_BYTE) - -struct state; /* forward declaration, dammit */ - -#define update_iv(st) memcpy((st)->st_iv, (st)->st_new_iv \ - , (st)->st_iv_len = (st)->st_new_iv_len) - -#define set_ph1_iv(st, iv) \ - passert((st)->st_ph1_iv_len <= sizeof((st)->st_ph1_iv)); \ - memcpy((st)->st_ph1_iv, (iv), (st)->st_ph1_iv_len); - -/* unification of cryptographic hashing mechanisms */ - -extern encryption_algorithm_t oakley_to_encryption_algorithm(int alg); -extern hash_algorithm_t oakley_to_hash_algorithm(int alg); -extern pseudo_random_function_t oakley_to_prf(int alg); -extern signature_scheme_t oakley_to_signature_scheme(int method); -extern int oakley_from_encryption_algorithm(encryption_algorithm_t alg); -extern int oakley_from_integrity_algorithm(integrity_algorithm_t alg); -extern int esp_from_encryption_algorithm(encryption_algorithm_t alg); -extern int esp_from_integrity_algorithm(integrity_algorithm_t alg); -extern encryption_algorithm_t encryption_algorithm_from_esp(int esp); -extern integrity_algorithm_t integrity_algorithm_from_esp(int esp); - diff --git a/src/pluto/db_ops.c b/src/pluto/db_ops.c deleted file mode 100644 index 547ea5f22..000000000 --- a/src/pluto/db_ops.c +++ /dev/null @@ -1,412 +0,0 @@ -/* Dynamic db (proposal, transforms, attributes) handling. - * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * The stratedy is to have (full contained) struct db_prop in db_context - * pointing to ONE dynamically sizable transform vector (trans0). - * Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0) - * in a "serialized" way (attributes storage is used in linear sequence for - * subsecuent transforms). - * - * Resizing for both trans0 and attrs0 is supported: - * - For trans0: quite simple, just allocate and copy trans. vector content - * also update trans_cur (by offset) - * - For attrs0: after allocating and copying attrs, I must rewrite each - * trans->attrs present in trans0; to achieve this, calculate - * attrs pointer offset (new minus old) and iterate over - * each transform "adding" this difference. - * also update attrs_cur (by offset) - * - * db_context structure: - * +---------------------+ - * | prop | - * | .protoid | - * | .trans | --+ - * | .trans_cnt | | - * +---------------------+ <-+ - * | trans0 | ----> { trans#1 | ... | trans#i | ... } - * +---------------------+ ^ - * | trans_cur | ----------------------' current transf. - * +---------------------+ - * | attrs0 | ----> { attr#1 | ... | attr#j | ... } - * +---------------------+ ^ - * | attrs_cur | ---------------------' current attr. - * +---------------------+ - * | max_trans,max_attrs | max_trans/attrs: number of elem. of each vector - * +---------------------+ - * - * See testing examples at end for interface usage. - */ -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <malloc.h> -#include <sys/types.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "state.h" -#include "packet.h" -#include "spdb.h" -#include "db_ops.h" -#include "log.h" -#include "whack.h" - -#include <assert.h> - -#ifdef NOT_YET -/* - * Allocator cache: - * Because of the single-threaded nature of pluto/spdb.c, - * alloc()/free() is exercised many times with very small - * lifetime objects. - * Just caching last object (currently it will select the - * largest) will avoid this allocation mas^Wperturbations - * - */ -struct db_ops_alloc_cache { - void *ptr; - int size; -}; -#endif - -#ifndef NO_DB_OPS_STATS -/* - * stats: do account for allocations - * displayed in db_ops_show_status() - */ -struct db_ops_stats { - int st_curr_cnt; /* current number of allocations */ - int st_total_cnt; /* total allocations so far */ - size_t st_maxsz; /* max. size requested */ -}; -#define DB_OPS_ZERO { 0, 0, 0}; -#define DB_OPS_STATS_DESC "{curr_cnt, total_cnt, maxsz}" -#define DB_OPS_STATS_STR(name) name "={%d,%d,%d} " -#define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, (int)(st).st_maxsz -static struct db_ops_stats db_context_st = DB_OPS_ZERO; -static struct db_ops_stats db_trans_st = DB_OPS_ZERO; -static struct db_ops_stats db_attrs_st = DB_OPS_ZERO; -static __inline__ void *malloc_bytes_st(size_t size, struct db_ops_stats *st) -{ - void *ptr = malloc(size); - if (ptr) - { - st->st_curr_cnt++; - st->st_total_cnt++; - if (size > st->st_maxsz) st->st_maxsz=size; - } - return ptr; -} -#define ALLOC_BYTES_ST(z,st) malloc_bytes_st(z, &st); -#define PFREE_ST(p,st) do { st.st_curr_cnt--; free(p); } while (0); - -#else - -#define ALLOC_BYTES_ST(z,n) malloc(z); -#define PFREE_ST(p,n) free(p); - -#endif /* NO_DB_OPS_STATS */ -/* Initialize db object - * max_trans and max_attrs can be 0, will be dynamically expanded - * as a result of "add" operations - */ -int -db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs) -{ - ctx->trans0 = NULL; - ctx->attrs0 = NULL; - - if (max_trans > 0) { /* quite silly if not */ - ctx->trans0 = ALLOC_BYTES_ST ( sizeof(struct db_trans) * max_trans, - db_trans_st); - memset(ctx->trans0, '\0', sizeof(struct db_trans) * max_trans); - } - - if (max_attrs > 0) { /* quite silly if not */ - ctx->attrs0 = ALLOC_BYTES_ST (sizeof(struct db_attr) * max_attrs, - db_attrs_st); - memset(ctx->attrs0, '\0', sizeof(struct db_attr) * max_attrs); - } - - ctx->max_trans = max_trans; - ctx->max_attrs = max_attrs; - ctx->trans_cur = ctx->trans0; - ctx->attrs_cur = ctx->attrs0; - ctx->prop.protoid = protoid; - ctx->prop.trans = ctx->trans0; - ctx->prop.trans_cnt = 0; - return 0; -} - -/* Expand storage for transforms by number delta_trans */ -static int -db_trans_expand(struct db_context *ctx, int delta_trans) -{ - int ret = -1; - struct db_trans *new_trans, *old_trans; - int max_trans = ctx->max_trans + delta_trans; - int offset; - - old_trans = ctx->trans0; - new_trans = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans, - db_trans_st); - if (!new_trans) - goto out; - memcpy(new_trans, old_trans, ctx->max_trans * sizeof(struct db_trans)); - - /* update trans0 (obviously) */ - ctx->trans0 = ctx->prop.trans = new_trans; - /* update trans_cur (by offset) */ - offset = (char *)(new_trans) - (char *)(old_trans); - - { - char *cctx = (char *)(ctx->trans_cur); - - cctx += offset; - ctx->trans_cur = (struct db_trans *)cctx; - } - /* update elem count */ - ctx->max_trans = max_trans; - PFREE_ST(old_trans, db_trans_st); - ret = 0; -out: - return ret; -} -/* - * Expand storage for attributes by delta_attrs number AND - * rewrite trans->attr pointers - */ -static int -db_attrs_expand(struct db_context *ctx, int delta_attrs) -{ - int ret = -1; - struct db_attr *new_attrs, *old_attrs; - struct db_trans *t; - int ti; - int max_attrs = ctx->max_attrs + delta_attrs; - int offset; - - old_attrs = ctx->attrs0; - new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs, - db_attrs_st); - if (!new_attrs) - goto out; - - memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr)); - - /* update attrs0 and attrs_cur (obviously) */ - offset = (char *)(new_attrs) - (char *)(old_attrs); - - { - char *actx = (char *)(ctx->attrs0); - - actx += offset; - ctx->attrs0 = (struct db_attr *)actx; - - actx = (char *)ctx->attrs_cur; - actx += offset; - ctx->attrs_cur = (struct db_attr *)actx; - } - - /* for each transform, rewrite attrs pointer by offsetting it */ - for (t=ctx->prop.trans, ti=0; ti < ctx->prop.trans_cnt; t++, ti++) { - char *actx = (char *)(t->attrs); - - actx += offset; - t->attrs = (struct db_attr *)actx; - } - /* update elem count */ - ctx->max_attrs = max_attrs; - PFREE_ST(old_attrs, db_attrs_st); - ret = 0; -out: - return ret; -} -/* Allocate a new db object */ -struct db_context * -db_prop_new(u_int8_t protoid, int max_trans, int max_attrs) -{ - struct db_context *ctx; - ctx = ALLOC_BYTES_ST ( sizeof (struct db_context), db_context_st); - if (!ctx) goto out; - - if (db_prop_init(ctx, protoid, max_trans, max_attrs) < 0) { - PFREE_ST(ctx, db_context_st); - ctx=NULL; - } -out: - return ctx; -} -/* Free a db object */ -void -db_destroy(struct db_context *ctx) -{ - if (ctx->trans0) PFREE_ST(ctx->trans0, db_trans_st); - if (ctx->attrs0) PFREE_ST(ctx->attrs0, db_attrs_st); - PFREE_ST(ctx, db_context_st); -} -/* Start a new transform, expand trans0 is needed */ -int -db_trans_add(struct db_context *ctx, u_int8_t transid) -{ - /* skip incrementing current trans pointer the 1st time*/ - if (ctx->trans_cur && ctx->trans_cur->attr_cnt) - ctx->trans_cur++; - /* - * Strategy: if more space is needed, expand by - * <current_size>/2 + 1 - * - * This happens to produce a "reasonable" sequence - * after few allocations, eg.: - * 0,1,2,4,8,13,20,31,47 - */ - if ((ctx->trans_cur - ctx->trans0) >= ctx->max_trans) { - /* XXX:jjo if fails should shout and flag it */ - if (db_trans_expand(ctx, ctx->max_trans/2 + 1)<0) - return -1; - } - ctx->trans_cur->transid = transid; - ctx->trans_cur->attrs=ctx->attrs_cur; - ctx->trans_cur->attr_cnt = 0; - ctx->prop.trans_cnt++; - return 0; -} -/* Add attr copy to current transform, expanding attrs0 if needed */ -int -db_attr_add(struct db_context *ctx, const struct db_attr *a) -{ - /* - * Strategy: if more space is needed, expand by - * <current_size>/2 + 1 - */ - if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) { - /* XXX:jjo if fails should shout and flag it */ - if (db_attrs_expand(ctx, ctx->max_attrs/2 + 1) < 0) - return -1; - } - *ctx->attrs_cur++=*a; - ctx->trans_cur->attr_cnt++; - return 0; -} -/* Add attr copy (by value) to current transform, - * expanding attrs0 if needed, just calls db_attr_add(). - */ -int -db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val) -{ - struct db_attr attr; - attr.type = type; - attr.val = val; - return db_attr_add (ctx, &attr); -} -#ifndef NO_DB_OPS_STATS -int -db_ops_show_status(void) -{ - whack_log(RC_COMMENT, "stats " __FILE__ ": " - DB_OPS_STATS_DESC " :" - DB_OPS_STATS_STR("context") - DB_OPS_STATS_STR("trans") - DB_OPS_STATS_STR("attrs"), - DB_OPS_STATS_F(db_context_st), - DB_OPS_STATS_F(db_trans_st), - DB_OPS_STATS_F(db_attrs_st) - ); - return 0; -} -#endif /* NO_DB_OPS_STATS */ -/* - * From below to end just testing stuff .... - */ -#ifdef TEST -static void db_prop_print(struct db_prop *p) -{ - struct db_trans *t; - struct db_attr *a; - int ti, ai; - enum_names *n, *n_at, *n_av; - printf("protoid=\"%s\"\n", enum_name(&protocol_names, p->protoid)); - for (ti=0, t=p->trans; ti< p->trans_cnt; ti++, t++) { - switch( t->transid) { - case PROTO_ISAKMP: - n=&isakmp_transformid_names;break; - case PROTO_IPSEC_ESP: - n=&esp_transformid_names;break; - default: - continue; - } - printf(" transid=\"%s\"\n", - enum_name(n, t->transid)); - for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) { - int i; - switch( t->transid) { - case PROTO_ISAKMP: - n_at=&oakley_attr_names; - i=a->type|ISAKMP_ATTR_AF_TV; - n_av=oakley_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK]; - break; - case PROTO_IPSEC_ESP: - n_at=&ipsec_attr_names; - i=a->type|ISAKMP_ATTR_AF_TV; - n_av=ipsec_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK]; - break; - default: - continue; - } - printf(" type=\"%s\" value=\"%s\"\n", - enum_name(n_at, i), - enum_name(n_av, a->val)); - } - } - -} -static void db_print(struct db_context *ctx) -{ - printf("trans_cur diff=%d, attrs_cur diff=%d\n", - ctx->trans_cur - ctx->trans0, - ctx->attrs_cur - ctx->attrs0); - db_prop_print(&ctx->prop); -} - -void -passert_fail(const char *pred_str, const char *file_str, unsigned long line_no); -void abort(void); -void -passert_fail(const char *pred_str, const char *file_str, unsigned long line_no) -{ - fprintf(stderr, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str); - abort(); /* exiting correctly doesn't always work */ -} -int main(void) { - struct db_context *ctx=db_prop_new(PROTO_ISAKMP, 0, 0); - db_trans_add(ctx, KEY_IKE); - db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC); - db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5); - db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG); - db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024); - db_trans_add(ctx, KEY_IKE); - db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_AES_CBC); - db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5); - db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY); - db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536); - db_trans_add(ctx, ESP_3DES); - db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1); - db_print(ctx); - db_destroy(ctx); - return 0; -} -#endif diff --git a/src/pluto/db_ops.h b/src/pluto/db_ops.h deleted file mode 100644 index 464c245dd..000000000 --- a/src/pluto/db_ops.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Dynamic db (proposal, transforms, attributes) handling. - * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _DB_OPS_H -#define _DB_OPS_H - -/* - * Main db object, (quite proposal "oriented") - */ -#ifndef NO_DB_CONTEXT -struct db_context { - struct db_prop prop; /* proposal buffer (not pointer) */ - struct db_trans *trans0; /* transf. list, dynamically sized */ - struct db_trans *trans_cur; /* current transform ptr */ - struct db_attr *attrs0; /* attr. list, dynamically sized */ - struct db_attr *attrs_cur; /* current attribute ptr */ - int max_trans; /* size of trans list */ - int max_attrs; /* size of attrs list */ -}; -/* - * Allocate a new db object - */ -struct db_context * db_prop_new(u_int8_t protoid, int max_trans, int max_attrs); -/* Initialize object for proposal building */ -int db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs); -/* Free all resourses for this db */ -void db_destroy(struct db_context *ctx); - -/* Start a new transform */ -int db_trans_add(struct db_context *ctx, u_int8_t transid); -/* Add a new attribute by copying db_attr content */ -int db_attr_add(struct db_context *db_ctx, const struct db_attr *attr); -/* Add a new attribute by value */ -int db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val); - -/* Get proposal from db object */ -static __inline__ struct db_prop *db_prop_get(struct db_context *ctx) { - return &ctx->prop; -} -/* Show stats (allocation, etc) */ -#endif /* NO_DB_CONTEXT */ -int db_ops_show_status(void); -#endif /* _DB_OPS_H */ diff --git a/src/pluto/defs.c b/src/pluto/defs.c deleted file mode 100644 index 7f3a819de..000000000 --- a/src/pluto/defs.c +++ /dev/null @@ -1,145 +0,0 @@ -/* misc. universal things - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <dirent.h> -#include <inttypes.h> -#include <time.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ - -bool -all_zero(const unsigned char *m, size_t len) -{ - size_t i; - - for (i = 0; i != len; i++) - if (m[i] != '\0') - return FALSE; - return TRUE; -} - -/* Note that there may be as many as six IDs that are temporary at - * one time before unsharing the two ends of a connection. So we need - * at least six temporary buffers for DER_ASN1_DN IDs. - * We rotate them. Be careful! - */ -#define MAX_BUF 10 - -char* -temporary_cyclic_buffer(void) -{ - static char buf[MAX_BUF][BUF_LEN]; /* MAX_BUF internal buffers */ - static int counter = 0; /* cyclic counter */ - - if (++counter == MAX_BUF) counter = 0; /* next internal buffer */ - return buf[counter]; /* assign temporary buffer */ -} - -/* concatenates two sub paths into a string with a maximum size of BUF_LEN - * use for temporary storage only - */ -char* concatenate_paths(char *a, char *b) -{ - char *c; - - if (*b == '/' || *b == '.') - return b; - - c = temporary_cyclic_buffer(); - snprintf(c, BUF_LEN, "%s/%s", a, b); - return c; -} - -/* moves a chunk to a memory position, chunk is freed afterwards - * position pointer is advanced after the insertion point - */ -void -mv_chunk(u_char **pos, chunk_t content) -{ - if (content.len > 0) - { - chunkcpy(*pos, content); - free(content.ptr); - } -} - -/* checks if the expiration date has been reached and - * warns during the warning_interval of the imminent - * expiry. strict=TRUE declares a fatal error, - * strict=FALSE issues a warning upon expiry. - */ -const char* -check_expiry(time_t expiration_date, int warning_interval, bool strict) -{ - time_t now, time_left; - - if (expiration_date == UNDEFINED_TIME) - return "ok (expires never)"; - - /* determine the current time */ - time(&now); - - time_left = (expiration_date - now); - if (time_left < 0) - return strict? "fatal (expired)" : "warning (expired)"; - - if (time_left > 86400*warning_interval) - return "ok"; - { - static char buf[35]; /* temporary storage */ - const char* unit = "second"; - - if (time_left > 172800) - { - time_left /= 86400; - unit = "day"; - } - else if (time_left > 7200) - { - time_left /= 3600; - unit = "hour"; - } - else if (time_left > 120) - { - time_left /= 60; - unit = "minute"; - } - snprintf(buf, 35, "warning (expires in %" PRIu64 " %s%s)", - (u_int64_t)time_left, unit, (time_left == 1) ? "" : "s"); - return buf; - } -} - - -/* - * Filter eliminating the directory entries '.' and '..' - */ -int -file_select(const struct dirent *entry) -{ - return strcmp(entry->d_name, "." ) && - strcmp(entry->d_name, ".."); -} - - diff --git a/src/pluto/defs.h b/src/pluto/defs.h deleted file mode 100644 index 532652e5b..000000000 --- a/src/pluto/defs.h +++ /dev/null @@ -1,79 +0,0 @@ -/* misc. universal things - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _DEFS_H -#define _DEFS_H - -#include <string.h> -#include <sys/types.h> - -#include <chunk.h> - -#ifdef DEBUG -# define USED_BY_DEBUG /* ignore */ -#else -# define USED_BY_DEBUG UNUSED -#endif - -/* type of serial number of a state object - * Needed in connections.h and state.h; here to simplify dependencies. - */ -typedef unsigned long so_serial_t; -#define SOS_NOBODY 0 /* null serial number */ -#define SOS_FIRST 1 /* first normal serial number */ - -/* memory allocation */ - -#define clone_thing(orig) clalloc((void *)&(orig), sizeof(orig)) - -#define clone_str(str) \ - ((str) == NULL? NULL : strdup(str)) - -#define replace(p, q) \ - { free(p); (p) = (q); } - -#define chunkcpy(dst, chunk) \ - { memcpy(dst, chunk.ptr, chunk.len); dst += chunk.len;} - -extern char* temporary_cyclic_buffer(void); -extern char* concatenate_paths(char *a, char *b); - -/* move a chunk to a memory position and free it after insertion */ -extern void mv_chunk(u_char **pos, chunk_t content); - -/* warns a predefined interval before expiry */ -extern const char* check_expiry(time_t expiration_date, - int warning_interval, bool strict); - -#define MAX_PROMPT_PASS_TRIALS 5 -#define PROMPT_PASS_LEN 64 - -/* filter eliminating the directory entries '.' and '..' */ -typedef struct dirent dirent_t; -extern int file_select(const dirent_t *entry); - -/* cleanly exit Pluto */ -extern void exit_pluto(int /*status*/) NEVER_RETURNS; - -/* zero all bytes */ -#define zero(x) memset((x), '\0', sizeof(*(x))) - -/* are all bytes 0? */ -extern bool all_zero(const unsigned char *m, size_t len); - -/* pad_up(n, m) is the amount to add to n to make it a multiple of m */ -#define pad_up(n, m) (((m) - 1) - (((n) + (m) - 1) % (m))) - -#endif /* _DEFS_H */ diff --git a/src/pluto/demux.c b/src/pluto/demux.c deleted file mode 100644 index 612e0813c..000000000 --- a/src/pluto/demux.c +++ /dev/null @@ -1,2527 +0,0 @@ -/* demultiplex incoming IKE messages - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* Ordering Constraints on Payloads - * - * rfc2409: The Internet Key Exchange (IKE) - * - * 5 Exchanges: - * "The SA payload MUST precede all other payloads in a phase 1 exchange." - * - * "Except where otherwise noted, there are no requirements for ISAKMP - * payloads in any message to be in any particular order." - * - * 5.3 Phase 1 Authenticated With a Revised Mode of Public Key Encryption: - * - * "If the HASH payload is sent it MUST be the first payload of the - * second message exchange and MUST be followed by the encrypted - * nonce. If the HASH payload is not sent, the first payload of the - * second message exchange MUST be the encrypted nonce." - * - * "Save the requirements on the location of the optional HASH payload - * and the mandatory nonce payload there are no further payload - * requirements. All payloads-- in whatever order-- following the - * encrypted nonce MUST be encrypted with Ke_i or Ke_r depending on the - * direction." - * - * 5.5 Phase 2 - Quick Mode - * - * "In Quick Mode, a HASH payload MUST immediately follow the ISAKMP - * header and a SA payload MUST immediately follow the HASH." - * [NOTE: there may be more than one SA payload, so this is not - * totally reasonable. Probably all SAs should be so constrained.] - * - * "If ISAKMP is acting as a client negotiator on behalf of another - * party, the identities of the parties MUST be passed as IDci and - * then IDcr." - * - * "With the exception of the HASH, SA, and the optional ID payloads, - * there are no payload ordering restrictions on Quick Mode." - */ - -/* Unfolding of Identity -- a central mystery - * - * This concerns Phase 1 identities, those of the IKE hosts. - * These are the only ones that are authenticated. Phase 2 - * identities are for IPsec SAs. - * - * There are three case of interest: - * - * (1) We initiate, based on a whack command specifying a Connection. - * We know the identity of the peer from the Connection. - * - * (2) (to be implemented) we initiate based on a flow from our client - * to some IP address. - * We immediately know one of the peer's client IP addresses from - * the flow. We must use this to figure out the peer's IP address - * and Id. To be solved. - * - * (3) We respond to an IKE negotiation. - * We immediately know the peer's IP address. - * We get an ID Payload in Main I2. - * - * Unfortunately, this is too late for a number of things: - * - the ISAKMP SA proposals have already been made (Main I1) - * AND one accepted (Main R1) - * - the SA includes a specification of the type of ID - * authentication so this is negotiated without being told the ID. - * - with Preshared Key authentication, Main I2 is encrypted - * using the key, so it cannot be decoded to reveal the ID - * without knowing (or guessing) which key to use. - * - * There are three reasonable choices here for the responder: - * + assume that the initiator is making wise offers since it - * knows the IDs involved. We can balk later (but not gracefully) - * when we find the actual initiator ID - * + attempt to infer identity by IP address. Again, we can balk - * when the true identity is revealed. Actually, it is enough - * to infer properties of the identity (eg. SA properties and - * PSK, if needed). - * + make all properties universal so discrimination based on - * identity isn't required. For example, always accept the same - * kinds of encryption. Accept Public Key Id authentication - * since the Initiator presumably has our public key and thinks - * we must have / can find his. This approach is weakest - * for preshared key since the actual key must be known to - * decrypt the Initiator's ID Payload. - * These choices can be blended. For example, a class of Identities - * can be inferred, sufficient to select a preshared key but not - * sufficient to infer a unique identity. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/time.h> /* only used for belt-and-suspenders select call */ -#include <sys/poll.h> /* only used for forensic poll call */ -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <sys/queue.h> - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) -# include <asm/types.h> /* for __u8, __u32 */ -# include <linux/errqueue.h> -# include <sys/uio.h> /* struct iovec */ -#endif - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "cookie.h" -#include "connections.h" -#include "state.h" -#include "packet.h" -#include "crypto.h" -#include "ike_alg.h" -#include "log.h" -#include "demux.h" /* needs packet.h */ -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "timer.h" -#include "whack.h" /* requires connections.h */ -#include "server.h" -#include "nat_traversal.h" -#include "vendor.h" -#include "modecfg.h" - -/* This file does basic header checking and demux of - * incoming packets. - */ - -/* forward declarations */ -static bool read_packet(struct msg_digest *md); -static void process_packet(struct msg_digest **mdp); - -/* Reply messages are built in this buffer. - * Only one state transition function can be using it at a time - * so suspended STFs must save and restore it. - * It could be an auto variable of complete_state_transition except for the fact - * that when a suspended STF resumes, its reply message buffer - * must be at the same location -- there are pointers into it. - */ -u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE]; - -/* state_microcode is a tuple of information parameterizing certain - * centralized processing of a packet. For example, it roughly - * specifies what payloads are expected in this message. - * The microcode is selected primarily based on the state. - * In Phase 1, the payload structure often depends on the - * authentication technique, so that too plays a part in selecting - * the state_microcode to use. - */ - -struct state_microcode { - enum state_kind state, next_state; - lset_t flags; - lset_t req_payloads; /* required payloads (allows just one) */ - lset_t opt_payloads; /* optional payloads (any mumber) */ - /* if not ISAKMP_NEXT_NONE, process_packet will emit HDR with this as np */ - u_int8_t first_out_payload; - enum event_type timeout_event; - state_transition_fn *processor; -}; - -/* State Microcode Flags, in several groups */ - -/* Oakley Auth values: to which auth values does this entry apply? - * Most entries will use SMF_ALL_AUTH because they apply to all. - * Note: SMF_ALL_AUTH matches 0 for those circumstances when no auth - * has been set. - */ -#define SMF_ALL_AUTH LRANGE(0, OAKLEY_AUTH_ROOF-1) -#define SMF_PSK_AUTH LELEM(OAKLEY_PRESHARED_KEY) -#define SMF_DS_AUTH (LELEM(OAKLEY_DSS_SIG) | LELEM(OAKLEY_RSA_SIG) | \ - LELEM(OAKLEY_ECDSA_SIG) | LELEM(OAKLEY_ECDSA_256) | \ - LELEM(OAKLEY_ECDSA_384) | LELEM(OAKLEY_ECDSA_521)) -#define SMF_PKE_AUTH (LELEM(OAKLEY_RSA_ENC) | LELEM(OAKLEY_ELGAMAL_ENC)) -#define SMF_RPKE_AUTH (LELEM(OAKLEY_RSA_ENC_REV) | LELEM(OAKLEY_ELGAMAL_ENC_REV)) - -/* misc flags */ - -#define SMF_INITIATOR LELEM(OAKLEY_AUTH_ROOF + 0) -#define SMF_FIRST_ENCRYPTED_INPUT LELEM(OAKLEY_AUTH_ROOF + 1) -#define SMF_INPUT_ENCRYPTED LELEM(OAKLEY_AUTH_ROOF + 2) -#define SMF_OUTPUT_ENCRYPTED LELEM(OAKLEY_AUTH_ROOF + 3) -#define SMF_RETRANSMIT_ON_DUPLICATE LELEM(OAKLEY_AUTH_ROOF + 4) - -#define SMF_ENCRYPTED (SMF_INPUT_ENCRYPTED | SMF_OUTPUT_ENCRYPTED) - -/* this state generates a reply message */ -#define SMF_REPLY LELEM(OAKLEY_AUTH_ROOF + 5) - -/* this state completes P1, so any pending P2 negotiations should start */ -#define SMF_RELEASE_PENDING_P2 LELEM(OAKLEY_AUTH_ROOF + 6) - -/* end of flags */ - - -static state_transition_fn /* forward declaration */ - unexpected, - informational; - -/* state_microcode_table is a table of all state_microcode tuples. - * It must be in order of state (the first element). - * After initialization, ike_microcode_index[s] points to the - * first entry in state_microcode_table for state s. - * Remember that each state name in Main or Quick Mode describes - * what has happened in the past, not what this message is. - */ - -static const struct state_microcode - *ike_microcode_index[STATE_IKE_ROOF - STATE_IKE_FLOOR]; - -static const struct state_microcode state_microcode_table[] = { -#define PT(n) ISAKMP_NEXT_##n -#define P(n) LELEM(PT(n)) - - /***** Phase 1 Main Mode *****/ - - /* No state for main_outI1: --> HDR, SA */ - - /* STATE_MAIN_R0: I1 --> R1 - * HDR, SA --> HDR, SA - */ - { STATE_MAIN_R0, STATE_MAIN_R1 - , SMF_ALL_AUTH | SMF_REPLY - , P(SA), P(VID) | P(CR), PT(NONE) - , EVENT_RETRANSMIT, main_inI1_outR1}, - - /* STATE_MAIN_I1: R1 --> I2 - * HDR, SA --> auth dependent - * SMF_PSK_AUTH, SMF_DS_AUTH: --> HDR, KE, Ni - * SMF_PKE_AUTH: - * --> HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r - * SMF_RPKE_AUTH: - * --> HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i, <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i] - * Note: since we don't know auth at start, we cannot differentiate - * microcode entries based on it. - */ - { STATE_MAIN_I1, STATE_MAIN_I2 - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_REPLY - , P(SA), P(VID) | P(CR), PT(NONE) /* don't know yet */ - , EVENT_RETRANSMIT, main_inR1_outI2 }, - - /* STATE_MAIN_R1: I2 --> R2 - * SMF_PSK_AUTH, SMF_DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr - * SMF_PKE_AUTH: HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r - * --> HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i - * SMF_RPKE_AUTH: - * HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i, <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i] - * --> HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r - */ - { STATE_MAIN_R1, STATE_MAIN_R2 - , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_REPLY - , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(KE) - , EVENT_RETRANSMIT, main_inI2_outR2 }, - - { STATE_MAIN_R1, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_REPLY - , P(KE) | P(ID) | P(NONCE), P(VID) | P(CR) | P(HASH), PT(KE) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - { STATE_MAIN_R1, STATE_UNDEFINED - , SMF_RPKE_AUTH | SMF_REPLY - , P(NONCE) | P(KE) | P(ID), P(VID) | P(CR) | P(HASH) | P(CERT), PT(NONCE) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - /* for states from here on, output message must be encrypted */ - - /* STATE_MAIN_I2: R2 --> I3 - * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I - * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I - * SMF_PKE_AUTH: HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i - * --> HDR*, HASH_I - * SMF_RPKE_AUTH: HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r - * --> HDR*, HASH_I - */ - { STATE_MAIN_I2, STATE_MAIN_I3 - , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY - , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(ID) - , EVENT_RETRANSMIT, main_inR2_outI3 }, - - { STATE_MAIN_I2, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY - , P(KE) | P(ID) | P(NONCE), P(VID) | P(CR), PT(HASH) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - { STATE_MAIN_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY - , P(NONCE) | P(KE) | P(ID), P(VID) | P(CR), PT(HASH) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - /* for states from here on, input message must be encrypted */ - - /* STATE_MAIN_R2: I3 --> R3 - * SMF_PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R - * SMF_DS_AUTH: HDR*, IDi1, [ CERT, ] SIG_I --> HDR*, IDr1, [ CERT, ] SIG_R - * SMF_PKE_AUTH, SMF_RPKE_AUTH: HDR*, HASH_I --> HDR*, HASH_R - */ - { STATE_MAIN_R2, STATE_MAIN_R3 - , SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED - | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ID) | P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, main_inI3_outR3 }, - - { STATE_MAIN_R2, STATE_MAIN_R3 - , SMF_DS_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED - | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), PT(NONE) - , EVENT_SA_REPLACE, main_inI3_outR3 }, - - { STATE_MAIN_R2, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED - | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ }, - - /* STATE_MAIN_I3: R3 --> done - * SMF_PSK_AUTH: HDR*, IDr1, HASH_R --> done - * SMF_DS_AUTH: HDR*, IDr1, [ CERT, ] SIG_R --> done - * SMF_PKE_AUTH, SMF_RPKE_AUTH: HDR*, HASH_R --> done - * May initiate quick mode by calling quick_outI1 - */ - { STATE_MAIN_I3, STATE_MAIN_I4 - , SMF_PSK_AUTH | SMF_INITIATOR - | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ID) | P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, main_inR3 }, - - { STATE_MAIN_I3, STATE_MAIN_I4 - , SMF_DS_AUTH | SMF_INITIATOR - | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), PT(NONE) - , EVENT_SA_REPLACE, main_inR3 }, - - { STATE_MAIN_I3, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_INITIATOR - | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ }, - - /* STATE_MAIN_R3: can only get here due to packet loss */ - { STATE_MAIN_R3, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE - , LEMPTY, LEMPTY - , PT(NONE), EVENT_NULL, unexpected }, - - /* STATE_MAIN_I4: can only get here due to packet loss */ - { STATE_MAIN_I4, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED - , LEMPTY, LEMPTY - , PT(NONE), EVENT_NULL, unexpected }, - - - /***** Phase 2 Quick Mode *****/ - - /* No state for quick_outI1: - * --> HDR*, HASH(1), SA, Nr [, KE ] [, IDci, IDcr ] - */ - - /* STATE_QUICK_R0: - * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] - * Installs inbound IPsec SAs. - * Because it may suspend for asynchronous DNS, first_out_payload - * is set to NONE to suppress early emission of HDR*. - * ??? it is legal to have multiple SAs, but we don't support it yet. - */ - { STATE_QUICK_R0, STATE_QUICK_R1 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY - , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(NONE) - , EVENT_RETRANSMIT, quick_inI1_outR1 }, - - /* STATE_QUICK_I1: - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(3) - * Installs inbound and outbound IPsec SAs, routing, etc. - * ??? it is legal to have multiple SAs, but we don't support it yet. - */ - { STATE_QUICK_I1, STATE_QUICK_I2 - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_REPLY - , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(HASH) - , EVENT_SA_REPLACE, quick_inR1_outI2 }, - - /* STATE_QUICK_R1: HDR*, HASH(3) --> done - * Installs outbound IPsec SAs, routing, etc. - */ - { STATE_QUICK_R1, STATE_QUICK_R2 - , SMF_ALL_AUTH | SMF_ENCRYPTED - , P(HASH), LEMPTY, PT(NONE) - , EVENT_SA_REPLACE, quick_inI2 }, - - /* STATE_QUICK_I2: can only happen due to lost packet */ - { STATE_QUICK_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - /* STATE_QUICK_R2: can only happen due to lost packet */ - { STATE_QUICK_R2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - - /***** informational messages *****/ - - /* STATE_INFO: */ - { STATE_INFO, STATE_UNDEFINED - , SMF_ALL_AUTH - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, informational }, - - /* STATE_INFO_PROTECTED: */ - { STATE_INFO_PROTECTED, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , P(HASH), LEMPTY, PT(NONE) - , EVENT_NULL, informational }, - - /* XAUTH state transitions */ - { STATE_XAUTH_I0, STATE_XAUTH_I1 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_RETRANSMIT, xauth_inI0 }, - - { STATE_XAUTH_R1, STATE_XAUTH_R2 - , SMF_ALL_AUTH | SMF_ENCRYPTED - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_RETRANSMIT, xauth_inR1 }, - - { STATE_XAUTH_I1, STATE_XAUTH_I2 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, xauth_inI1 }, - - { STATE_XAUTH_R2, STATE_XAUTH_R3 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(NONE) - , EVENT_SA_REPLACE, xauth_inR2 }, - - { STATE_XAUTH_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - { STATE_XAUTH_R3, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - /* ModeCfg pull mode state transitions */ - - { STATE_MODE_CFG_R0, STATE_MODE_CFG_R1 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inR0 }, - - { STATE_MODE_CFG_I1, STATE_MODE_CFG_I2 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inI1 }, - - { STATE_MODE_CFG_R1, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - { STATE_MODE_CFG_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - /* ModeCfg push mode state transitions */ - - { STATE_MODE_CFG_I0, STATE_MODE_CFG_I3 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inI0 }, - - { STATE_MODE_CFG_R3, STATE_MODE_CFG_R4 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inR3 }, - - { STATE_MODE_CFG_I3, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - { STATE_MODE_CFG_R4, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - -#undef P -#undef PT -}; - -void -init_demux(void) -{ - /* fill ike_microcode_index: - * make ike_microcode_index[s] point to first entry in - * state_microcode_table for state s (backward scan makes this easier). - * Check that table is in order -- catch coding errors. - * For what it's worth, this routine is idempotent. - */ - const struct state_microcode *t; - - for (t = &state_microcode_table[countof(state_microcode_table) - 1];;) - { - passert(STATE_IKE_FLOOR <= t->state && t->state < STATE_IKE_ROOF); - ike_microcode_index[t->state - STATE_IKE_FLOOR] = t; - if (t == state_microcode_table) - break; - t--; - passert(t[0].state <= t[1].state); - } -} - -/* Process any message on the MSG_ERRQUEUE - * - * This information is generated because of the IP_RECVERR socket option. - * The API is sparsely documented, and may be LINUX-only, and only on - * fairly recent versions at that (hence the conditional compilation). - * - * - ip(7) describes IP_RECVERR - * - recvmsg(2) describes MSG_ERRQUEUE - * - readv(2) describes iovec - * - cmsg(3) describes how to process auxiliary messages - * - * ??? we should link this message with one we've sent - * so that the diagnostic can refer to that negotiation. - * - * ??? how long can the messge be? - * - * ??? poll(2) has a very incomplete description of the POLL* events. - * We assume that POLLIN, POLLOUT, and POLLERR are all we need to deal with - * and that POLLERR will be on iff there is a MSG_ERRQUEUE message. - * - * We have to code around a couple of surprises: - * - * - Select can say that a socket is ready to read from, and - * yet a read will hang. It turns out that a message available on the - * MSG_ERRQUEUE will cause select to say something is pending, but - * a normal read will hang. poll(2) can tell when a MSG_ERRQUEUE - * message is pending. - * - * This is dealt with by calling check_msg_errqueue after select - * has indicated that there is something to read, but before the - * read is performed. check_msg_errqueue will return TRUE if there - * is something left to read. - * - * - A write to a socket may fail because there is a pending MSG_ERRQUEUE - * message, without there being anything wrong with the write. This - * makes for confusing diagnostics. - * - * To avoid this, we call check_msg_errqueue before a write. True, - * there is a race condition (a MSG_ERRQUEUE message might arrive - * between the check and the write), but we should eliminate many - * of the problematic events. To narrow the window, the poll(2) - * will await until an event happens (in the case or a write, - * POLLOUT; this should be benign for POLLIN). - */ - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) -static bool -check_msg_errqueue(const struct iface *ifp, short interest) -{ - struct pollfd pfd; - - pfd.fd = ifp->fd; - pfd.events = interest | POLLPRI | POLLOUT; - - while (pfd.revents = 0 - , poll(&pfd, 1, -1) > 0 && (pfd.revents & POLLERR)) - { - u_int8_t buffer[3000]; /* hope that this is big enough */ - union - { - struct sockaddr sa; - struct sockaddr_in sa_in4; - struct sockaddr_in6 sa_in6; - } from; - - int from_len = sizeof(from); - - int packet_len; - - struct msghdr emh; - struct iovec eiov; - union { - /* force alignment (not documented as necessary) */ - struct cmsghdr ecms; - - /* how much space is enough? */ - unsigned char space[256]; - } ecms_buf; - - struct cmsghdr *cm; - char fromstr[sizeof(" for message to port 65536") + INET6_ADDRSTRLEN]; - struct state *sender = NULL; - - zero(&from.sa); - from_len = sizeof(from); - - emh.msg_name = &from.sa; /* ??? filled in? */ - emh.msg_namelen = sizeof(from); - emh.msg_iov = &eiov; - emh.msg_iovlen = 1; - emh.msg_control = &ecms_buf; - emh.msg_controllen = sizeof(ecms_buf); - emh.msg_flags = 0; - - eiov.iov_base = buffer; /* see readv(2) */ - eiov.iov_len = sizeof(buffer); - - packet_len = recvmsg(ifp->fd, &emh, MSG_ERRQUEUE); - - if (packet_len == -1) - { - log_errno((e, "recvmsg(,, MSG_ERRQUEUE) on %s failed in comm_handle" - , ifp->rname)); - break; - } - else if (packet_len == sizeof(buffer)) - { - plog("MSG_ERRQUEUE message longer than %lu bytes; truncated" - , (unsigned long) sizeof(buffer)); - } - else - { - sender = find_sender((size_t) packet_len, buffer); - } - - DBG_cond_dump(DBG_ALL, "rejected packet:\n", buffer, packet_len); - DBG_cond_dump(DBG_ALL, "control:\n", emh.msg_control, emh.msg_controllen); - /* ??? Andi Kleen <ak@suse.de> and misc documentation - * suggests that name will have the original destination - * of the packet. We seem to see msg_namelen == 0. - * Andi says that this is a kernel bug and has fixed it. - * Perhaps in 2.2.18/2.4.0. - */ - passert(emh.msg_name == &from.sa); - DBG_cond_dump(DBG_ALL, "name:\n", emh.msg_name - , emh.msg_namelen); - - fromstr[0] = '\0'; /* usual case :-( */ - switch (from.sa.sa_family) - { - char as[INET6_ADDRSTRLEN]; - - case AF_INET: - if (emh.msg_namelen == sizeof(struct sockaddr_in)) - snprintf(fromstr, sizeof(fromstr) - , " for message to %s port %u" - , inet_ntop(from.sa.sa_family - , &from.sa_in4.sin_addr, as, sizeof(as)) - , ntohs(from.sa_in4.sin_port)); - break; - case AF_INET6: - if (emh.msg_namelen == sizeof(struct sockaddr_in6)) - snprintf(fromstr, sizeof(fromstr) - , " for message to %s port %u" - , inet_ntop(from.sa.sa_family - , &from.sa_in6.sin6_addr, as, sizeof(as)) - , ntohs(from.sa_in6.sin6_port)); - break; - } - - for (cm = CMSG_FIRSTHDR(&emh) - ; cm != NULL - ; cm = CMSG_NXTHDR(&emh,cm)) - { - if (cm->cmsg_level == SOL_IP - && cm->cmsg_type == IP_RECVERR) - { - /* ip(7) and recvmsg(2) specify: - * ee_origin is SO_EE_ORIGIN_ICMP for ICMP - * or SO_EE_ORIGIN_LOCAL for locally generated errors. - * ee_type and ee_code are from the ICMP header. - * ee_info is the discovered MTU for EMSGSIZE errors - * ee_data is not used. - * - * ??? recvmsg(2) says "SOCK_EE_OFFENDER" but - * means "SO_EE_OFFENDER". The OFFENDER is really - * the router that complained. As such, the port - * is meaningless. - */ - - /* ??? cmsg(3) claims that CMSG_DATA returns - * void *, but RFC 2292 and /usr/include/bits/socket.h - * say unsigned char *. The manual is being fixed. - */ - struct sock_extended_err *ee = (void *)CMSG_DATA(cm); - const char *offstr = "unspecified"; - char offstrspace[INET6_ADDRSTRLEN]; - char orname[50]; - - if (cm->cmsg_len > CMSG_LEN(sizeof(struct sock_extended_err))) - { - const struct sockaddr *offender = SO_EE_OFFENDER(ee); - - switch (offender->sa_family) - { - case AF_INET: - offstr = inet_ntop(offender->sa_family - , &((const struct sockaddr_in *)offender)->sin_addr - , offstrspace, sizeof(offstrspace)); - break; - case AF_INET6: - offstr = inet_ntop(offender->sa_family - , &((const struct sockaddr_in6 *)offender)->sin6_addr - , offstrspace, sizeof(offstrspace)); - break; - default: - offstr = "unknown"; - break; - } - } - - switch (ee->ee_origin) - { - case SO_EE_ORIGIN_NONE: - snprintf(orname, sizeof(orname), "none"); - break; - case SO_EE_ORIGIN_LOCAL: - snprintf(orname, sizeof(orname), "local"); - break; - case SO_EE_ORIGIN_ICMP: - snprintf(orname, sizeof(orname) - , "ICMP type %d code %d (not authenticated)" - , ee->ee_type, ee->ee_code - ); - break; - case SO_EE_ORIGIN_ICMP6: - snprintf(orname, sizeof(orname) - , "ICMP6 type %d code %d (not authenticated)" - , ee->ee_type, ee->ee_code - ); - break; - default: - snprintf(orname, sizeof(orname), "invalid origin %lu" - , (unsigned long) ee->ee_origin); - break; - } - - { - struct state *old_state = cur_state; - - cur_state = sender; - - /* note dirty trick to suppress ~ at start of format - * if we know what state to blame. - */ - if ((packet_len == 1) && (buffer[0] == 0xff) -#ifdef DEBUG - && ((cur_debugging & DBG_NATT) == 0) -#endif - ) { - /* don't log NAT-T keepalive related errors unless NATT debug is - * enabled - */ - } - else - plog((sender != NULL) + "~" - "ERROR: asynchronous network error report on %s" - "%s" - ", complainant %s" - ": %s" - " [errno %lu, origin %s" - /* ", pad %d, info %ld" */ - /* ", data %ld" */ - "]" - , ifp->rname - , fromstr - , offstr - , strerror(ee->ee_errno) - , (unsigned long) ee->ee_errno - , orname - /* , ee->ee_pad, (unsigned long)ee->ee_info */ - /* , (unsigned long)ee->ee_data */ - ); - cur_state = old_state; - } - } - else - { - /* .cmsg_len is a kernel_size_t(!), but the value - * certainly ought to fit in an unsigned long. - */ - plog("unknown cmsg: level %d, type %d, len %lu" - , cm->cmsg_level, cm->cmsg_type - , (unsigned long) cm->cmsg_len); - } - } - } - return (pfd.revents & interest) != 0; -} -#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */ - -bool -send_packet(struct state *st, const char *where) -{ - connection_t *c = st->st_connection; - int port_buf; - bool err; - u_int8_t ike_pkt[MAX_OUTPUT_UDP_SIZE]; - u_int8_t *ptr; - unsigned long len; - - if (c->interface->ike_float && st->st_tpacket.len != 1) - { - if ((unsigned long) st->st_tpacket.len > (MAX_OUTPUT_UDP_SIZE-sizeof(u_int32_t))) - { - DBG_log("send_packet(): really too big"); - return FALSE; - } - ptr = ike_pkt; - /** Add Non-ESP marker **/ - memset(ike_pkt, 0, sizeof(u_int32_t)); - memcpy(ike_pkt + sizeof(u_int32_t), st->st_tpacket.ptr, - (unsigned long)st->st_tpacket.len); - len = (unsigned long) st->st_tpacket.len + sizeof(u_int32_t); - } - else - { - ptr = st->st_tpacket.ptr; - len = (unsigned long) st->st_tpacket.len; - } - - DBG(DBG_RAW, - { - DBG_log("sending %lu bytes for %s through %s to %s:%u:" - , (unsigned long) st->st_tpacket.len - , where - , c->interface->rname - , ip_str(&c->spd.that.host_addr) - , (unsigned)c->spd.that.host_port); - DBG_dump_chunk(NULL, st->st_tpacket); - }); - - /* XXX: Not very clean. We manipulate the port of the ip_address to - * have a port in the sockaddr*, but we retain the original port - * and restore it afterwards. - */ - - port_buf = portof(&c->spd.that.host_addr); - setportof(htons(c->spd.that.host_port), &c->spd.that.host_addr); - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) - (void) check_msg_errqueue(c->interface, POLLOUT); -#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */ - - err = sendto(c->interface->fd - , ptr, len, 0 - , sockaddrof(&c->spd.that.host_addr) - , sockaddrlenof(&c->spd.that.host_addr)) != (ssize_t)len; - - /* restore port */ - setportof(port_buf, &c->spd.that.host_addr); - - if (err) - { - /* do not log NAT-T Keep Alive packets */ - if (streq(where, "NAT-T Keep Alive")) - return FALSE; - log_errno((e, "sendto on %s to %s:%u failed in %s" - , c->interface->rname - , ip_str(&c->spd.that.host_addr) - , (unsigned)c->spd.that.host_port - , where)); - return FALSE; - } - else - { - return TRUE; - } -} - -static stf_status -unexpected(struct msg_digest *md) -{ - loglog(RC_LOG_SERIOUS, "unexpected message received in state %s" - , enum_name(&state_names, md->st->st_state)); - return STF_IGNORE; -} - -static stf_status -informational(struct msg_digest *md UNUSED) -{ - struct payload_digest *const n_pld = md->chain[ISAKMP_NEXT_N]; - - /* If the Notification Payload is not null... */ - if (n_pld != NULL) - { - pb_stream *const n_pbs = &n_pld->pbs; - struct isakmp_notification *const n = &n_pld->payload.notification; - int disp_len; - char disp_buf[200]; - - /* Switch on Notification Type (enum) */ - switch (n->isan_type) - { - case R_U_THERE: - return dpd_inI_outR(md->st, n, n_pbs); - - case R_U_THERE_ACK: - return dpd_inR(md->st, n, n_pbs); - default: - if (pbs_left(n_pbs) >= sizeof(disp_buf)-1) - disp_len = sizeof(disp_buf)-1; - else - disp_len = pbs_left(n_pbs); - memcpy(disp_buf, n_pbs->cur, disp_len); - disp_buf[disp_len] = '\0'; - break; - } - } - return STF_IGNORE; -} - -/* message digest allocation and deallocation */ - -static struct msg_digest *md_pool = NULL; - -/* free_md_pool is only used to avoid leak reports */ -void -free_md_pool(void) -{ - for (;;) - { - struct msg_digest *md = md_pool; - - if (md == NULL) - break; - md_pool = md->next; - free(md); - } -} - -static struct msg_digest * -malloc_md(void) -{ - struct msg_digest *md = md_pool; - - /* convenient initializer: - * - all pointers NULL - * - .note = NOTHING_WRONG - * - .encrypted = FALSE - */ - static const struct msg_digest blank_md = { - .next = NULL, - }; - - if (md == NULL) - { - md = malloc_thing(struct msg_digest); - zero(md); - } - else - md_pool = md->next; - - *md = blank_md; - md->digest_roof = md->digest; - - /* note: although there may be multiple msg_digests at once - * (due to suspended state transitions), there is a single - * global reply_buffer. It will need to be saved and restored. - */ - init_pbs(&md->reply, reply_buffer, sizeof(reply_buffer), "reply packet"); - - return md; -} - -void -release_md(struct msg_digest *md) -{ - chunk_free(&md->raw_packet); - free(md->packet_pbs.start); - md->packet_pbs.start = NULL; - md->next = md_pool; - md_pool = md; -} - -/* wrapper for read_packet and process_packet - * - * The main purpose of this wrapper is to factor out teardown code - * from the many return points in process_packet. This amounts to - * releasing the msg_digest and resetting global variables. - * - * When processing of a packet is suspended (STF_SUSPEND), - * process_packet sets md to NULL to prevent the msg_digest being freed. - * Someone else must ensure that msg_digest is freed eventually. - * - * read_packet is broken out to minimize the lifetime of the - * enormous input packet buffer, an auto. - */ -void -comm_handle(const struct iface *ifp) -{ - static struct msg_digest *md; - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) - /* Even though select(2) says that there is a message, - * it might only be a MSG_ERRQUEUE message. At least - * sometimes that leads to a hanging recvfrom. To avoid - * what appears to be a kernel bug, check_msg_errqueue - * uses poll(2) and tells us if there is anything for us - * to read. - * - * This is early enough that teardown isn't required: - * just return on failure. - */ - if (!check_msg_errqueue(ifp, POLLIN)) - return; /* no normal message to read */ -#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */ - - md = malloc_md(); - md->iface = ifp; - - if (read_packet(md)) - process_packet(&md); - - if (md != NULL) - release_md(md); - - cur_state = NULL; - reset_cur_connection(); - cur_from = NULL; -} - -/* read the message. - * Since we don't know its size, we read it into - * an overly large buffer and then copy it to a - * new, properly sized buffer. - */ -static bool -read_packet(struct msg_digest *md) -{ - const struct iface *ifp = md->iface; - int packet_len; - u_int8_t *buffer; - u_int8_t *buffer_nat; - union - { - struct sockaddr sa; - struct sockaddr_in sa_in4; - struct sockaddr_in6 sa_in6; - } from; - int from_len = sizeof(from); - err_t from_ugh = NULL; - static const char undisclosed[] = "unknown source"; - - happy(anyaddr(addrtypeof(&ifp->addr), &md->sender)); - zero(&from.sa); - ioctl(ifp->fd, FIONREAD, &packet_len); - buffer = malloc(packet_len); - packet_len = recvfrom(ifp->fd, buffer, packet_len, 0 - , &from.sa, &from_len); - - /* First: digest the from address. - * We presume that nothing here disturbs errno. - */ - if (packet_len == -1 - && from_len == sizeof(from) - && all_zero((const void *)&from.sa, sizeof(from))) - { - /* "from" is untouched -- not set by recvfrom */ - from_ugh = undisclosed; - } - else if (from_len - < (int) (offsetof(struct sockaddr, sa_family) + sizeof(from.sa.sa_family))) - { - from_ugh = "truncated"; - } - else - { - const struct af_info *afi = aftoinfo(from.sa.sa_family); - - if (afi == NULL) - { - from_ugh = "unexpected Address Family"; - } - else if (from_len != (int)afi->sa_sz) - { - from_ugh = "wrong length"; - } - else - { - switch (from.sa.sa_family) - { - case AF_INET: - from_ugh = initaddr((void *) &from.sa_in4.sin_addr - , sizeof(from.sa_in4.sin_addr), AF_INET, &md->sender); - md->sender_port = ntohs(from.sa_in4.sin_port); - break; - case AF_INET6: - from_ugh = initaddr((void *) &from.sa_in6.sin6_addr - , sizeof(from.sa_in6.sin6_addr), AF_INET6, &md->sender); - md->sender_port = ntohs(from.sa_in6.sin6_port); - break; - } - } - } - - /* now we report any actual I/O error */ - if (packet_len == -1) - { - if (from_ugh == undisclosed - && errno == ECONNREFUSED) - { - /* Tone down scary message for vague event: - * We get "connection refused" in response to some - * datagram we sent, but we cannot tell which one. - */ - plog("some IKE message we sent has been rejected with ECONNREFUSED (kernel supplied no details)"); - } - else if (from_ugh != NULL) - { - log_errno((e, "recvfrom on %s failed; Pluto cannot decode source sockaddr in rejection: %s" - , ifp->rname, from_ugh)); - } - else - { - log_errno((e, "recvfrom on %s from %s:%u failed" - , ifp->rname - , ip_str(&md->sender), (unsigned)md->sender_port)); - } - free(buffer); - return FALSE; - } - else if (from_ugh != NULL) - { - plog("recvfrom on %s returned malformed source sockaddr: %s" - , ifp->rname, from_ugh); - free(buffer); - return FALSE; - } - cur_from = &md->sender; - cur_from_port = md->sender_port; - - if (ifp->ike_float == TRUE) - { - u_int32_t non_esp; - - if (packet_len < (int)sizeof(u_int32_t)) - { - plog("recvfrom %s:%u too small packet (%d)" - , ip_str(cur_from), (unsigned) cur_from_port, packet_len); - free(buffer); - return FALSE; - } - memcpy(&non_esp, buffer, sizeof(u_int32_t)); - if (non_esp != 0) - { - plog("recvfrom %s:%u has no Non-ESP marker" - , ip_str(cur_from), (unsigned) cur_from_port); - free(buffer); - return FALSE; - } - packet_len -= sizeof(u_int32_t); - buffer_nat = malloc(packet_len); - memcpy(buffer_nat, buffer + sizeof(u_int32_t), packet_len); - free(buffer); - buffer = buffer_nat; - } - - /* Clone actual message contents - * and set up md->packet_pbs to describe it. - */ - init_pbs(&md->packet_pbs, buffer, packet_len, "packet"); - - DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL, - { - DBG_log(BLANK_FORMAT); - DBG_log("*received %d bytes from %s:%u on %s" - , (int) pbs_room(&md->packet_pbs) - , ip_str(cur_from), (unsigned) cur_from_port - , ifp->rname); - }); - - DBG(DBG_RAW, - DBG_dump("", md->packet_pbs.start, pbs_room(&md->packet_pbs))); - - if ((pbs_room(&md->packet_pbs)==1) && (md->packet_pbs.start[0]==0xff)) - { - /** - * NAT-T Keep-alive packets should be discarded by kernel ESPinUDP - * layer. But bogus keep-alive packets (sent with a non-esp marker) - * can reach this point. Complain and discard them. - */ - DBG(DBG_NATT, - DBG_log("NAT-T keep-alive (bogus ?) should not reach this point. " - "Ignored. Sender: %s:%u", ip_str(cur_from), - (unsigned) cur_from_port); - ) - return FALSE; - } - -#define IKEV2_VERSION_OFFSET 17 -#define IKEV2_VERSION 0x20 - - /* ignore IKEv2 packets - they will be handled by charon */ - if (pbs_room(&md->packet_pbs) > IKEV2_VERSION_OFFSET - && (md->packet_pbs.start[IKEV2_VERSION_OFFSET] & 0xF0) == IKEV2_VERSION) - { - DBG(DBG_CONTROLMORE, - DBG_log(" ignoring IKEv2 packet") - ) - return FALSE; - } - - return TRUE; -} - -/* process an input packet, possibly generating a reply. - * - * If all goes well, this routine eventually calls a state-specific - * transition function. - */ -static void -process_packet(struct msg_digest **mdp) -{ - struct msg_digest *md = *mdp; - const struct state_microcode *smc; - bool new_iv_set = FALSE; - bool restore_iv = FALSE; - u_char new_iv[MAX_DIGEST_LEN]; - u_int new_iv_len = 0; - - struct state *st = NULL; - enum state_kind from_state = STATE_UNDEFINED; /* state we started in */ - -#define SEND_NOTIFICATION(t) { \ - if (st) send_notification_from_state(st, from_state, t); \ - else send_notification_from_md(md, t); } - - if (!in_struct(&md->hdr, &isakmp_hdr_desc, &md->packet_pbs, &md->message_pbs)) - { - /* Identify specific failures: - * - bad ISAKMP major/minor version numbers - */ - if (md->packet_pbs.roof - md->packet_pbs.cur >= (ptrdiff_t)isakmp_hdr_desc.size) - { - struct isakmp_hdr *hdr = (struct isakmp_hdr *)md->packet_pbs.cur; - if ((hdr->isa_version >> ISA_MAJ_SHIFT) != ISAKMP_MAJOR_VERSION) - { - SEND_NOTIFICATION(ISAKMP_INVALID_MAJOR_VERSION); - return; - } - else if ((hdr->isa_version & ISA_MIN_MASK) != ISAKMP_MINOR_VERSION) - { - SEND_NOTIFICATION(ISAKMP_INVALID_MINOR_VERSION); - return; - } - } - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - if (md->packet_pbs.roof != md->message_pbs.roof) - { - plog("size (%u) differs from size specified in ISAKMP HDR (%u)" - , (unsigned) pbs_room(&md->packet_pbs), md->hdr.isa_length); -#ifdef CISCO_QUIRKS - if (pbs_room(&md->packet_pbs) - md->hdr.isa_length == 16) - plog("Cisco VPN client appends 16 surplus NULL bytes"); - else -#endif - return; - } - - switch (md->hdr.isa_xchg) - { -#ifdef NOTYET - case ISAKMP_XCHG_NONE: - case ISAKMP_XCHG_BASE: -#endif - - case ISAKMP_XCHG_IDPROT: /* part of a Main Mode exchange */ - if (md->hdr.isa_msgid != MAINMODE_MSGID) - { - plog("Message ID was 0x%08lx but should be zero in Main Mode", - (unsigned long) md->hdr.isa_msgid); - SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); - return; - } - - if (is_zero_cookie(md->hdr.isa_icookie)) - { - plog("Initiator Cookie must not be zero in Main Mode message"); - SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); - return; - } - - if (is_zero_cookie(md->hdr.isa_rcookie)) - { - /* initial message from initiator - * ??? what if this is a duplicate of another message? - */ - if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION) - { - plog("initial Main Mode message is invalid:" - " its Encrypted Flag is on"); - SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); - return; - } - - /* don't build a state until the message looks tasty */ - from_state = STATE_MAIN_R0; - } - else - { - /* not an initial message */ - - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - /* perhaps this is a first message from the responder - * and contains a responder cookie that we've not yet seen. - */ - st = find_state(md->hdr.isa_icookie, zero_cookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - plog("Main Mode message is part of an unknown exchange"); - /* XXX Could send notification back */ - return; - } - } - set_cur_state(st); - from_state = st->st_state; - } - break; - -#ifdef NOTYET - case ISAKMP_XCHG_AO: - case ISAKMP_XCHG_AGGR: -#endif - - case ISAKMP_XCHG_INFO: /* an informational exchange */ - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, MAINMODE_MSGID); - - if (st != NULL) - set_cur_state(st); - - if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION) - { - if (st == NULL) - { - plog("Informational Exchange is for an unknown (expired?) SA"); - /* XXX Could send notification back */ - return; - } - - if (!IS_ISAKMP_ENCRYPTED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "encrypted Informational Exchange message is invalid" - " because no key is known"); - /* XXX Could send notification back */ - return; - } - - if (md->hdr.isa_msgid == MAINMODE_MSGID) - { - loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because" - " it has a Message ID of 0"); - /* XXX Could send notification back */ - return; - } - - if (!reserve_msgid(st, md->hdr.isa_msgid)) - { - loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because" - " it has a previously used Message ID (0x%08lx)" - , (unsigned long)md->hdr.isa_msgid); - /* XXX Could send notification back */ - return; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - memcpy(st->st_ph1_iv, st->st_new_iv, st->st_new_iv_len); - st->st_ph1_iv_len = st->st_new_iv_len; - - /* backup new_iv */ - new_iv_len = st->st_new_iv_len; - passert(new_iv_len <= MAX_DIGEST_LEN) - memcpy(new_iv, st->st_new_iv, new_iv_len); - restore_iv = TRUE; - } - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - - from_state = STATE_INFO_PROTECTED; - } - else - { - if (st != NULL && IS_ISAKMP_ENCRYPTED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "Informational Exchange message" - " must be encrypted"); - /* XXX Could send notification back */ - return; - } - from_state = STATE_INFO; - } - break; - - case ISAKMP_XCHG_QUICK: /* part of a Quick Mode exchange */ - if (is_zero_cookie(md->hdr.isa_icookie)) - { - plog("Quick Mode message is invalid because" - " it has an Initiator Cookie of 0"); - SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); - return; - } - - if (is_zero_cookie(md->hdr.isa_rcookie)) - { - plog("Quick Mode message is invalid because" - " it has a Responder Cookie of 0"); - SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); - return; - } - - if (md->hdr.isa_msgid == MAINMODE_MSGID) - { - plog("Quick Mode message is invalid because" - " it has a Message ID of 0"); - SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); - return; - } - - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - /* No appropriate Quick Mode state. - * See if we have a Main Mode state. - * ??? what if this is a duplicate of another message? - */ - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, MAINMODE_MSGID); - - if (st == NULL) - { - plog("Quick Mode message is for a non-existent (expired?)" - " ISAKMP SA"); - /* XXX Could send notification back */ - return; - } - - set_cur_state(st); - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "Quick Mode message is unacceptable because" - " it is for an incomplete ISAKMP SA"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED /* XXX ? */); - return; - } - - /* only accept this new Quick Mode exchange if it has a unique message ID */ - if (!reserve_msgid(st, md->hdr.isa_msgid)) - { - loglog(RC_LOG_SERIOUS, "Quick Mode I1 message is unacceptable because" - " it uses a previously used Message ID 0x%08lx" - " (perhaps this is a duplicated packet)" - , (unsigned long) md->hdr.isa_msgid); - SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); - return; - } - - /* Quick Mode Initial IV */ - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - - from_state = STATE_QUICK_R0; - } - else - { - set_cur_state(st); - from_state = st->st_state; - } - - break; - - case ISAKMP_XCHG_MODE_CFG: - if (is_zero_cookie(md->hdr.isa_icookie)) - { - plog("ModeCfg message is invalid because" - " it has an Initiator Cookie of 0"); - /* XXX Could send notification back */ - return; - } - - if (is_zero_cookie(md->hdr.isa_rcookie)) - { - plog("ModeCfg message is invalid because" - " it has a Responder Cookie of 0"); - /* XXX Could send notification back */ - return; - } - - if (md->hdr.isa_msgid == 0) - { - plog("ModeCfg message is invalid because" - " it has a Message ID of 0"); - /* XXX Could send notification back */ - return; - } - - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - bool has_xauth_policy; - - /* No appropriate ModeCfg state. - * See if we have a Main Mode state. - * ??? what if this is a duplicate of another message? - */ - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, 0); - - if (st == NULL) - { - plog("ModeCfg message is for a non-existent (expired?)" - " ISAKMP SA"); - /* XXX Could send notification back */ - return; - } - - set_cur_state(st); - - /* the XAUTH_STATUS message might have a new msgid */ - if (st->st_state == STATE_XAUTH_I1) - { - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - from_state = st->st_state; - break; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "ModeCfg message is unacceptable because" - " it is for an incomplete ISAKMP SA (state=%s)" - , enum_name(&state_names, st->st_state)); - /* XXX Could send notification back */ - return; - } - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - - /* - * okay, now we have to figure out if we are receiving a bogus - * new message in an outstanding XAUTH server conversation - * (i.e. a reply to our challenge) - * (this occurs with some broken other implementations). - * - * or if receiving for the first time, an XAUTH challenge. - * - * or if we are getting a MODECFG request. - * - * we distinguish these states because we can not both be an - * XAUTH server and client, and our policy tells us which - * one we are. - * - * to complicate further, it is normal to start a new msgid - * when going from one state to another, or when restarting - * the challenge. - * - */ - - has_xauth_policy = (st->st_connection->policy - & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK)) - != LEMPTY; - - if (has_xauth_policy && !st->st_xauth.started - && IS_PHASE1(st->st_state)) - { - from_state = STATE_XAUTH_I0; - } - else if (st->st_connection->spd.that.modecfg - && IS_PHASE1(st->st_state)) - { - from_state = STATE_MODE_CFG_R0; - } - else if (st->st_connection->spd.this.modecfg - && IS_PHASE1(st->st_state)) - { - from_state = STATE_MODE_CFG_I0; - } - else - { - /* XXX check if we are being a mode config server here */ - plog("received ModeCfg message when in state %s, and we aren't mode config client" - , enum_name(&state_names, st->st_state)); - return; - } - } - else - { - set_cur_state(st); - from_state = st->st_state; - } - break; - -#ifdef NOTYET - case ISAKMP_XCHG_NGRP: - case ISAKMP_XCHG_ACK_INFO: -#endif - - default: - plog("unsupported exchange type %s in message" - , enum_show(&exchange_names, md->hdr.isa_xchg)); - SEND_NOTIFICATION(ISAKMP_UNSUPPORTED_EXCHANGE_TYPE); - return; - } - - /* We have found a from_state, and perhaps a state object. - * If we need to build a new state object, - * we wait until the packet has been sanity checked. - */ - - /* We don't support the Commit Flag. It is such a bad feature. - * It isn't protected -- neither encrypted nor authenticated. - * A man in the middle turns it on, leading to DoS. - * We just ignore it, with a warning. - * By placing the check here, we could easily add a policy bit - * to a connection to suppress the warning. This might be useful - * because the Commit Flag is expected from some peers. - */ - if (md->hdr.isa_flags & ISAKMP_FLAG_COMMIT) - { - plog("IKE message has the Commit Flag set but Pluto doesn't implement this feature; ignoring flag"); - } - - /* Set smc to describe this state's properties. - * Look up the appropriate microcode based on state and - * possibly Oakley Auth type. - */ - passert(STATE_IKE_FLOOR <= from_state && from_state < STATE_IKE_ROOF); - smc = ike_microcode_index[from_state - STATE_IKE_FLOOR]; - - if (st != NULL) - { - u_int16_t auth; - - switch (st->st_oakley.auth) - { - case XAUTHInitPreShared: - case XAUTHRespPreShared: - auth = OAKLEY_PRESHARED_KEY; - break; - case XAUTHInitRSA: - case XAUTHRespRSA: - auth = OAKLEY_RSA_SIG; - break; - default: - auth = st->st_oakley.auth; - } - - while (!LHAS(smc->flags, auth)) - { - smc++; - passert(smc->state == from_state); - } - } - - /* Ignore a packet if the state has a suspended state transition - * Probably a duplicated packet but the original packet is not yet - * recorded in st->st_rpacket, so duplicate checking won't catch. - * ??? Should the packet be recorded earlier to improve diagnosis? - */ - if (st != NULL && st->st_suspended_md != NULL) - { - loglog(RC_LOG, "discarding packet received during DNS lookup in %s" - , enum_name(&state_names, st->st_state)); - return; - } - - /* Detect and handle duplicated packets. - * This won't work for the initial packet of an exchange - * because we won't have a state object to remember it. - * If we are in a non-receiving state (terminal), and the preceding - * state did transmit, then the duplicate may indicate that that - * transmission wasn't received -- retransmit it. - * Otherwise, just discard it. - * ??? Notification packets are like exchanges -- I hope that - * they are idempotent! - */ - if (st != NULL - && st->st_rpacket.ptr != NULL - && st->st_rpacket.len == pbs_room(&md->packet_pbs) - && memeq(st->st_rpacket.ptr, md->packet_pbs.start, st->st_rpacket.len)) - { - if (smc->flags & SMF_RETRANSMIT_ON_DUPLICATE) - { - if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS) - { - st->st_retransmit++; - loglog(RC_RETRANSMISSION - , "retransmitting in response to duplicate packet; already %s" - , enum_name(&state_names, st->st_state)); - send_packet(st, "retransmit in response to duplicate"); - } - else - { - loglog(RC_LOG_SERIOUS, "discarding duplicate packet -- exhausted retransmission; already %s" - , enum_name(&state_names, st->st_state)); - } - } - else - { - loglog(RC_LOG_SERIOUS, "discarding duplicate packet; already %s" - , enum_name(&state_names, st->st_state)); - } - return; - } - - if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION) - { - DBG(DBG_CRYPT, DBG_log("received encrypted packet from %s:%u" - , ip_str(&md->sender), (unsigned)md->sender_port)); - - if (st == NULL) - { - plog("discarding encrypted message for an unknown ISAKMP SA"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED /* XXX ? */); - return; - } - if (st->st_skeyid_e.ptr == (u_char *) NULL) - { - loglog(RC_LOG_SERIOUS, "discarding encrypted message" - " because we haven't yet negotiated keying materiel"); - SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); - return; - } - - /* Mark as encrypted */ - md->encrypted = TRUE; - - DBG(DBG_CRYPT, DBG_log("decrypting %u bytes using algorithm %s" - , (unsigned) pbs_left(&md->message_pbs) - , enum_show(&oakley_enc_names, st->st_oakley.encrypt))); - - /* do the specified decryption - * - * IV is from st->st_iv or (if new_iv_set) st->st_new_iv. - * The new IV is placed in st->st_new_iv - * - * See RFC 2409 "IKE" Appendix B - * - * XXX The IV should only be updated really if the packet - * is successfully processed. - * We should keep this value, check for a success return - * value from the parsing routines and then replace. - * - * Each post phase 1 exchange generates IVs from - * the last phase 1 block, not the last block sent. - */ - { - size_t crypter_block_size, crypter_iv_size; - encryption_algorithm_t enc_alg; - crypter_t *crypter; - chunk_t data, iv; - char *new_iv; - - enc_alg = oakley_to_encryption_algorithm(st->st_oakley.encrypt); - crypter = lib->crypto->create_crypter(lib->crypto, enc_alg, st->st_enc_key.len); - crypter_block_size = crypter->get_block_size(crypter); - crypter_iv_size = crypter->get_iv_size(crypter); - - if (pbs_left(&md->message_pbs) % crypter_block_size != 0) - { - loglog(RC_LOG_SERIOUS, "malformed message: not a multiple of encryption blocksize"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - /* XXX Detect weak keys */ - - /* grab a copy of raw packet (for duplicate packet detection) */ - md->raw_packet = chunk_create(md->packet_pbs.start, pbs_room(&md->packet_pbs)); - md->raw_packet = chunk_clone(md->raw_packet); - - data = chunk_create(md->message_pbs.cur, pbs_left(&md->message_pbs)); - - /* Decrypt everything after header */ - if (!new_iv_set) - { - /* use old IV */ - passert(st->st_iv_len <= sizeof(st->st_new_iv)); - st->st_new_iv_len = st->st_iv_len; - memcpy(st->st_new_iv, st->st_iv, st->st_new_iv_len); - } - - /* form iv by truncation */ - st->st_new_iv_len = crypter_iv_size; - iv = chunk_create(st->st_new_iv, st->st_new_iv_len); - new_iv = alloca(crypter_iv_size); - memcpy(new_iv, data.ptr + data.len - crypter_iv_size, - crypter_iv_size); - - crypter->set_key(crypter, st->st_enc_key); - crypter->decrypt(crypter, data, iv, NULL); - crypter->destroy(crypter); - - memcpy(st->st_new_iv, new_iv, crypter_iv_size); - if (restore_iv) - { - memcpy(st->st_new_iv, new_iv, new_iv_len); - st->st_new_iv_len = new_iv_len; - } - } - - DBG_cond_dump(DBG_CRYPT, "decrypted:\n", md->message_pbs.cur - , md->message_pbs.roof - md->message_pbs.cur); - - DBG_cond_dump(DBG_CRYPT, "next IV:" - , st->st_new_iv, st->st_new_iv_len); - } - else - { - /* packet was not encryped -- should it have been? */ - - if (smc->flags & SMF_INPUT_ENCRYPTED) - { - loglog(RC_LOG_SERIOUS, "packet rejected: should have been encrypted"); - SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); - return; - } - } - - /* Digest the message. - * Padding must be removed to make hashing work. - * Padding comes from encryption (so this code must be after decryption). - * Padding rules are described before the definition of - * struct isakmp_hdr in packet.h. - */ - { - struct payload_digest *pd = md->digest; - int np = md->hdr.isa_np; - lset_t needed = smc->req_payloads; - const char *excuse - = LIN(SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT, smc->flags) - ? "probable authentication failure (mismatch of preshared secrets?): " - : ""; - - while (np != ISAKMP_NEXT_NONE) - { - struct_desc *sd = np < ISAKMP_NEXT_ROOF? payload_descs[np] : NULL; - - if (pd == &md->digest[PAYLIMIT]) - { - loglog(RC_LOG_SERIOUS, "more than %d payloads in message; ignored", PAYLIMIT); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - switch (np) - { - case ISAKMP_NEXT_NATD_RFC: - case ISAKMP_NEXT_NATOA_RFC: - if (!st || !(st->nat_traversal & NAT_T_WITH_RFC_VALUES)) - { - /* - * don't accept NAT-D/NAT-OA reloc directly in message, unless - * we're using NAT-T RFC - */ - sd = NULL; - } - break; - } - - if (sd == NULL) - { - /* payload type is out of range or requires special handling */ - switch (np) - { - case ISAKMP_NEXT_ID: - sd = IS_PHASE1(from_state) - ? &isakmp_identification_desc : &isakmp_ipsec_identification_desc; - break; - case ISAKMP_NEXT_NATD_DRAFTS: - np = ISAKMP_NEXT_NATD_RFC; /* NAT-D relocated */ - sd = payload_descs[np]; - break; - case ISAKMP_NEXT_NATOA_DRAFTS: - np = ISAKMP_NEXT_NATOA_RFC; /* NAT-OA relocated */ - sd = payload_descs[np]; - break; - default: - loglog(RC_LOG_SERIOUS, "%smessage ignored because it contains an unknown or" - " unexpected payload type (%s) at the outermost level" - , excuse, enum_show(&payload_names, np)); - SEND_NOTIFICATION(ISAKMP_INVALID_PAYLOAD_TYPE); - return; - } - } - - { - lset_t s = LELEM(np); - - if (LDISJOINT(s - , needed | smc->opt_payloads| LELEM(ISAKMP_NEXT_N) | LELEM(ISAKMP_NEXT_D))) - { - loglog(RC_LOG_SERIOUS, "%smessage ignored because it " - "contains an unexpected payload type (%s)" - , excuse, enum_show(&payload_names, np)); - SEND_NOTIFICATION(ISAKMP_INVALID_PAYLOAD_TYPE); - return; - } - needed &= ~s; - } - - if (!in_struct(&pd->payload, sd, &md->message_pbs, &pd->pbs)) - { - loglog(RC_LOG_SERIOUS, "%smalformed payload in packet", excuse); - if (md->hdr.isa_xchg != ISAKMP_XCHG_INFO) - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - /* place this payload at the end of the chain for this type */ - { - struct payload_digest **p; - - for (p = &md->chain[np]; *p != NULL; p = &(*p)->next) - ; - *p = pd; - pd->next = NULL; - } - - np = pd->payload.generic.isag_np; - pd++; - - /* since we've digested one payload happily, it is probably - * the case that any decryption worked. So we will not suggest - * encryption failure as an excuse for subsequent payload - * problems. - */ - excuse = ""; - } - - md->digest_roof = pd; - - DBG(DBG_PARSING, - if (pbs_left(&md->message_pbs) != 0) - DBG_log("removing %d bytes of padding", (int) pbs_left(&md->message_pbs))); - - md->message_pbs.roof = md->message_pbs.cur; - - /* check that all mandatory payloads appeared */ - - if (needed != 0) - { - loglog(RC_LOG_SERIOUS, "message for %s is missing payloads %s" - , enum_show(&state_names, from_state) - , bitnamesof(payload_name, needed)); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - - /* more sanity checking: enforce most ordering constraints */ - - if (IS_PHASE1(from_state)) - { - /* rfc2409: The Internet Key Exchange (IKE), 5 Exchanges: - * "The SA payload MUST precede all other payloads in a phase 1 exchange." - */ - if (md->chain[ISAKMP_NEXT_SA] != NULL - && md->hdr.isa_np != ISAKMP_NEXT_SA) - { - loglog(RC_LOG_SERIOUS, "malformed Phase 1 message: does not start with an SA payload"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - else if (IS_QUICK(from_state)) - { - /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode - * - * "In Quick Mode, a HASH payload MUST immediately follow the ISAKMP - * header and a SA payload MUST immediately follow the HASH." - * [NOTE: there may be more than one SA payload, so this is not - * totally reasonable. Probably all SAs should be so constrained.] - * - * "If ISAKMP is acting as a client negotiator on behalf of another - * party, the identities of the parties MUST be passed as IDci and - * then IDcr." - * - * "With the exception of the HASH, SA, and the optional ID payloads, - * there are no payload ordering restrictions on Quick Mode." - */ - - if (md->hdr.isa_np != ISAKMP_NEXT_HASH) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: does not start with a HASH payload"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - { - struct payload_digest *p; - int i; - - for (p = md->chain[ISAKMP_NEXT_SA], i = 1; p != NULL - ; p = p->next, i++) - { - if (p != &md->digest[i]) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: SA payload is in wrong position"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - } - - /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode: - * "If ISAKMP is acting as a client negotiator on behalf of another - * party, the identities of the parties MUST be passed as IDci and - * then IDcr." - */ - { - struct payload_digest *id = md->chain[ISAKMP_NEXT_ID]; - - if (id != NULL) - { - if (id->next == NULL || id->next->next != NULL) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:" - " if any ID payload is present," - " there must be exactly two"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - if (id+1 != id->next) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:" - " the ID payloads are not adjacent"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - } - } - - /* Ignore payloads that we don't handle: - * Delete, Notification, VendorID - */ - /* XXX Handle deletions */ - /* XXX Handle Notifications */ - /* XXX Handle VID payloads */ - { - struct payload_digest *p; - - for (p = md->chain[ISAKMP_NEXT_N]; p != NULL; p = p->next) - { - if (p->payload.notification.isan_type != R_U_THERE - && p->payload.notification.isan_type != R_U_THERE_ACK) - { - loglog(RC_LOG_SERIOUS, "ignoring informational payload, type %s" - , enum_show(¬ification_names, p->payload.notification.isan_type)); - } - DBG_cond_dump(DBG_PARSING, "info:", p->pbs.cur, pbs_left(&p->pbs)); - } - - for (p = md->chain[ISAKMP_NEXT_D]; p != NULL; p = p->next) - { - accept_delete(st, md, p); - DBG_cond_dump(DBG_PARSING, "del:", p->pbs.cur, pbs_left(&p->pbs)); - } - - for (p = md->chain[ISAKMP_NEXT_VID]; p != NULL; p = p->next) - { - handle_vendorid(md, p->pbs.cur, pbs_left(&p->pbs)); - } - } - md->from_state = from_state; - md->smc = smc; - md->st = st; - - /* possibly fill in hdr */ - if (smc->first_out_payload != ISAKMP_NEXT_NONE) - echo_hdr(md, (smc->flags & SMF_OUTPUT_ENCRYPTED) != 0 - , smc->first_out_payload); - - complete_state_transition(mdp, smc->processor(md)); -} - -/* complete job started by the state-specific state transition function */ - -void -complete_state_transition(struct msg_digest **mdp, stf_status result) -{ - bool has_xauth_policy; - bool is_xauth_server; - struct msg_digest *md = *mdp; - const struct state_microcode *smc = md->smc; - enum state_kind from_state = md->from_state; - struct state *st; - - cur_state = st = md->st; /* might have changed */ - - /* If state has DPD support, import it */ - if (st && md->dpd) - st->st_dpd = TRUE; - - switch (result) - { - case STF_IGNORE: - break; - - case STF_SUSPEND: - /* the stf didn't complete its job: don't relase md */ - *mdp = NULL; - break; - - case STF_OK: - /* advance the state */ - st->st_state = smc->next_state; - - /* Delete previous retransmission event. - * New event will be scheduled below. - */ - delete_event(st); - - /* replace previous receive packet with latest */ - - free(st->st_rpacket.ptr); - - if (md->encrypted) - { - /* if encrypted, duplication already done */ - st->st_rpacket = md->raw_packet; - md->raw_packet.ptr = NULL; - } - else - { - st->st_rpacket = chunk_create(md->packet_pbs.start, - pbs_room(&md->packet_pbs)); - st->st_rpacket = chunk_clone(st->st_rpacket); - } - - /* free previous transmit packet */ - chunk_free(&st->st_tpacket); - - /* if requested, send the new reply packet */ - if (smc->flags & SMF_REPLY) - { - close_output_pbs(&md->reply); /* good form, but actually a no-op */ - - st->st_tpacket = chunk_create(md->reply.start, pbs_offset(&md->reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - if (nat_traversal_enabled) - nat_traversal_change_port_lookup(md, md->st); - - /* actually send the packet - * Note: this is a great place to implement "impairments" - * for testing purposes. Suppress or duplicate the - * send_packet call depending on st->st_state. - */ - send_packet(st, enum_name(&state_names, from_state)); - } - - /* Schedule for whatever timeout is specified */ - { - time_t delay = UNDEFINED_TIME; - enum event_type kind = smc->timeout_event; - bool agreed_time = FALSE; - connection_t *c = st->st_connection; - - switch (kind) - { - case EVENT_RETRANSMIT: /* Retransmit packet */ - delay = EVENT_RETRANSMIT_DELAY_0; - break; - - case EVENT_SA_REPLACE: /* SA replacement event */ - if (IS_PHASE1(st->st_state)) - { - /* Note: we will defer to the "negotiated" (dictated) - * lifetime if we are POLICY_DONT_REKEY. - * This allows the other side to dictate - * a time we would not otherwise accept - * but it prevents us from having to initiate - * rekeying. The negative consequences seem - * minor. - */ - delay = c->sa_ike_life_seconds; - if ((c->policy & POLICY_DONT_REKEY) - || delay >= st->st_oakley.life_seconds) - { - agreed_time = TRUE; - delay = st->st_oakley.life_seconds; - } - } - else - { - /* Delay is min of up to four things: - * each can limit the lifetime. - */ - delay = c->sa_ipsec_life_seconds; - if (st->st_ah.present - && delay >= st->st_ah.attrs.life_seconds) - { - agreed_time = TRUE; - delay = st->st_ah.attrs.life_seconds; - } - if (st->st_esp.present - && delay >= st->st_esp.attrs.life_seconds) - { - agreed_time = TRUE; - delay = st->st_esp.attrs.life_seconds; - } - if (st->st_ipcomp.present - && delay >= st->st_ipcomp.attrs.life_seconds) - { - agreed_time = TRUE; - delay = st->st_ipcomp.attrs.life_seconds; - } - } - - /* By default, we plan to rekey. - * - * If there isn't enough time to rekey, plan to - * expire. - * - * If we are --dontrekey, a lot more rules apply. - * If we are the Initiator, use REPLACE_IF_USED. - * If we are the Responder, and the dictated time - * was unacceptable (too large), plan to REPLACE - * (the only way to ratchet down the time). - * If we are the Responder, and the dictated time - * is acceptable, plan to EXPIRE. - * - * Important policy lies buried here. - * For example, we favour the initiator over the - * responder by making the initiator start rekeying - * sooner. Also, fuzz is only added to the - * initiator's margin. - * - * Note: for ISAKMP SA, we let the negotiated - * time stand (implemented by earlier logic). - */ - if (agreed_time - && (c->policy & POLICY_DONT_REKEY)) - { - kind = (smc->flags & SMF_INITIATOR) - ? EVENT_SA_REPLACE_IF_USED - : EVENT_SA_EXPIRE; - } - if (kind != EVENT_SA_EXPIRE) - { - unsigned long marg = c->sa_rekey_margin; - - if (smc->flags & SMF_INITIATOR) - marg += marg - * c->sa_rekey_fuzz / 100.E0 - * (rand() / (RAND_MAX + 1.E0)); - else - marg /= 2; - - if ((unsigned long)delay > marg) - { - delay -= marg; - st->st_margin = marg; - } - else - { - kind = EVENT_SA_EXPIRE; - } - } - break; - - case EVENT_NULL: /* non-event */ - case EVENT_REINIT_SECRET: /* Refresh cookie secret */ - default: - bad_case(kind); - } - event_schedule(kind, delay, st); - } - - /* tell whack and log of progress */ - { - const char *story = state_story[st->st_state]; - enum rc_type w = RC_NEW_STATE + st->st_state; - char sadetails[128]; - - sadetails[0]='\0'; - - if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - char *b = sadetails; - const char *ini = " {"; - const char *fin = ""; - - /* -1 is to leave space for "fin" */ - - if (st->st_esp.present) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sESP=>0x%08x <0x%08x" - , ini - , ntohl(st->st_esp.attrs.spi) - , ntohl(st->st_esp.our_spi)); - ini = " "; - fin = "}"; - } - /* advance b to end of string */ - b = b + strlen(b); - - if (st->st_ah.present) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sAH=>0x%08x <0x%08x" - , ini - , ntohl(st->st_ah.attrs.spi) - , ntohl(st->st_ah.our_spi)); - ini = " "; - fin = "}"; - } - /* advance b to end of string */ - b = b + strlen(b); - - if (st->st_ipcomp.present) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sIPCOMP=>0x%08x <0x%08x" - , ini - , ntohl(st->st_ipcomp.attrs.spi) - , ntohl(st->st_ipcomp.our_spi)); - ini = " "; - fin = "}"; - } - /* advance b to end of string */ - b = b + strlen(b); - - if (st->nat_traversal) - { - char oa[ADDRTOT_BUF]; - addrtot(&st->nat_oa, 0, oa, sizeof(oa)); - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sNATOA=%s" - , ini, oa); - ini = " "; - fin = "}"; - } - - /* advance b to end of string */ - b = b + strlen(b); - - if (st->st_dpd) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sDPD" - , ini); - ini = " "; - fin = "}"; - } - - strcat(b, fin); - } - - if (IS_ISAKMP_SA_ESTABLISHED(st->st_state) - || IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - /* log our success */ - plog("%s%s", story, sadetails); - w = RC_SUCCESS; - } - - /* tell whack our progress */ - whack_log(w - , "%s: %s%s" - , enum_name(&state_names, st->st_state) - , story, sadetails); - } - - has_xauth_policy = (st->st_connection->policy - & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK)) - != LEMPTY; - is_xauth_server = (st->st_connection->policy - & POLICY_XAUTH_SERVER) - != LEMPTY; - - /* Should we start XAUTH as a server */ - if (has_xauth_policy && is_xauth_server - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_xauth.started) - { - DBG(DBG_CONTROL, - DBG_log("starting XAUTH server") - ) - xauth_send_request(st); - break; - } - - /* Wait for XAUTH request from server */ - if (has_xauth_policy && !is_xauth_server - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_xauth.started) - { - DBG(DBG_CONTROL, - DBG_log("waiting for XAUTH request from server") - ) - break; - } - - /* Should we start ModeConfig as a client? */ - if (st->st_connection->spd.this.modecfg - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !(st->st_connection->policy & POLICY_MODECFG_PUSH) - && !st->st_modecfg.started) - { - DBG(DBG_CONTROL, - DBG_log("starting ModeCfg client in pull mode") - ) - modecfg_send_request(st); - break; - } - - /* Should we start ModeConfig as a server? */ - if (st->st_connection->spd.that.modecfg - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_modecfg.started - && (st->st_connection->policy & POLICY_MODECFG_PUSH)) - { - DBG(DBG_CONTROL, - DBG_log("starting ModeCfg server in push mode") - ) - modecfg_send_set(st); - break; - } - - /* Wait for ModeConfig set from server */ - if (st->st_connection->spd.this.modecfg - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_modecfg.vars_set) - { - DBG(DBG_CONTROL, - DBG_log("waiting for ModeCfg set from server") - ) - break; - } - - if (smc->flags & SMF_RELEASE_PENDING_P2) - { - /* Initiate any Quick Mode negotiations that - * were waiting to piggyback on this Keying Channel. - * - * ??? there is a potential race condition - * if we are the responder: the initial Phase 2 - * message might outrun the final Phase 1 message. - * I think that retransmission will recover. - */ - unpend(st); - } - - if (IS_ISAKMP_SA_ESTABLISHED(st->st_state) - || IS_IPSEC_SA_ESTABLISHED(st->st_state)) - release_whack(st); - break; - - case STF_INTERNAL_ERROR: - whack_log(RC_INTERNALERR + md->note - , "%s: internal error" - , enum_name(&state_names, st->st_state)); - - DBG(DBG_CONTROL, - DBG_log("state transition function for %s had internal error" - , enum_name(&state_names, from_state))); - break; - - default: /* a shortcut to STF_FAIL, setting md->note */ - passert(result > STF_FAIL); - md->note = result - STF_FAIL; - result = STF_FAIL; - /* FALL THROUGH ... */ - case STF_FAIL: - /* As it is, we act as if this message never happened: - * whatever retrying was in place, remains in place. - */ - whack_log(RC_NOTIFICATION + md->note - , "%s: %s" - , enum_name(&state_names, (st == NULL)? STATE_MAIN_R0:st->st_state) - , enum_name(¬ification_names, md->note)); - - SEND_NOTIFICATION(md->note); - - DBG(DBG_CONTROL, - DBG_log("state transition function for %s failed: %s" - , enum_name(&state_names, from_state) - , enum_name(¬ification_names, md->note))); - break; - } -} diff --git a/src/pluto/demux.h b/src/pluto/demux.h deleted file mode 100644 index 6ce53c14f..000000000 --- a/src/pluto/demux.h +++ /dev/null @@ -1,97 +0,0 @@ -/* demultiplex incoming IKE messages - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _DEMUX_H -#define _DEMUX_H - -#include "packet.h" -#include "state.h" - -extern void init_demux(void); -extern bool send_packet(struct state *st, const char *where); -extern void comm_handle(const struct iface *ifp); - -extern u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE]; - -/* State transition function infrastructure - * - * com_handle parses a message, decides what state object it applies to, - * and calls the appropriate state transition function (STF). - * These declarations define the interface to these functions. - * - * Each STF must be able to be restarted up to any failure point: - * a later message will cause the state to be re-entered. This - * explains the use of the replace macro and the care in handling - * MP_INT members of struct state. - */ - -struct payload_digest { - pb_stream pbs; - union payload payload; - struct payload_digest *next; /* of same kind */ -}; - -/* message digest - * Note: raw_packet and packet_pbs are "owners" of space on heap. - */ - -struct msg_digest { - struct msg_digest *next; /* for free list */ - chunk_t raw_packet; /* if encrypted, received packet before decryption */ - const struct iface *iface; /* interface on which message arrived */ - ip_address sender; /* where message came from */ - u_int16_t sender_port; /* host order */ - pb_stream packet_pbs; /* whole packet */ - pb_stream message_pbs; /* message to be processed */ - struct isakmp_hdr hdr; /* message's header */ - bool encrypted; /* was it encrypted? */ - enum state_kind from_state; /* state we started in */ - const struct state_microcode *smc; /* microcode for initial state */ - struct state *st; /* current state object */ - pb_stream reply; /* room for reply */ - pb_stream rbody; /* room for reply body (after header) */ - notification_t note; /* reason for failure */ - bool dpd; /* peer supports RFC 3706 DPD */ - bool openpgp; /* peer supports OpenPGP certificates */ - bool ms_nt5; /* peer is a windows 2000+ host */ - -# define PAYLIMIT 40 - struct payload_digest - digest[PAYLIMIT], - *digest_roof, - *chain[ISAKMP_NEXT_ROOF]; - unsigned short nat_traversal_vid; -}; - -extern void release_md(struct msg_digest *md); - -/* status for state-transition-function - * Note: STF_FAIL + notification_t means fail with that notification - */ - -typedef enum { - STF_IGNORE, /* don't respond */ - STF_SUSPEND, /* unfinished -- don't release resources */ - STF_OK, /* success */ - STF_INTERNAL_ERROR, /* discard everything, we failed */ - STF_FAIL /* discard everything, something failed. notification_t added. */ -} stf_status; - -typedef stf_status state_transition_fn(struct msg_digest *md); - -extern void complete_state_transition(struct msg_digest **mdp, stf_status result); - -extern void free_md_pool(void); - -#endif /* _DEMUX_H */ diff --git a/src/pluto/dnskey.c b/src/pluto/dnskey.c deleted file mode 100644 index 91b1b6ac1..000000000 --- a/src/pluto/dnskey.c +++ /dev/null @@ -1,1590 +0,0 @@ -/* Find public key in DNS - * Copyright (C) 2000-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <resolv.h> -#include <netdb.h> /* ??? for h_errno */ -#include <sys/queue.h> - -#include <freeswan.h> - -#include <utils/identification.h> -#include <credentials/keys/public_key.h> - -#include "constants.h" -#include "adns.h" /* needs <resolv.h> */ -#include "defs.h" -#include "log.h" -#include "myid.h" -#include "connections.h" -#include "keys.h" /* needs connections.h */ -#include "dnskey.h" -#include "packet.h" -#include "timer.h" - -/* somebody has to decide */ -#define MAX_TXT_RDATA ((MAX_KEY_BYTES * 8 / 6) + 40) /* somewhat arbitrary overkill */ - -/* ADNS stuff */ - -int adns_qfd = NULL_FD, /* file descriptor for sending queries to adns (O_NONBLOCK) */ - adns_afd = NULL_FD; /* file descriptor for receiving answers from adns */ -static pid_t adns_pid = 0; -const char *pluto_adns_option = NULL; /* path from --pluto_adns */ - -int adns_restart_count; -#define ADNS_RESTART_MAX 20 - -void -init_adns(void) -{ - const char *adns_path = pluto_adns_option; - static const char adns_name[] = "_pluto_adns"; - const char *helper_bin_dir = getenv("IPSEC_LIBDIR"); - char adns_path_space[4096]; /* plenty long? */ - int qfds[2]; - int afds[2]; - - /* find a pathname to the ADNS program */ - if (adns_path == NULL) - { - /* pathname was not specified as an option: build it. - * First, figure out the directory to be used. - */ - ssize_t n; - - if (helper_bin_dir != NULL) - { - n = strlen(helper_bin_dir); - if ((size_t)n <= sizeof(adns_path_space) - sizeof(adns_name)) - { - strcpy(adns_path_space, helper_bin_dir); - if (n > 0 && adns_path_space[n -1] != '/') - { - adns_path_space[n++] = '/'; - } - } - } - else - { - /* The program will be in the same directory as Pluto, - * so we use the sympolic link /proc/self/exe to - * tell us of the path prefix. - */ - n = readlink("/proc/self/exe", adns_path_space, sizeof(adns_path_space)); - - if (n < 0) - { - exit_log_errno((e - , "readlink(\"/proc/self/exe\") failed in init_adns()")); - } - } - - if ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name)) - { - exit_log("path to %s is too long", adns_name); - } - - while (n > 0 && adns_path_space[n - 1] != '/') - { - n--; - } - strcpy(adns_path_space + n, adns_name); - adns_path = adns_path_space; - } - if (access(adns_path, X_OK) < 0) - { - exit_log_errno((e, "%s missing or not executable", adns_path)); - } - - if (pipe(qfds) != 0 || pipe(afds) != 0) - { - exit_log_errno((e, "pipe(2) failed in init_adns()")); - } - - adns_pid = fork(); - switch (adns_pid) - { - case -1: - exit_log_errno((e, "fork() failed in init_adns()")); - - case 0: - /* child */ - { - /* Make stdin and stdout our pipes. - * Take care to handle case where pipes already use these fds. - */ - if (afds[1] == 0) - { - afds[1] = dup(afds[1]); /* avoid being overwritten */ - } - if (qfds[0] != 0) - { - dup2(qfds[0], 0); - close(qfds[0]); - } - if (afds[1] != 1) - { - dup2(afds[1], 1); - close(qfds[1]); - } - if (afds[0] > 1) - { - close(afds[0]); - } - if (afds[1] > 1) - { - close(afds[1]); - } - DBG(DBG_DNS, execlp(adns_path, adns_name, "-d", NULL)); - - execlp(adns_path, adns_name, NULL); - exit_log_errno((e, "execlp of %s failed", adns_path)); - } - default: - /* parent */ - close(qfds[0]); - adns_qfd = qfds[1]; - adns_afd = afds[0]; - close(afds[1]); - fcntl(adns_qfd, F_SETFD, FD_CLOEXEC); - fcntl(adns_afd, F_SETFD, FD_CLOEXEC); - fcntl(adns_qfd, F_SETFL, O_NONBLOCK); - break; - } -} - -void -stop_adns(void) -{ - close_any(adns_qfd); - adns_qfd = NULL_FD; - close_any(adns_afd); - adns_afd = NULL_FD; - - if (adns_pid != 0) - { - int status; - pid_t p = waitpid(adns_pid, &status, 0); - - if (p == -1) - { - log_errno((e, "waitpid for ADNS process failed")); - } - else if (WIFEXITED(status)) - { - if (WEXITSTATUS(status) != 0) - { - plog("ADNS process exited with status %d" - , (int) WEXITSTATUS(status)); - } - } - else if (WIFSIGNALED(status)) - { - plog("ADNS process terminated by signal %d", (int)WTERMSIG(status)); - } - else - { - plog("wait for end of ADNS process returned odd status 0x%x\n" - , status); - } - } -} - - - -/* tricky macro to pass any hot potato */ -#define TRY(x) { err_t ugh = x; if (ugh != NULL) return ugh; } - - -/* Process TXT X-IPsec-Server record, accumulating relevant ones - * in cr->gateways_from_dns, a list sorted by "preference". - * - * Format of TXT record body: X-IPsec-Server ( nnn ) = iii kkk - * nnn is a 16-bit unsigned integer preference - * iii is @FQDN or dotted-decimal IPv4 address or colon-hex IPv6 address - * kkk is an optional RSA public signing key in base 64. - * - * NOTE: we've got to be very wary of anything we find -- bad guys - * might have prepared it. - */ - -#define our_TXT_attr_string "X-IPsec-Server" -static const char our_TXT_attr[] = our_TXT_attr_string; - -identification_t* decode_iii(u_char **pp) -{ - identification_t *gw_id; - u_char *p = *pp + strspn(*pp, " \t"); - u_char *e = p + strcspn(p, " \t"); - u_char under = *e; - - if (p == e) - { - return NULL; - } - *e = '\0'; - gw_id = identification_create_from_string(p); - *e = under; - *pp = e + strspn(e, " \t"); - - return gw_id; -} - -static err_t process_txt_rr_body(u_char *str, bool doit, - enum dns_auth_level dns_auth_level, - struct adns_continuation *const cr) -{ - identification_t *client_id = cr->id; /* subject of query */ - u_char *p = str; - unsigned long pref = 0; - struct gw_info gi; - - p += strspn(p, " \t"); /* ignore leading whitespace */ - - /* is this for us? */ - if (strncasecmp(p, our_TXT_attr, sizeof(our_TXT_attr)-1) != 0) - { - return NULL; /* neither interesting nor bad */ - } - - p += sizeof(our_TXT_attr) - 1; /* ignore our attribute name */ - p += strspn(p, " \t"); /* ignore leading whitespace */ - - /* decode '(' nnn ')' */ - if (*p != '(') - { - return "X-IPsec-Server missing '('"; - } - - { - char *e; - - p++; - pref = strtoul(p, &e, 0); - if ((u_char *)e == p) - { - return "malformed X-IPsec-Server priority"; - } - p = e + strspn(e, " \t"); - - if (*p != ')') - { - return "X-IPsec-Server priority missing ')'"; - } - p++; - p += strspn(p, " \t"); - - if (pref > 0xFFFF) - { - return "X-IPsec-Server priority larger than 0xFFFF"; - } - } - - /* time for '=' */ - - if (*p != '=') - { - return "X-IPsec-Server priority missing '='"; - } - p++; - p += strspn(p, " \t"); - - /* Decode iii (Security Gateway ID). */ - zero(&gi); /* before first use */ - - gi.gw_id = decode_iii(&p); - if (gi.gw_id == NULL) - { - return "TXT " our_TXT_attr_string " badly formed (no gateway specified)"; - } - - if (!cr->sgw_specified) - { - /* we don't know the peer's ID (because we are initiating - * and we don't know who to initiate with. - * So we're looking for gateway specs with an IP address - */ - if (gi.gw_id->get_type(gi.gw_id) != ID_IPV4_ADDR && - gi.gw_id->get_type(gi.gw_id) != ID_IPV6_ADDR) - { - DBG(DBG_DNS, - DBG_log("TXT %s record for '%Y': security gateway '%Y';" - " ignored because gateway's IP is unspecified", - our_TXT_attr, client_id, gi.gw_id); - ) - return NULL; /* we cannot use this record, but it isn't wrong */ - } - } - else - { - /* We do know the peer's ID (because we are responding) - * So we're looking for gateway specs specifying this known ID. - */ - identification_t *peer_id = cr->sgw_id; - - if (!peer_id->equals(peer_id, gi.gw_id)) - { - DBG(DBG_DNS, - DBG_log("TXT %s record for '%Y': security gateway '%Y';" - " ignored -- looking to confirm '%Y' as gateway", - our_TXT_attr, client_id, gi.gw_id, peer_id); - ) - return NULL; /* we cannot use this record, but it isn't wrong */ - } - } - - if (doit) - { - /* really accept gateway */ - struct gw_info **gwip; /* gateway insertion point */ - - gi.client_id = client_id; /* will need to unshare_id_content */ - - /* decode optional kkk: base 64 encoding of key */ - - gi.gw_key_present = *p != '\0'; - if (gi.gw_key_present) - { - /* Decode base 64 encoding of key. - * Similar code is in process_lwdnsq_key. - */ - u_char buf[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */ - size_t sz; - err_t ugh; - chunk_t rfc3110_chunk; - public_key_t *key; - - ugh = ttodatav(p, 0, 64, buf, sizeof(buf), &sz, - diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); - if (ugh) - { - return builddiag("malformed key data: %s", ugh); - } - if (sz > sizeof(buf)) - { - return builddiag("key data larger than %lu bytes", - (unsigned long) sizeof(buf)); - } - rfc3110_chunk = chunk_create(buf, sz); - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, - BUILD_BLOB_DNSKEY, rfc3110_chunk, - BUILD_END); - if (key == NULL) - { - return builddiag("invalid key data"); - } - - /* now find a key entry to put it in */ - gi.key = public_key_from_rsa(key); - - unreference_key(&cr->last_info); - cr->last_info = reference_key(gi.key); - } - - /* we're home free! Allocate everything and add to gateways list. */ - gi.refcnt = 1; - gi.pref = pref; - gi.key->dns_auth_level = dns_auth_level; - gi.key->last_tried_time = gi.key->last_worked_time = NO_TIME; - - /* find insertion point */ - for (gwip = &cr->gateways_from_dns; *gwip != NULL && (*gwip)->pref < pref; gwip = &(*gwip)->next) - ; - - DBG(DBG_DNS, - { - chunk_t keyid; - public_key_t *key = gi.key->public_key; - - if (gi.gw_key_present && - key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &keyid)) - { - DBG_log("gateway for %s is %s with key %#B", - client_id, gi.gw_id, &keyid); - } - else - { - DBG_log("gateway for '%Y' is '%Y'; no key specified", - client_id, gi.gw_id); - } - }); - - gi.next = *gwip; - *gwip = clone_thing(gi); - (*gwip)->gw_id = (*gwip)->gw_id->clone((*gwip)->gw_id); - (*gwip)->client_id = (*gwip)->client_id->clone((*gwip)->client_id); - } - - return NULL; -} - -static const char * -rr_typename(int type) -{ - switch (type) - { - case T_TXT: - return "TXT"; - case T_KEY: - return "KEY"; - default: - return "???"; - } -} - - -/* structure of Query Reply (RFC 1035 4.1.1): - * - * +---------------------+ - * | Header | - * +---------------------+ - * | Question | the question for the name server - * +---------------------+ - * | Answer | RRs answering the question - * +---------------------+ - * | Authority | RRs pointing toward an authority - * +---------------------+ - * | Additional | RRs holding additional information - * +---------------------+ - */ - -/* Header section format (as modified by RFC 2535 6.1): - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ID | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QDCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ANCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | NSCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ARCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ -struct qr_header { - u_int16_t id; /* 16-bit identifier to match query */ - - u_int16_t stuff; /* packed crud: */ - -#define QRS_QR 0x8000 /* QR: on if this is a response */ - -#define QRS_OPCODE_SHIFT 11 /* OPCODE field */ -#define QRS_OPCODE_MASK 0xF -#define QRSO_QUERY 0 /* standard query */ -#define QRSO_IQUERY 1 /* inverse query */ -#define QRSO_STATUS 2 /* server status request query */ - -#define QRS_AA 0x0400 /* AA: on if Authoritative Answer */ -#define QRS_TC 0x0200 /* TC: on if truncation happened */ -#define QRS_RD 0x0100 /* RD: on if recursion desired */ -#define QRS_RA 0x0080 /* RA: on if recursion available */ -#define QRS_Z 0x0040 /* Z: reserved; must be zero */ -#define QRS_AD 0x0020 /* AD: on if authentic data (RFC 2535) */ -#define QRS_CD 0x0010 /* AD: on if checking disabled (RFC 2535) */ - -#define QRS_RCODE_SHIFT 0 /* RCODE field: response code */ -#define QRS_RCODE_MASK 0xF -#define QRSR_OK 0 - - - u_int16_t qdcount; /* number of entries in question section */ - u_int16_t ancount; /* number of resource records in answer section */ - u_int16_t nscount; /* number of name server resource records in authority section */ - u_int16_t arcount; /* number of resource records in additional records section */ -}; - -static field_desc qr_header_fields[] = { - { ft_nat, 16/BITS_PER_BYTE, "ID", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "stuff", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "QD Count", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Answer Count", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Authority Count", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Additional Count", NULL }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc qr_header_desc = { - "Query Response Header", - qr_header_fields, - sizeof(struct qr_header) -}; - -/* Messages for codes in RCODE (see RFC 1035 4.1.1) */ -static const err_t rcode_text[QRS_RCODE_MASK + 1] = { - NULL, /* not an error */ - "Format error - The name server was unable to interpret the query", - "Server failure - The name server was unable to process this query" - " due to a problem with the name server", - "Name Error - Meaningful only for responses from an authoritative name" - " server, this code signifies that the domain name referenced in" - " the query does not exist", - "Not Implemented - The name server does not support the requested" - " kind of query", - "Refused - The name server refuses to perform the specified operation" - " for policy reasons", - /* the rest are reserved for future use */ - }; - -/* throw away a possibly compressed domain name */ - -static err_t -eat_name(pb_stream *pbs) -{ - u_char name_buf[NS_MAXDNAME + 2]; - u_char *ip = pbs->cur; - unsigned oi = 0; - unsigned jump_count = 0; - - for (;;) - { - u_int8_t b; - - if (ip >= pbs->roof) - return "ran out of message while skipping domain name"; - - b = *ip++; - if (jump_count == 0) - pbs->cur = ip; - - if (b == 0) - break; - - switch (b & 0xC0) - { - case 0x00: - /* we grab the next b characters */ - if (oi + b > NS_MAXDNAME) - return "domain name too long"; - - if (pbs->roof - ip <= b) - return "domain name falls off end of message"; - - if (oi != 0) - name_buf[oi++] = '.'; - - memcpy(name_buf + oi, ip, b); - oi += b; - ip += b; - if (jump_count == 0) - pbs->cur = ip; - break; - - case 0xC0: - { - unsigned ix; - - if (ip >= pbs->roof) - return "ran out of message in middle of compressed domain name"; - - ix = ((b & ~0xC0u) << 8) | *ip++; - if (jump_count == 0) - pbs->cur = ip; - - if (ix >= pbs_room(pbs)) - return "impossible compressed domain name"; - - /* Avoid infinite loop. - * There can be no more jumps than there are bytes - * in the packet. Not a tight limit, but good enough. - */ - jump_count++; - if (jump_count > pbs_room(pbs)) - return "loop in compressed domain name"; - - ip = pbs->start + ix; - } - break; - - default: - return "invalid code in label"; - } - } - - name_buf[oi++] = '\0'; - - DBG(DBG_DNS, DBG_log("skipping name %s", name_buf)); - - return NULL; -} - -static err_t -eat_name_helpfully(pb_stream *pbs, const char *context) -{ - err_t ugh = eat_name(pbs); - - return ugh == NULL? ugh - : builddiag("malformed name within DNS record of %s: %s", context, ugh); -} - -/* non-variable part of 4.1.2 Question Section entry: - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | | - * / QNAME / - * / / - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QTYPE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QCLASS | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ - -struct qs_fixed { - u_int16_t qtype; - u_int16_t qclass; -}; - -static field_desc qs_fixed_fields[] = { - { ft_loose_enum, 16/BITS_PER_BYTE, "QTYPE", &rr_qtype_names }, - { ft_loose_enum, 16/BITS_PER_BYTE, "QCLASS", &rr_class_names }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc qs_fixed_desc = { - "Question Section entry fixed part", - qs_fixed_fields, - sizeof(struct qs_fixed) -}; - -/* 4.1.3. Resource record format: - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | | - * / / - * / NAME / - * | | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | TYPE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | CLASS | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | TTL | - * | | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | RDLENGTH | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - * / RDATA / - * / / - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ - -struct rr_fixed { - u_int16_t type; - u_int16_t class; - u_int32_t ttl; /* actually signed */ - u_int16_t rdlength; -}; - - -static field_desc rr_fixed_fields[] = { - { ft_loose_enum, 16/BITS_PER_BYTE, "type", &rr_type_names }, - { ft_loose_enum, 16/BITS_PER_BYTE, "class", &rr_class_names }, - { ft_nat, 32/BITS_PER_BYTE, "TTL", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "RD length", NULL }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc rr_fixed_desc = { - "Resource Record fixed part", - rr_fixed_fields, - /* note: following is tricky: avoids padding problems */ - offsetof(struct rr_fixed, rdlength) + sizeof(u_int16_t) -}; - -/* RFC 1035 3.3.14: TXT RRs have text in the RDATA field. - * It is in the form of a sequence of <character-string>s as described in 3.3. - * unpack_txt_rdata() deals with this peculiar representation. - */ - -/* RFC 2535 3.1 KEY RDATA format: - * - * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | flags | protocol | algorithm | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | / - * / public key / - * / / - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-| - */ - -struct key_rdata { - u_int16_t flags; - u_int8_t protocol; - u_int8_t algorithm; -}; - -static field_desc key_rdata_fields[] = { - { ft_nat, 16/BITS_PER_BYTE, "flags", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "protocol", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "algorithm", NULL }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc key_rdata_desc = { - "KEY RR RData fixed part", - key_rdata_fields, - sizeof(struct key_rdata) -}; - -/* RFC 2535 4.1 SIG RDATA format: - * - * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | type covered | algorithm | labels | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | original TTL | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | signature expiration | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | signature inception | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | key tag | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ signer's name + - * | / - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-/ - * / / - * / signature / - * / / - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -struct sig_rdata { - u_int16_t type_covered; - u_int8_t algorithm; - u_int8_t labels; - u_int32_t original_ttl; - u_int32_t sig_expiration; - u_int32_t sig_inception; - u_int16_t key_tag; -}; - -static field_desc sig_rdata_fields[] = { - { ft_nat, 16/BITS_PER_BYTE, "type_covered", NULL}, - { ft_nat, 8/BITS_PER_BYTE, "algorithm", NULL}, - { ft_nat, 8/BITS_PER_BYTE, "labels", NULL}, - { ft_nat, 32/BITS_PER_BYTE, "original ttl", NULL}, - { ft_nat, 32/BITS_PER_BYTE, "sig expiration", NULL}, - { ft_nat, 32/BITS_PER_BYTE, "sig inception", NULL}, - { ft_nat, 16/BITS_PER_BYTE, "key tag", NULL}, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc sig_rdata_desc = { - "SIG RR RData fixed part", - sig_rdata_fields, - sizeof(struct sig_rdata) -}; - -/* handle a KEY Resource Record. */ - -#ifdef USE_KEYRR -static err_t -process_key_rr(u_char *ptr, size_t len -, bool doit /* should we capture information? */ -, enum dns_auth_level dns_auth_level -, struct adns_continuation *const cr) -{ - pb_stream pbs; - struct key_rdata kr; - - if (len < sizeof(struct key_rdata)) - return "KEY Resource Record's RD Length is too small"; - - init_pbs(&pbs, ptr, len, "KEY RR"); - - if (!in_struct(&kr, &key_rdata_desc, &pbs, NULL)) - return "failed to get fixed part of KEY Resource Record RDATA"; - - if (kr.protocol == 4 /* IPSEC (RFC 2535 3.1.3) */ - && kr.algorithm == 1 /* RSA/MD5 (RFC 2535 3.2) */ - && (kr.flags & 0x8000) == 0 /* use for authentication (3.1.2) */ - && (kr.flags & 0x2CF0) == 0) /* must be zero */ - { - /* we have what seems to be a tasty key */ - - if (doit) - { - chunk_t k = { pbs.cur, pbs_left(&pbs) }; - - TRY(add_public_key(&cr->id, dns_auth_level, PUBKEY_ALG_RSA, &k - , &cr->keys_from_dns)); - } - } - return NULL; -} -#endif /* USE_KEYRR */ - - -/* unpack TXT rr RDATA into C string. - * A sequence of <character-string>s as described in RFC 1035 3.3. - * We concatenate them. - */ -static err_t -unpack_txt_rdata(u_char *d, size_t dlen, const u_char *s, size_t slen) -{ - size_t i = 0 - , o = 0; - - while (i < slen) - { - size_t cl = s[i++]; - - if (i + cl > slen) - return "TXT rr RDATA representation malformed"; - - if (o + cl >= dlen) - return "TXT rr RDATA too large"; - - memcpy(d + o, s + i, cl); - i += cl; - o += cl; - } - d[o] = '\0'; - if (strlen(d) != o) - return "TXT rr RDATA contains a NUL"; - - return NULL; -} - -static err_t -process_txt_rr(u_char *rdata, size_t rdlen -, bool doit /* should we capture information? */ -, enum dns_auth_level dns_auth_level -, struct adns_continuation *const cr) -{ - u_char str[RSA_MAX_ENCODING_BYTES * 8 / 6 + 20]; /* space for unpacked RDATA */ - - TRY(unpack_txt_rdata(str, sizeof(str), rdata, rdlen)); - return process_txt_rr_body(str, doit, dns_auth_level, cr); -} - -static err_t -process_answer_section(pb_stream *pbs -, bool doit /* should we capture information? */ -, enum dns_auth_level *dns_auth_level -, u_int16_t ancount /* number of RRs in the answer section */ -, struct adns_continuation *const cr) -{ - const int type = cr->query.type; /* type of RR of interest */ - unsigned c; - - DBG(DBG_DNS, DBG_log("*Answer Section:")); - - for (c = 0; c != ancount; c++) - { - struct rr_fixed rrf; - size_t tail; - - /* ??? do we need to match the name? */ - - TRY(eat_name_helpfully(pbs, "Answer Section")); - - if (!in_struct(&rrf, &rr_fixed_desc, pbs, NULL)) - return "failed to get fixed part of Answer Section Resource Record"; - - if (rrf.rdlength > pbs_left(pbs)) - return "RD Length extends beyond end of message"; - - /* ??? should we care about ttl? */ - - tail = rrf.rdlength; - - if (rrf.type == type && rrf.class == C_IN) - { - err_t ugh = NULL; - - switch (type) - { -#ifdef USE_KEYRR - case T_KEY: - ugh = process_key_rr(pbs->cur, tail, doit, *dns_auth_level, cr); - break; -#endif /* USE_KEYRR */ - case T_TXT: - ugh = process_txt_rr(pbs->cur, tail, doit, *dns_auth_level, cr); - break; - case T_SIG: - /* Check if SIG RR authenticates what we are learning. - * The RRset covered by a SIG must have the same owner, - * class, and type. - * For us, the class is always C_IN, so that matches. - * We decode the SIG RR's fixed part to check - * that the type_covered field matches our query type - * (this may be redundant). - * We don't check the owner (apparently this is the - * name on the record) -- we assume that it matches - * or we would not have been given this SIG in the - * Answer Section. - * - * We only look on first pass, and only if we've something - * to learn. This cuts down on useless decoding. - */ - if (!doit && *dns_auth_level == DAL_UNSIGNED) - { - struct sig_rdata sr; - - if (!in_struct(&sr, &sig_rdata_desc, pbs, NULL)) - ugh = "failed to get fixed part of SIG Resource Record RDATA"; - else if (sr.type_covered == type) - *dns_auth_level = DAL_SIGNED; - } - break; - default: - ugh = builddiag("unexpected RR type %d", type); - break; - } - if (ugh != NULL) - return ugh; - } - in_raw(NULL, tail, pbs, "RR RDATA"); - } - - return doit - && cr->gateways_from_dns == NULL -#ifdef USE_KEYRR - && cr->keys_from_dns == NULL -#endif /* USE_KEYRR */ - ? builddiag("no suitable %s record found in DNS", rr_typename(type)) - : NULL; -} - -/* process DNS answer -- TXT or KEY query */ - -static err_t -process_dns_answer(struct adns_continuation *const cr -, u_char ans[], int anslen) -{ - const int type = cr->query.type; /* type of record being sought */ - int r; /* all-purpose return value holder */ - u_int16_t c; /* number of current RR in current answer section */ - pb_stream pbs; - u_int8_t *ans_start; /* saved position of answer section */ - struct qr_header qr_header; - enum dns_auth_level dns_auth_level; - - init_pbs(&pbs, ans, anslen, "Query Response Message"); - - /* decode and check header */ - - if (!in_struct(&qr_header, &qr_header_desc, &pbs, NULL)) - return "malformed header"; - - /* ID: nothing to do with us */ - - /* stuff -- lots of things */ - if ((qr_header.stuff & QRS_QR) == 0) - return "not a response?!?"; - - if (((qr_header.stuff >> QRS_OPCODE_SHIFT) & QRS_OPCODE_MASK) != QRSO_QUERY) - return "unexpected opcode"; - - /* I don't think we care about AA */ - - if (qr_header.stuff & QRS_TC) - return "response truncated"; - - /* I don't think we care about RD, RA, or CD */ - - /* AD means "authentic data" */ - dns_auth_level = qr_header.stuff & QRS_AD? DAL_UNSIGNED : DAL_NOTSEC; - - if (qr_header.stuff & QRS_Z) - return "Z bit is not zero"; - - r = (qr_header.stuff >> QRS_RCODE_SHIFT) & QRS_RCODE_MASK; - if (r != 0) - return r < (int)countof(rcode_text)? rcode_text[r] : "unknown rcode"; - - if (qr_header.ancount == 0) - return builddiag("no %s RR found by DNS", rr_typename(type)); - - /* end of header checking */ - - /* Question Section processing */ - - /* 4.1.2. Question section format: - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | | - * / QNAME / - * / / - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QTYPE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QCLASS | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ - - DBG(DBG_DNS, DBG_log("*Question Section:")); - - for (c = 0; c != qr_header.qdcount; c++) - { - struct qs_fixed qsf; - - TRY(eat_name_helpfully(&pbs, "Question Section")); - - if (!in_struct(&qsf, &qs_fixed_desc, &pbs, NULL)) - return "failed to get fixed part of Question Section"; - - if (qsf.qtype != type) - return "unexpected QTYPE in Question Section"; - - if (qsf.qclass != C_IN) - return "unexpected QCLASS in Question Section"; - } - - /* rest of sections are made up of Resource Records */ - - /* Answer Section processing -- error checking, noting T_SIG */ - - ans_start = pbs.cur; /* remember start of answer section */ - - TRY(process_answer_section(&pbs, FALSE, &dns_auth_level - , qr_header.ancount, cr)); - - /* Authority Section processing (just sanity checking) */ - - DBG(DBG_DNS, DBG_log("*Authority Section:")); - - for (c = 0; c != qr_header.nscount; c++) - { - struct rr_fixed rrf; - size_t tail; - - TRY(eat_name_helpfully(&pbs, "Authority Section")); - - if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL)) - return "failed to get fixed part of Authority Section Resource Record"; - - if (rrf.rdlength > pbs_left(&pbs)) - return "RD Length extends beyond end of message"; - - /* ??? should we care about ttl? */ - - tail = rrf.rdlength; - - in_raw(NULL, tail, &pbs, "RR RDATA"); - } - - /* Additional Section processing (just sanity checking) */ - - DBG(DBG_DNS, DBG_log("*Additional Section:")); - - for (c = 0; c != qr_header.arcount; c++) - { - struct rr_fixed rrf; - size_t tail; - - TRY(eat_name_helpfully(&pbs, "Additional Section")); - - if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL)) - return "failed to get fixed part of Additional Section Resource Record"; - - if (rrf.rdlength > pbs_left(&pbs)) - return "RD Length extends beyond end of message"; - - /* ??? should we care about ttl? */ - - tail = rrf.rdlength; - - in_raw(NULL, tail, &pbs, "RR RDATA"); - } - - /* done all sections */ - - /* ??? is padding legal, or can we complain if more left in record? */ - - /* process Answer Section again -- accept contents */ - - pbs.cur = ans_start; /* go back to start of answer section */ - - return process_answer_section(&pbs, TRUE, &dns_auth_level - , qr_header.ancount, cr); -} - -/****************************************************************/ - -static err_t build_dns_name(u_char name_buf[NS_MAXDNAME + 2], - unsigned long serial USED_BY_DEBUG, - identification_t *id, - const char *typename USED_BY_DEBUG, - identification_t *gw USED_BY_DEBUG) -{ - /* note: all end in "." to suppress relative searches */ - id = resolve_myid(id); - - switch (id->get_type(id)) - { - case ID_IPV4_ADDR: - { - chunk_t b = id->get_encoding(id); - - snprintf(name_buf, NS_MAXDNAME + 2, "%d.%d.%d.%d.in-addr.arpa.", - b.ptr[3], b.ptr[2], b.ptr[1], b.ptr[0]); - break; - } - case ID_IPV6_ADDR: - { - chunk_t b = id->get_encoding(id); - size_t bl; - u_char *op = name_buf; - static const char suffix[] = "IP6.INT."; - - for (bl = b.len; bl-- != 0; ) - { - if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1) - { - return "IPv6 reverse name too long"; - } - op += sprintf(op, "%x.%x.", b.ptr[bl] & 0xF, b.ptr[bl] >> 4); - } - strcpy(op, suffix); - break; - } - case ID_FQDN: - { - if (snprintf(name_buf, NS_MAXDNAME + 2, "%Y.", id) > NS_MAXDNAME + 1) - { - return "FQDN too long for domain name"; - } - break; - } - default: - return "can only query DNS for key for ID that is a FQDN, IPV4_ADDR, or IPV6_ADDR"; - } - - DBG(DBG_CONTROL | DBG_DNS, - DBG_log("DNS query %lu for %s for %s (gw: %Y)", serial, typename, name_buf, gw) - ) - return NULL; -} - -void gw_addref(struct gw_info *gw) -{ - if (gw != NULL) - { - DBG(DBG_DNS, DBG_log("gw_addref: %p refcnt: %d++", gw, gw->refcnt)) - gw->refcnt++; - } -} - -void gw_delref(struct gw_info **gwp) -{ - struct gw_info *gw = *gwp; - - if (gw != NULL) - { - DBG(DBG_DNS, DBG_log("gw_delref: %p refcnt: %d--", gw, gw->refcnt)); - - passert(gw->refcnt != 0); - gw->refcnt--; - if (gw->refcnt == 0) - { - DESTROY_IF(gw->client_id); - DESTROY_IF(gw->gw_id); - if (gw->gw_key_present) - { - unreference_key(&gw->key); - } - gw_delref(&gw->next); - free(gw); /* trickery could make this a tail-call */ - } - *gwp = NULL; - } -} - -static int adns_in_flight = 0; /* queries outstanding */ - -/* Start an asynchronous DNS query. - * - * For KEY record, the result will be a list in cr->keys_from_dns. - * For TXT records, the result will be a list in cr->gateways_from_dns. - * - * If sgw_id is null, only consider TXT records that specify an - * IP address for the gatway: we need this in the initiation case. - * - * If sgw_id is non-null, only consider TXT records that specify - * this id as the security gatway; this is useful to the Responder - * for confirming claims of gateways. - * - * Continuation cr gives information for continuing when the result shows up. - * - * Two kinds of errors must be handled: synchronous (immediate) - * and asynchronous. Synchronous errors are indicated by the returned - * value of start_adns_query; in this case, the continuation will - * have been freed and the continuation routine will not be called. - * Asynchronous errors are indicated by the ugh parameter passed to the - * continuation routine. - * - * After the continuation routine has completed, handle_adns_answer - * will free the continuation. The continuation routine should have - * freed any axiliary resources. - * - * Note: in the synchronous error case, start_adns_query will have - * freed the continuation; this means that the caller will have to - * be very careful to release any auxiliary resources that were in - * the continuation record without using the continuation record. - * - * Either there will be an error result passed to the continuation routine, - * or the results will be in cr->keys_from_dns or cr->gateways_from_dns. - * The result variables must by left NULL by the continutation routine. - * The continuation routine is responsible for establishing and - * disestablishing any logging context (whack_log_fd, cur_*). - */ - -static struct adns_continuation *continuations = NULL; /* newest of queue */ -static struct adns_continuation *next_query = NULL; /* oldest not sent */ - -static struct adns_continuation *continuation_for_qtid(unsigned long qtid) -{ - struct adns_continuation *cr = NULL; - - if (qtid != 0) - { - for (cr = continuations; cr != NULL && cr->qtid != qtid; cr = cr->previous) - ; - } - return cr; -} - -static void release_adns_continuation(struct adns_continuation *cr) -{ - passert(cr != next_query); - gw_delref(&cr->gateways_from_dns); -#ifdef USE_KEYRR - free_public_keys(&cr->keys_from_dns); -#endif /* USE_KEYRR */ - cr->id = cr->id->clone(cr->id); - cr->sgw_id = cr->sgw_id->clone(cr->sgw_id); - - /* unlink from doubly-linked list */ - if (cr->next == NULL) - { - continuations = cr->previous; - } - else - { - cr->next->previous = cr->previous; - } - - if (cr->previous != NULL) - { - cr->previous->next = cr->next; - } - - free(cr); -} - -err_t start_adns_query(identification_t *id, /* domain to query */ - identification_t *sgw_id, /* if non-null, any accepted gw_info must match */ - int type, /* T_TXT or T_KEY, selecting rr type of interest */ - cont_fn_t cont_fn, - struct adns_continuation *cr) -{ - static unsigned long qtid = 1; /* query transaction id; NOTE: static */ - const char *typename = rr_typename(type); - - if(adns_pid == 0 && adns_restart_count < ADNS_RESTART_MAX) - { - plog("ADNS helper was not running. Restarting attempt %d",adns_restart_count); - init_adns(); - } - - /* Splice this in at head of doubly-linked list of continuations. - * Note: this must be done before any release_adns_continuation(). - */ - cr->next = NULL; - cr->previous = continuations; - if (continuations != NULL) - { - continuations->next = cr; - } - continuations = cr; - - cr->qtid = qtid++; - cr->type = type; - cr->cont_fn = cont_fn; - cr->id = id->clone(id); - cr->sgw_specified = (sgw_id != NULL); - cr->sgw_id = cr->sgw_specified ? - sgw_id->clone(sgw_id) : - identification_create_from_string("%any"); - cr->gateways_from_dns = NULL; -#ifdef USE_KEYRR - cr->keys_from_dns = NULL; -#endif /* USE_KEYRR */ - -#ifdef DEBUG - cr->debugging = cur_debugging; -#else - cr->debugging = LEMPTY; -#endif - - zero(&cr->query); - { - err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid, id, - typename, cr->sgw_id); - - if (ugh) - { - release_adns_continuation(cr); - return ugh; - } - } - - if (next_query == NULL) - next_query = cr; - - unsent_ADNS_queries = TRUE; - - return NULL; -} - -/* send remaining ADNS queries (until pipe full or none left) - * - * This is a co-routine, so it uses static variables to - * preserve state across calls. - */ -bool unsent_ADNS_queries = FALSE; - -void -send_unsent_ADNS_queries(void) -{ - static const unsigned char *buf_end = NULL; /* NOTE STATIC */ - static const unsigned char *buf_cur = NULL; /* NOTE STATIC */ - - if (adns_qfd == NULL_FD) - return; /* nothing useful to do */ - - for (;;) - { - if (buf_cur != buf_end) - { - static int try = 0; /* NOTE STATIC */ - size_t n = buf_end - buf_cur; - ssize_t r = write(adns_qfd, buf_cur, n); - - if (r == -1) - { - switch (errno) - { - case EINTR: - continue; /* try again now */ - case EAGAIN: - DBG(DBG_DNS, DBG_log("EAGAIN writing to ADNS")); - break; /* try again later */ - default: - try++; - log_errno((e, "error %d writing DNS query", try)); - break; /* try again later */ - } - unsent_ADNS_queries = TRUE; - break; /* done! */ - } - else - { - passert(r >= 0); - try = 0; - buf_cur += r; - } - } - else - { - if (next_query == NULL) - { - unsent_ADNS_queries = FALSE; - break; /* done! */ - } - - next_query->query.debugging = next_query->debugging; - next_query->query.serial = next_query->qtid; - next_query->query.len = sizeof(next_query->query); - next_query->query.qmagic = ADNS_Q_MAGIC; - next_query->query.type = next_query->type; - buf_cur = (const void *)&next_query->query; - buf_end = buf_cur + sizeof(next_query->query); - - next_query = next_query->next; - adns_in_flight++; - } - } -} - -static void recover_adns_die(void) -{ - struct adns_continuation *cr = NULL; - - adns_pid = 0; - if(adns_restart_count < ADNS_RESTART_MAX) { - adns_restart_count++; - - /* next DNS query will restart it */ - - /* we have to walk the list of the outstanding requests, - * and redo them! - */ - - cr = continuations; - - /* find the head of the list */ - if(continuations != NULL) { - for (; cr->previous != NULL; cr = cr->previous); - } - - next_query = cr; - - if(next_query != NULL) { - unsent_ADNS_queries = TRUE; - } - } -} - -void reset_adns_restart_count(void) -{ - adns_restart_count=0; -} - -void handle_adns_answer(void) -{ - /* These are retained across calls to handle_adns_answer. */ - static size_t buflen = 0; /* bytes in answer buffer */ - static struct adns_answer buf; - - ssize_t n; - - passert(buflen < sizeof(buf)); - n = read(adns_afd, (unsigned char *)&buf + buflen, sizeof(buf) - buflen); - - if (n < 0) - { - if (errno != EINTR) - { - log_errno((e, "error reading answer from adns")); - /* ??? how can we recover? */ - } - n = 0; /* now n reflects amount read */ - } - else if (n == 0) - { - /* EOF */ - if (adns_in_flight != 0) - { - plog("EOF from ADNS with %d queries outstanding (restarts %d)" - , adns_in_flight, adns_restart_count); - recover_adns_die(); - } - if (buflen != 0) - { - plog("EOF from ADNS with %lu bytes of a partial answer outstanding" - "(restarts %d)" - , (unsigned long)buflen - , adns_restart_count); - recover_adns_die(); - } - stop_adns(); - return; - } - else - { - passert(adns_in_flight > 0); - } - - buflen += n; - while (buflen >= offsetof(struct adns_answer, ans) && buflen >= buf.len) - { - /* we've got a tasty answer -- process it */ - err_t ugh; - struct adns_continuation *cr = continuation_for_qtid(buf.serial); /* assume it works */ - const char *typename = rr_typename(cr->query.type); - const char *name_buf = cr->query.name_buf; - -#ifdef USE_KEYRR - passert(cr->keys_from_dns == NULL); -#endif /* USE_KEYRR */ - passert(cr->gateways_from_dns == NULL); - adns_in_flight--; - if (buf.result == -1) - { - /* newer resolvers support statp->res_h_errno as well as h_errno. - * That might be better, but older resolvers don't. - * See resolver(3), if you have it. - * The undocumented(!) h_errno values are defined in - * /usr/include/netdb.h. - */ - switch (buf.h_errno_val) - { - case NO_DATA: - ugh = builddiag("no %s record for %s", typename, name_buf); - break; - case HOST_NOT_FOUND: - ugh = builddiag("no host %s for %s record", name_buf, typename); - break; - default: - ugh = builddiag("failure querying DNS for %s of %s: %s" - , typename, name_buf, hstrerror(buf.h_errno_val)); - break; - } - } - else if (buf.result > (int) sizeof(buf.ans)) - { - ugh = builddiag("(INTERNAL ERROR) answer too long (%ld) for buffer" - , (long)buf.result); - } - else - { - ugh = process_dns_answer(cr, buf.ans, buf.result); - if (ugh != NULL) - ugh = builddiag("failure processing %s record of DNS answer for %s: %s" - , typename, name_buf, ugh); - } - DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL | DBG_DNS, - DBG_log(BLANK_FORMAT); - if (ugh == NULL) - DBG_log("asynch DNS answer %lu for %s of %s" - , cr->query.serial, typename, name_buf); - else - DBG_log("asynch DNS answer %lu %s", cr->query.serial, ugh); - ); - - passert(GLOBALS_ARE_RESET()); - cr->cont_fn(cr, ugh); - reset_globals(); - release_adns_continuation(cr); - - /* shift out answer that we've consumed */ - buflen -= buf.len; - memmove((unsigned char *)&buf, (unsigned char *)&buf + buf.len, buflen); - } -} diff --git a/src/pluto/dnskey.h b/src/pluto/dnskey.h deleted file mode 100644 index 39a406cbd..000000000 --- a/src/pluto/dnskey.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Find public key in DNS - * Copyright (C) 2000-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <utils/identification.h> - -extern int adns_qfd; /* file descriptor for sending queries to adns */ -extern int adns_afd; /* file descriptor for receiving answers from adns */ -extern const char *pluto_adns_option; /* path from --pluto_adns */ -extern void init_adns(void); -extern void stop_adns(void); -extern void handle_adns_answer(void); - -extern bool unsent_ADNS_queries; -extern void send_unsent_ADNS_queries(void); - -/* (common prefix of) stuff remembered between async query and answer. - * Filled in by start_adns_query. - * Freed by call to release_adns_continuation. - */ - -struct adns_continuation; /* forward declaration (not far!) */ - -typedef void (*cont_fn_t)(struct adns_continuation *cr, err_t ugh); - -struct adns_continuation { - unsigned long qtid; /* query transaction id number */ - int type; /* T_TXT or T_KEY, selecting rr type of interest */ - cont_fn_t cont_fn; /* function to carry on suspended work */ - identification_t *id; /* subject of query */ - bool sgw_specified; - identification_t *sgw_id; /* peer, if constrained */ - lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */ - struct gw_info *gateways_from_dns; /* answer, if looking for our TXT rrs */ -#ifdef USE_KEYRR - struct pubkey_list *keys_from_dns; /* answer, if looking for KEY rrs */ -#endif - struct adns_continuation *previous, *next; - struct pubkey *last_info; /* the last structure we accumulated */ - struct adns_query query; -}; - -extern err_t start_adns_query(identification_t *id /* domain to query */ - , identification_t *sgw_id /* if non-null, any accepted gw_info must match */ - , int type /* T_TXT or T_KEY, selecting rr type of interest */ - , cont_fn_t cont_fn /* continuation function */ - , struct adns_continuation *cr); - - -/* Gateway info gleaned from reverse DNS of client */ -struct gw_info { - unsigned refcnt; /* reference counted! */ - unsigned pref; /* preference: lower is better */ -#define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */ - identification_t* client_id; /* id of client of peer */ - identification_t* gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */ - bool gw_key_present; - struct pubkey *key; - struct gw_info *next; -}; - -extern void gw_addref(struct gw_info *gw); -extern void gw_delref(struct gw_info **gwp); -extern void reset_adns_restart_count(void); - diff --git a/src/pluto/event_queue.c b/src/pluto/event_queue.c deleted file mode 100644 index 602a013ee..000000000 --- a/src/pluto/event_queue.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <unistd.h> -#include <fcntl.h> - -#include "event_queue.h" - -#include <debug.h> -#include <threading/mutex.h> -#include <utils/linked_list.h> - -typedef struct private_event_queue_t private_event_queue_t; - -/** - * Private data of event_queue_t class. - */ -struct private_event_queue_t { - /** - * Public event_queue_t interface. - */ - event_queue_t public; - - /** - * List of queued events (event_t*). - */ - linked_list_t *events; - - /** - * Mutex for event list. - */ - mutex_t *mutex; - - /** - * Read end of the notification pipe. - */ - int read_fd; - - /** - * Write end of the notification pipe. - */ - int write_fd; - -}; - -typedef struct event_t event_t; - -struct event_t { - /** - * Callback function. - */ - void (*callback)(void *data); - - /** - * Data to supply to the callback. - */ - void *data; - - /** - * Cleanup function. - */ - void (*cleanup)(void *data); -}; - -static event_t *event_create(void (*callback)(void *data), void *data, - void (*cleanup)(void *data)) -{ - event_t *this; - INIT(this, - .callback = callback, - .data = data, - .cleanup = cleanup, - ); - return this; -} - -static void event_destroy(event_t *this) -{ - if (this->cleanup) - { - this->cleanup(this->data); - } - free(this); -} - -METHOD(event_queue_t, get_event_fd, int, - private_event_queue_t *this) -{ - return this->read_fd; -} - -METHOD(event_queue_t, handle, void, - private_event_queue_t *this) -{ - char buf[10]; - linked_list_t *events; - event_t *event; - this->mutex->lock(this->mutex); - /* flush pipe */ - while (read(this->read_fd, &buf, sizeof(buf)) == sizeof(buf)); - /* replace the list, so we can unlock the mutex while executing the jobs */ - events = this->events; - this->events = linked_list_create(); - this->mutex->unlock(this->mutex); - - while (events->remove_first(events, (void**)&event) == SUCCESS) - { - event->callback(event->data); - event_destroy(event); - } - events->destroy(events); -} - -METHOD(event_queue_t, queue, void, - private_event_queue_t *this, void (*callback)(void *data), void *data, - void (*cleanup)(void *data)) -{ - event_t *event = event_create(callback, data, cleanup); - char c = 0; - this->mutex->lock(this->mutex); - this->events->insert_last(this->events, event); - ignore_result(write(this->write_fd, &c, 1)); - this->mutex->unlock(this->mutex); -} - -METHOD(event_queue_t, destroy, void, - private_event_queue_t *this) -{ - this->mutex->lock(this->mutex); - this->events->destroy_function(this->events, (void*)event_destroy); - this->mutex->unlock(this->mutex); - this->mutex->destroy(this->mutex); - close(this->read_fd); - close(this->write_fd); - free(this); -} - -static bool set_nonblock(int socket) -{ - int flags = fcntl(socket, F_GETFL); - return flags != -1 && fcntl(socket, F_SETFL, flags | O_NONBLOCK) != -1; -} - -static bool set_cloexec(int socket) -{ - int flags = fcntl(socket, F_GETFD); - return flags != -1 && fcntl(socket, F_SETFD, flags | FD_CLOEXEC) != -1; -} - -/* - * Described in header. - */ -event_queue_t *event_queue_create() -{ - private_event_queue_t *this; - int fd[2]; - - INIT(this, - .public = { - .get_event_fd = _get_event_fd, - .handle = _handle, - .queue = _queue, - .destroy = _destroy, - }, - .events = linked_list_create(), - .mutex = mutex_create(MUTEX_TYPE_DEFAULT), - ); - - if (pipe(fd) == -1 || - !set_nonblock(fd[0]) || !set_cloexec(fd[0]) || - !set_nonblock(fd[1]) || !set_cloexec(fd[1])) - { - DBG1(DBG_JOB, "failed to create pipe for job queue"); - _destroy(this); - return NULL; - } - - this->read_fd = fd[0]; - this->write_fd = fd[1]; - - return &this->public; -} - diff --git a/src/pluto/event_queue.h b/src/pluto/event_queue.h deleted file mode 100644 index 343729e25..000000000 --- a/src/pluto/event_queue.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup event_queue event_queue - * @{ @ingroup pluto - */ - -#ifndef EVENT_QUEUE_H_ -#define EVENT_QUEUE_H_ - -typedef struct event_queue_t event_queue_t; - -/** - * The event queue facility can be used to synchronize thread-pool threads - * with the pluto main thread. That is, all queued callbacks are executed - * asynchronously by the pluto main thread. - */ -struct event_queue_t { - - /** - * Returns the file descriptor used to notify the main thread. - * - * @return fd to use in the main thread - */ - int (*get_event_fd) (event_queue_t *this); - - /** - * Handle all queued events. - */ - void (*handle) (event_queue_t *this); - - /** - * Add an event to the queue. - * - * @param callback callback function to add to the queue - * @param data data supplied to the callback function - * @param cleanup optional cleanup function - */ - void (*queue) (event_queue_t *this, void (*callback)(void *data), - void *data, void (*cleanup)(void *data)); - - /** - * Destroy this instance. - */ - void (*destroy) (event_queue_t *this); - -}; - -/** - * Create the event queue. - * - * @return created object - */ -event_queue_t *event_queue_create(); - -#endif /** EVENT_QUEUE_H_ @}*/ diff --git a/src/pluto/fetch.c b/src/pluto/fetch.c deleted file mode 100644 index 3dfc1386f..000000000 --- a/src/pluto/fetch.c +++ /dev/null @@ -1,766 +0,0 @@ -/* Dynamic fetching of X.509 CRLs - * Copyright (C) 2002 Stephane Laroche <stephane.laroche@colubris.com> - * Copyright (C) 2002-2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdlib.h> -#include <errno.h> -#include <sys/time.h> -#include <time.h> -#include <string.h> - -#ifdef THREADS -#include <pthread.h> -#endif - -#include <freeswan.h> - -#include <library.h> -#include <debug.h> -#include <asn1/asn1.h> -#include <credentials/certificates/certificate.h> -#ifdef THREADS -#include <threading/thread.h> -#endif - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "ca.h" -#include "whack.h" -#include "ocsp.h" -#include "crl.h" -#include "fetch.h" -#include "builder.h" - -fetch_req_t empty_fetch_req = { - NULL , /* next */ - 0 , /* trials */ - NULL , /* issuer */ - { NULL, 0}, /* authKeyID */ - NULL /* distributionPoints */ -}; - -/* chained list of crl fetch requests */ -static fetch_req_t *crl_fetch_reqs = NULL; - -/* chained list of ocsp fetch requests */ -static ocsp_location_t *ocsp_fetch_reqs = NULL; - -#ifdef THREADS -static thread_t *thread; -static pthread_mutex_t certs_and_keys_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t authcert_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t crl_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t ocsp_cache_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t ca_info_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t crl_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t ocsp_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t fetch_wake_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t fetch_wake_cond = PTHREAD_COND_INITIALIZER; - -/** - * lock access to my certs and keys - */ -void lock_certs_and_keys(const char *who) -{ - pthread_mutex_lock(&certs_and_keys_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("certs and keys locked by '%s'", who) - ) -} - -/** - * Unlock access to my certs and keys - */ -void unlock_certs_and_keys(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("certs and keys unlocked by '%s'", who) - ) - pthread_mutex_unlock(&certs_and_keys_mutex); -} - -/** - * Lock access to the chained authcert list - */ -void lock_authcert_list(const char *who) -{ - pthread_mutex_lock(&authcert_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("authcert list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained authcert list - */ -void unlock_authcert_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("authcert list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&authcert_list_mutex); -} - -/** - * Lock access to the chained crl list - */ -void lock_crl_list(const char *who) -{ - pthread_mutex_lock(&crl_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("crl list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained crl list - */ -void unlock_crl_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("crl list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&crl_list_mutex); -} - -/** - * Lock access to the ocsp cache - */ -extern void lock_ocsp_cache(const char *who) -{ - pthread_mutex_lock(&ocsp_cache_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("ocsp cache locked by '%s'", who) - ) -} - -/** - * Unlock access to the ocsp cache - */ -extern void unlock_ocsp_cache(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("ocsp cache unlocked by '%s'", who) - ) - pthread_mutex_unlock(&ocsp_cache_mutex); -} - -/** - * Lock access to the ca info list - */ -extern void lock_ca_info_list(const char *who) -{ - pthread_mutex_lock(&ca_info_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("ca info list locked by '%s'", who) - ) -} - -/** - * Unlock access to the ca info list - */ -extern void unlock_ca_info_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("ca info list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&ca_info_list_mutex); -} - -/** - * Lock access to the chained crl fetch request list - */ -static void lock_crl_fetch_list(const char *who) -{ - pthread_mutex_lock(&crl_fetch_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("crl fetch request list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained crl fetch request list - */ -static void unlock_crl_fetch_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("crl fetch request list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&crl_fetch_list_mutex); -} - -/** - * Lock access to the chained ocsp fetch request list - */ -static void lock_ocsp_fetch_list(const char *who) -{ - pthread_mutex_lock(&ocsp_fetch_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("ocsp fetch request list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained ocsp fetch request list - */ -static void unlock_ocsp_fetch_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("ocsp fetch request list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&ocsp_fetch_list_mutex); -} - -/** - * Wakes up the sleeping fetch thread - */ -void wake_fetch_thread(const char *who) -{ - if (crl_check_interval > 0) - { - DBG(DBG_CONTROLMORE, - DBG_log("fetch thread wake call by '%s'", who) - ) - pthread_mutex_lock(&fetch_wake_mutex); - pthread_cond_signal(&fetch_wake_cond); - pthread_mutex_unlock(&fetch_wake_mutex); - } -} -#else /* !THREADS */ -#define lock_crl_fetch_list(who) /* do nothing */ -#define unlock_crl_fetch_list(who) /* do nothing */ -#define lock_ocsp_fetch_list(who) /* do nothing */ -#define unlock_ocsp_fetch_list(who) /* do nothing */ -#endif /* !THREADS */ - -/** - * Free the dynamic memory used to store fetch requests - */ -static void free_fetch_request(fetch_req_t *req) -{ - req->distributionPoints->destroy_function(req->distributionPoints, free); - DESTROY_IF(req->issuer); - free(req->authKeyID.ptr); - free(req); -} - -#ifdef THREADS -/** - * Fetch an ASN.1 blob coded in PEM or DER format from a URL - */ -x509crl_t* fetch_crl(char *url) -{ - x509crl_t *crl; - chunk_t blob; - - DBG1(DBG_LIB, " fetching crl from '%s' ...", url); - if (lib->fetcher->fetch(lib->fetcher, url, &blob, FETCH_END) != SUCCESS) - { - DBG1(DBG_LIB, "crl fetching failed"); - return FALSE; - } - crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CRL, - BUILD_BLOB_PEM, blob, BUILD_END); - free(blob.ptr); - if (!crl) - { - DBG1(DBG_LIB, "crl fetched successfully but data coded in unknown " - "format"); - } - return crl; -} - -/** - * Complete a distributionPoint URI with ca information - */ -static char* complete_uri(char *distPoint, const char *ldaphost) -{ - char *symbol = strchr(distPoint, ':'); - - if (symbol) - { - int type_len = symbol - distPoint; - - if (type_len >= 4 && strncasecmp(distPoint, "ldap", 4) == 0) - { - char *ptr = symbol + 1; - int len = strlen(distPoint) - (type_len + 1); - - if (len > 2 && *ptr++ == '/' && *ptr++ == '/') - { - len -= 2; - symbol = strchr(ptr, '/'); - - if (symbol && symbol - ptr == 0 && ldaphost) - { - char uri[BUF_LEN]; - - /* insert the ldaphost into the uri */ - snprintf(uri, BUF_LEN, "%.*s%s%.*s", - (int)strlen(distPoint) - len, distPoint, ldaphost, - len, symbol); - return strdup(uri); - } - } - } - } - - /* default action: copy distributionPoint without change */ - return strdup(distPoint); -} - -/** - * Try to fetch the crls defined by the fetch requests - */ -static void fetch_crls(bool cache_crls) -{ - fetch_req_t *req; - fetch_req_t **reqp; - - lock_crl_fetch_list("fetch_crls"); - req = crl_fetch_reqs; - reqp = &crl_fetch_reqs; - - while (req != NULL) - { - enumerator_t *enumerator; - char *point; - bool valid_crl = FALSE; - const char *ldaphost; - ca_info_t *ca; - - lock_ca_info_list("fetch_crls"); - - ca = get_ca_info(req->issuer, req->authKeyID); - ldaphost = (ca == NULL)? NULL : ca->ldaphost; - - enumerator = req->distributionPoints->create_enumerator(req->distributionPoints); - while (enumerator->enumerate(enumerator, &point)) - { - x509crl_t *crl; - char *uri; - - uri = complete_uri(point, ldaphost); - crl = fetch_crl(uri); - free(uri); - - if (crl) - { - if (insert_crl(crl, point, cache_crls)) - { - DBG(DBG_CONTROL, - DBG_log("we have a valid crl") - ) - valid_crl = TRUE; - break; - } - } - } - enumerator->destroy(enumerator); - unlock_ca_info_list("fetch_crls"); - - if (valid_crl) - { - /* delete fetch request */ - fetch_req_t *req_free = req; - - req = req->next; - *reqp = req; - free_fetch_request(req_free); - } - else - { - /* try again next time */ - req->trials++; - reqp = &req->next; - req = req->next; - } - } - unlock_crl_fetch_list("fetch_crls"); -} - -static void fetch_ocsp_status(ocsp_location_t* location) -{ - chunk_t request = build_ocsp_request(location); - chunk_t response = chunk_empty; - - DBG1(DBG_LIB, " requesting ocsp status from '%s' ...", location->uri); - if (lib->fetcher->fetch(lib->fetcher, location->uri, &response, - FETCH_REQUEST_DATA, request, - FETCH_REQUEST_TYPE, "application/ocsp-request", - FETCH_END) == SUCCESS) - { - parse_ocsp(location, response); - } - else - { - DBG1(DBG_LIB, "ocsp request to %s failed", location->uri); - } - - free(request.ptr); - chunk_free(&location->nonce); - - /* increment the trial counter of the unresolved fetch requests */ - { - ocsp_certinfo_t *certinfo = location->certinfo; - - while (certinfo != NULL) - { - certinfo->trials++; - certinfo = certinfo->next; - } - } -} - -/** - * Try to fetch the necessary ocsp information - */ -static void fetch_ocsp(void) -{ - ocsp_location_t *location; - - lock_ocsp_fetch_list("fetch_ocsp"); - location = ocsp_fetch_reqs; - - /* fetch the ocps status for all locations */ - while (location != NULL) - { - if (location->certinfo != NULL) - { - fetch_ocsp_status(location); - } - location = location->next; - } - - unlock_ocsp_fetch_list("fetch_ocsp"); -} - -static void* fetch_thread(void *arg) -{ - struct timespec wait_interval; - - /* the fetching thread is only cancellable while waiting for new events */ - thread_cancelability(FALSE); - - DBG(DBG_CONTROL, - DBG_log("fetch thread started") - ) - - pthread_mutex_lock(&fetch_wake_mutex); - - while(1) - { - int status; - - wait_interval.tv_nsec = 0; - wait_interval.tv_sec = time(NULL) + crl_check_interval; - - DBG(DBG_CONTROL, - DBG_log("next regular crl check in %ld seconds", crl_check_interval) - ) - - thread_cancelability(TRUE); - status = pthread_cond_timedwait(&fetch_wake_cond, &fetch_wake_mutex - , &wait_interval); - thread_cancelability(FALSE); - - if (status == ETIMEDOUT) - { - DBG(DBG_CONTROL, - DBG_log(" "); - DBG_log("*time to check crls and the ocsp cache") - ) - check_ocsp(); - check_crls(); - } - else - { - DBG(DBG_CONTROL, - DBG_log("fetch thread was woken up") - ) - } - fetch_ocsp(); - fetch_crls(cache_crls); - } - return NULL; -} -#endif /* THREADS*/ - -/** - * Initializes curl and starts the fetching thread - */ -void fetch_initialize(void) -{ - if (crl_check_interval > 0) - { -#ifdef THREADS - thread = thread_create((thread_main_t)fetch_thread, NULL); - if (thread == NULL) - { - plog("fetching thread could not be started"); - } -#else /* !THREADS */ - plog("warning: not compiled with pthread support"); -#endif /* !THREADS */ - } -} - -/** - * Terminates the fetching thread - */ -void fetch_finalize(void) -{ - if (crl_check_interval > 0) - { -#ifdef THREADS - if (thread) - { - thread->cancel(thread); - thread->join(thread); - } -#endif - } -} - -void free_crl_fetch(void) -{ - lock_crl_fetch_list("free_crl_fetch"); - - while (crl_fetch_reqs != NULL) - { - fetch_req_t *req = crl_fetch_reqs; - crl_fetch_reqs = req->next; - free_fetch_request(req); - } - - unlock_crl_fetch_list("free_crl_fetch"); -} - -/** - * Free the chained list of ocsp requests - */ -void free_ocsp_fetch(void) -{ - lock_ocsp_fetch_list("free_ocsp_fetch"); - free_ocsp_locations(&ocsp_fetch_reqs); - unlock_ocsp_fetch_list("free_ocsp_fetch"); -} - - -/** - * Add an additional distribution point - */ -void add_distribution_point(linked_list_t *points, char *new_point) -{ - char *point; - bool add = TRUE; - enumerator_t *enumerator; - - if (new_point == NULL || *new_point == '\0') - { - return; - } - - enumerator = points->create_enumerator(points); - while (enumerator->enumerate(enumerator, &point)) - { - if (streq(point, new_point)) - { - add = FALSE; - break; - } - } - enumerator->destroy(enumerator); - - if (add) - { - points->insert_last(points, strdup(new_point)); - } -} - -/** - * Add additional distribution points - */ -void add_distribution_points(linked_list_t *points, linked_list_t *new_points) -{ - char *new_point; - enumerator_t *enumerator; - - enumerator = new_points->create_enumerator(new_points); - while (enumerator->enumerate(enumerator, &new_point)) - { - bool add = TRUE; - char *point; - enumerator_t *enumerator; - - enumerator = points->create_enumerator(points); - while (enumerator->enumerate(enumerator, &point)) - { - if (streq(point, new_point)) - { - add = FALSE; - break; - } - } - enumerator->destroy(enumerator); - - if (add) - { - points->insert_last(points, strdup(new_point)); - } - } - enumerator->destroy(enumerator); -} - -fetch_req_t* build_crl_fetch_request(identification_t *issuer, - chunk_t authKeyID, - linked_list_t *distributionPoints) -{ - char *point; - enumerator_t *enumerator; - fetch_req_t *req = malloc_thing(fetch_req_t); - - memset(req, 0, sizeof(fetch_req_t)); - req->distributionPoints = linked_list_create(); - - /* clone fields */ - req->issuer = issuer->clone(issuer); - req->authKeyID = chunk_clone(authKeyID); - - /* copy distribution points */ - enumerator = distributionPoints->create_enumerator(distributionPoints); - while (enumerator->enumerate(enumerator, &point)) - { - req->distributionPoints->insert_last(req->distributionPoints, - strdup(point)); - } - enumerator->destroy(enumerator); - - return req; -} - -/** - * Add a crl fetch request to the chained list - */ -void add_crl_fetch_request(fetch_req_t *req) -{ - fetch_req_t *r; - - lock_crl_fetch_list("add_crl_fetch_request"); - r = crl_fetch_reqs; - - while (r != NULL) - { - if (req->authKeyID.ptr ? same_keyid(req->authKeyID, r->authKeyID) : - req->issuer->equals(req->issuer, r->issuer)) - { - /* there is already a fetch request */ - DBG(DBG_CONTROL, - DBG_log("crl fetch request already exists") - ) - - /* there might be new distribution points */ - add_distribution_points(r->distributionPoints, - req->distributionPoints); - - unlock_crl_fetch_list("add_crl_fetch_request"); - free_fetch_request(req); - return; - } - r = r->next; - } - - /* insert new fetch request at the head of the queue */ - req->next = crl_fetch_reqs; - crl_fetch_reqs = req; - - DBG(DBG_CONTROL, - DBG_log("crl fetch request added") - ) - unlock_crl_fetch_list("add_crl_fetch_request"); -} - -/** - * Add an ocsp fetch request to the chained list - */ -void add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber) -{ - ocsp_certinfo_t certinfo; - - certinfo.serialNumber = serialNumber; - - lock_ocsp_fetch_list("add_ocsp_fetch_request"); - add_certinfo(location, &certinfo, &ocsp_fetch_reqs, TRUE); - unlock_ocsp_fetch_list("add_ocsp_fetch_request"); -} - -/** - * List all distribution points - */ -void list_distribution_points(linked_list_t *distributionPoints) -{ - char *point; - bool first_point = TRUE; - enumerator_t *enumerator; - - enumerator = distributionPoints->create_enumerator(distributionPoints); - while (enumerator->enumerate(enumerator, &point)) - { - whack_log(RC_COMMENT, " %s '%s'", - (first_point)? "distPts: " : " ", point); - first_point = FALSE; - } - enumerator->destroy(enumerator); -} - -/** - * List all fetch requests in the chained list - */ -void list_crl_fetch_requests(bool utc) -{ - fetch_req_t *req; - - lock_crl_fetch_list("list_crl_fetch_requests"); - req = crl_fetch_reqs; - - if (req != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of CRL Fetch Requests:"); - } - - while (req != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " trials: %d", req->trials); - whack_log(RC_COMMENT, " issuer: \"%Y\"", req->issuer); - if (req->authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &req->authKeyID); - } - list_distribution_points(req->distributionPoints); - req = req->next; - } - unlock_crl_fetch_list("list_crl_fetch_requests"); -} - -void list_ocsp_fetch_requests(bool utc) -{ - lock_ocsp_fetch_list("list_ocsp_fetch_requests"); - list_ocsp_locations(ocsp_fetch_reqs, TRUE, utc, FALSE); - unlock_ocsp_fetch_list("list_ocsp_fetch_requests"); - -} diff --git a/src/pluto/fetch.h b/src/pluto/fetch.h deleted file mode 100644 index 265dc5fe7..000000000 --- a/src/pluto/fetch.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Dynamic fetching of X.509 CRLs - * Copyright (C) 2002 Stephane Laroche <stephane.laroche@colubris.com> - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <utils/linked_list.h> -#include <utils/identification.h> - -#include "x509.h" - -#define FETCH_CMD_TIMEOUT 10 /* seconds */ - -struct ocsp_location; /* forward declaration of ocsp_location defined in ocsp.h */ - -typedef enum { - FETCH_GET = 1, - FETCH_POST = 2 -} fetch_request_t; - -typedef struct fetch_req fetch_req_t; - -struct fetch_req { - fetch_req_t *next; - int trials; - identification_t *issuer; - chunk_t authKeyID; - linked_list_t *distributionPoints; -}; - -#ifdef THREADS -extern void lock_crl_list(const char *who); -extern void unlock_crl_list(const char *who); -extern void lock_ocsp_cache(const char *who); -extern void unlock_ocsp_cache(const char *who); -extern void lock_ca_info_list(const char *who); -extern void unlock_ca_info_list(const char *who); -extern void lock_authcert_list(const char *who); -extern void unlock_authcert_list(const char *who); -extern void lock_certs_and_keys(const char *who); -extern void unlock_certs_and_keys(const char *who); -extern void wake_fetch_thread(const char *who); -#else -#define lock_crl_list(who) /* do nothing */ -#define unlock_crl_list(who) /* do nothing */ -#define lock_ocsp_cache(who) /* do nothing */ -#define unlock_ocsp_cache(who) /* do nothing */ -#define lock_ca_info_list(who) /* do nothing */ -#define unlock_ca_info_list(who) /* do nothing */ -#define lock_authcert_list(who) /* do nothing */ -#define unlock_authcert_list(who) /* do nothing */ -#define lock_certs_and_keys(who) /* do nothing */ -#define unlock_certs_and_keys(who) /* do nothing */ -#define wake_fetch_thread(who) /* do nothing */ -#endif -extern void fetch_initialize(void); -extern void fetch_finalize(void); -extern void free_crl_fetch(void); -extern void free_ocsp_fetch(void); -extern void add_distribution_point(linked_list_t *points, char* new_point); -extern void add_distribution_points(linked_list_t *points, - linked_list_t *new_points); -extern fetch_req_t* build_crl_fetch_request(identification_t *issuer, - chunk_t authKeyID, - linked_list_t *distributionPoints); -extern void add_crl_fetch_request(fetch_req_t *req); -extern void add_ocsp_fetch_request(struct ocsp_location *location, - chunk_t serialNumber); -extern void list_distribution_points(linked_list_t *distributionPoints); -extern void list_crl_fetch_requests(bool utc); -extern void list_ocsp_fetch_requests(bool utc); -extern size_t write_buffer(void *ptr, size_t size, size_t nmemb, void *data); - diff --git a/src/pluto/foodgroups.c b/src/pluto/foodgroups.c deleted file mode 100644 index e4f9a1d01..000000000 --- a/src/pluto/foodgroups.c +++ /dev/null @@ -1,450 +0,0 @@ -/* Implement policy groups-style control files (aka "foodgroups") - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <string.h> -#include <stdio.h> -#include <stddef.h> -#include <stdlib.h> -#include <sys/queue.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "foodgroups.h" -#include "kernel.h" -#include "lex.h" -#include "log.h" -#include "whack.h" - - -/* Food group config files are found in directory fg_path */ - -#ifndef POLICYGROUPSDIR -#define POLICYGROUPSDIR IPSEC_CONFDIR "/ipsec.d/policies" -#endif - -const char *policygroups_dir = POLICYGROUPSDIR; - -static char *fg_path = NULL; -static size_t fg_path_space = 0; - - -/* Groups is a list of connections that are policy groups. - * The list is updated as group connections are added and deleted. - */ - -struct fg_groups { - struct fg_groups *next; - connection_t *connection; -}; - -static struct fg_groups *groups = NULL; - - -/* Targets is a list of pairs: subnet and its policy group. - * This list is bulk-updated on whack --listen and - * incrementally updated when group connections are deleted. - * - * It is ordered by source subnet, and if those are equal, then target subnet. - * A subnet is compared by comparing the network, and if those are equal, - * comparing the mask. - */ - -struct fg_targets { - struct fg_targets *next; - struct fg_groups *group; - ip_subnet subnet; - char *name; /* name of instance of group conn */ -}; - -static struct fg_targets *targets = NULL; - -struct fg_targets *new_targets; - -/* ipcmp compares the two ip_address values a and b. - * It returns -1, 0, or +1 if a is, respectively, - * less than, equal to, or greater than b. - */ -static int ipcmp(ip_address *a, ip_address *b) -{ - if (addrtypeof(a) != addrtypeof(b)) - { - return addrtypeof(a) < addrtypeof(b)? -1 : 1; - } - else if (sameaddr(a, b)) - { - return 0; - } - else - { - const struct sockaddr *sa = sockaddrof(a) - , *sb = sockaddrof(b); - - passert(addrtypeof(a) == AF_INET); /* not yet implemented IPv6 version :-( */ - return (ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr) - < ntohl(((const struct sockaddr_in *)sb)->sin_addr.s_addr)) - ? -1 : 1; - } -} - -/* subnetcmp compares the two ip_subnet values a and b. - * It returns -1, 0, or +1 if a is, respectively, - * less than, equal to, or greater than b. - */ -static int subnetcmp(const ip_subnet *a, const ip_subnet *b) -{ - ip_address neta, maska, netb, maskb; - int r; - - networkof(a, &neta); - maskof(a, &maska); - networkof(b, &netb); - maskof(b, &maskb); - r = ipcmp(&neta, &netb); - if (r == 0) - r = ipcmp(&maska, &maskb); - return r; -} - -static void read_foodgroup(struct fg_groups *g) -{ - const char *fgn = g->connection->name; - const ip_subnet *lsn = &g->connection->spd.this.client; - size_t plen = strlen(policygroups_dir) + 1 + strlen(fgn) + 1; - struct file_lex_position flp_space; - - if (plen > fg_path_space) - { - free(fg_path); - fg_path_space = plen + 10; - fg_path = malloc(fg_path_space); - } - snprintf(fg_path, fg_path_space, "%s/%s", policygroups_dir, fgn); - if (!lexopen(&flp_space, fg_path, TRUE)) - { - DBG(DBG_CONTROL, DBG_log("no group file \"%s\"", fg_path)); - } - else - { - plog("loading group \"%s\"", fg_path); - for (;;) - { - switch (flp->bdry) - { - case B_none: - { - /* !!! this test is not sufficient for distinguishing address families. - * We need a notation to specify that a FQDN is to be resolved to IPv6. - */ - const struct af_info *afi = strchr(tok, ':') == NULL - ? &af_inet4_info: &af_inet6_info; - ip_subnet sn; - err_t ugh; - - if (strchr(tok, '/') == NULL) - { - /* no /, so treat as /32 or V6 equivalent */ - ip_address t; - - ugh = ttoaddr(tok, 0, afi->af, &t); - if (ugh == NULL) - ugh = addrtosubnet(&t, &sn); - } - else - { - ugh = ttosubnet(tok, 0, afi->af, &sn); - } - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s \"%s\"" - , flp->filename, flp->lino, ugh, tok); - } - else if (afi->af != AF_INET) - { - loglog(RC_LOG_SERIOUS - , "\"%s\" line %d: unsupported Address Family \"%s\"" - , flp->filename, flp->lino, tok); - } - else - { - /* Find where new entry ought to go in new_targets. */ - struct fg_targets **pp; - int r; - - for (pp = &new_targets; ; pp = &(*pp)->next) - { - if (*pp == NULL) - { - r = -1; /* end of list is infinite */ - break; - } - r = subnetcmp(lsn, &(*pp)->group->connection->spd.this.client); - if (r == 0) - r = subnetcmp(&sn, &(*pp)->subnet); - if (r <= 0) - break; - } - - if (r == 0) - { - char source[SUBNETTOT_BUF]; - - subnettot(lsn, 0, source, sizeof(source)); - loglog(RC_LOG_SERIOUS - , "\"%s\" line %d: subnet \"%s\", source %s, already \"%s\"" - , flp->filename - , flp->lino - , tok - , source - , (*pp)->group->connection->name); - } - else - { - struct fg_targets *f = malloc_thing(struct fg_targets); - - f->next = *pp; - f->group = g; - f->subnet = sn; - f->name = NULL; - *pp = f; - } - } - } - (void)shift(); /* next */ - continue; - - case B_record: - flp->bdry = B_none; /* eat the Record Boundary */ - (void)shift(); /* get real first token */ - continue; - - case B_file: - break; /* done */ - } - break; /* if we reach here, out of loop */ - } - lexclose(); - } -} - -static void free_targets(void) -{ - while (targets != NULL) - { - struct fg_targets *t = targets; - - targets = t->next; - free(t->name); - free(t); - } -} - -void load_groups(void) -{ - passert(new_targets == NULL); - - /* for each group, add config file targets into new_targets */ - { - struct fg_groups *g; - - for (g = groups; g != NULL; g = g->next) - if (oriented(*g->connection)) - read_foodgroup(g); - } - - /* dump new_targets */ - DBG(DBG_CONTROL, - { - struct fg_targets *t; - - for (t = new_targets; t != NULL; t = t->next) - { - char asource[SUBNETTOT_BUF]; - char atarget[SUBNETTOT_BUF]; - - subnettot(&t->group->connection->spd.this.client - , 0, asource, sizeof(asource)); - subnettot(&t->subnet, 0, atarget, sizeof(atarget)); - DBG_log("%s->%s %s" - , asource, atarget - , t->group->connection->name); - } - }); - - /* determine and deal with differences between targets and new_targets. - * structured like a merge. - */ - { - struct fg_targets *op = targets - , *np = new_targets; - - while (op != NULL && np != NULL) - { - int r = subnetcmp(&op->group->connection->spd.this.client - , &np->group->connection->spd.this.client); - - if (r == 0) - r = subnetcmp(&op->subnet, &np->subnet); - - if (r == 0 && op->group == np->group) - { - /* unchanged -- steal name & skip over */ - np->name = op->name; - op->name = NULL; - op = op->next; - np = np->next; - } - else - { - /* note: following cases overlap! */ - if (r <= 0) - { - remove_group_instance(op->group->connection, op->name); - op = op->next; - } - if (r >= 0) - { - np->name = add_group_instance(np->group->connection, &np->subnet); - np = np->next; - } - } - } - for (; op != NULL; op = op->next) - remove_group_instance(op->group->connection, op->name); - for (; np != NULL; np = np->next) - np->name = add_group_instance(np->group->connection, &np->subnet); - - /* update: new_targets replaces targets */ - free_targets(); - targets = new_targets; - new_targets = NULL; - } -} - - -void add_group(connection_t *c) -{ - struct fg_groups *g = malloc_thing(struct fg_groups); - - g->next = groups; - groups = g; - - g->connection = c; -} - -static struct fg_groups *find_group(const connection_t *c) -{ - struct fg_groups *g; - - for (g = groups; g != NULL && g->connection != c; g = g->next) - ; - return g; -} - -void route_group(connection_t *c) -{ - /* it makes no sense to route a connection that is ISAKMP-only */ - if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy)) - { - loglog(RC_ROUTE, "cannot route an ISAKMP-only group connection"); - } - else - { - struct fg_groups *g = find_group(c); - struct fg_targets *t; - - passert(g != NULL); - g->connection->policy |= POLICY_GROUTED; - for (t = targets; t != NULL; t = t->next) - { - if (t->group == g) - { - connection_t *ci = con_by_name(t->name, FALSE); - - if (ci != NULL) - { - set_cur_connection(ci); - if (!trap_connection(ci)) - whack_log(RC_ROUTE, "could not route"); - set_cur_connection(c); - } - } - } - } -} - -void unroute_group(connection_t *c) -{ - struct fg_groups *g = find_group(c); - struct fg_targets *t; - - passert(g != NULL); - g->connection->policy &= ~POLICY_GROUTED; - for (t = targets; t != NULL; t = t->next) - { - if (t->group == g) - { - connection_t *ci = con_by_name(t->name, FALSE); - - if (ci != NULL) - { - set_cur_connection(ci); - unroute_connection(ci); - set_cur_connection(c); - } - } - } -} - -void delete_group(const connection_t *c) -{ - struct fg_groups *g; - - /* find and remove from groups */ - { - struct fg_groups **pp; - - for (pp = &groups; (g = *pp)->connection != c; pp = &(*pp)->next) - ; - - *pp = g->next; - } - - /* find and remove from targets */ - { - struct fg_targets **pp; - - for (pp = &targets; *pp != NULL; ) - { - struct fg_targets *t = *pp; - - if (t->group == g) - { - *pp = t->next; - remove_group_instance(t->group->connection, t->name); - free(t); - /* pp is ready for next iteration */ - } - else - { - pp = &t->next; - } - } - } - - free(g); -} diff --git a/src/pluto/foodgroups.h b/src/pluto/foodgroups.h deleted file mode 100644 index b6d3386ae..000000000 --- a/src/pluto/foodgroups.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Implement policygroups-style control files (aka "foodgroups") - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -struct connection; /* forward declaration */ -extern void add_group(struct connection *c); -extern void route_group(struct connection *c); -extern void unroute_group(struct connection *c); -extern void delete_group(const struct connection *c); - -extern const char *policygroups_dir; -extern void load_groups(void); diff --git a/src/pluto/ike_alg.c b/src/pluto/ike_alg.c deleted file mode 100644 index 3061630e0..000000000 --- a/src/pluto/ike_alg.c +++ /dev/null @@ -1,452 +0,0 @@ -/* IKE modular algorithm handling interface - * Copyright (C) JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/queue.h> - -#include <freeswan.h> - -#include <library.h> -#include <debug.h> -#include <credentials/keys/public_key.h> -#include <credentials/keys/private_key.h> -#include <crypto/hashers/hasher.h> -#include <crypto/crypters/crypter.h> -#include <crypto/prfs/prf.h> - -#include "constants.h" -#include "defs.h" -#include "crypto.h" -#include "state.h" -#include "packet.h" -#include "keys.h" -#include "log.h" -#include "whack.h" -#include "spdb.h" -#include "alg_info.h" -#include "ike_alg.h" -#include "db_ops.h" -#include "connections.h" -#include "kernel.h" - -#define return_on(var, val) do { var=val;goto return_out; } while(0); - -/** - * IKE algorithm list handling - registration and lookup - */ - -/* Modular IKE algorithm storage structure */ - -static struct ike_alg *ike_alg_base[IKE_ALG_MAX+1] = {NULL, NULL}; - -/** - * Return ike_algo object by {type, id} - */ -static struct ike_alg *ike_alg_find(u_int algo_type, u_int algo_id, - u_int keysize __attribute__((unused))) -{ - struct ike_alg *e = ike_alg_base[algo_type]; - - while (e != NULL && algo_id > e->algo_id) - { - e = e->algo_next; - } - return (e != NULL && e->algo_id == algo_id) ? e : NULL; -} - -/** - * "raw" ike_alg list adding function - */ -int ike_alg_add(struct ike_alg* a, const char *plugin_name) -{ - if (a->algo_type > IKE_ALG_MAX) - { - plog("ike_alg: Not added, invalid algorithm type"); - return -EINVAL; - } - - if (ike_alg_find(a->algo_type, a->algo_id, 0) != NULL) - { - plog("ike_alg: Not added, algorithm already exists"); - return -EEXIST; - } - - { - struct ike_alg **ep = &ike_alg_base[a->algo_type]; - struct ike_alg *e = *ep; - - while (e != NULL && a->algo_id > e->algo_id) - { - ep = &e->algo_next; - e = *ep; - } - *ep = a; - a->plugin_name = plugin_name; - a->algo_next = e; - return 0; - } -} - -/** - * Get IKE hash algorithm - */ -struct hash_desc *ike_alg_get_hasher(u_int alg) -{ - return (struct hash_desc *) ike_alg_find(IKE_ALG_HASH, alg, 0); -} - -/** - * Get IKE encryption algorithm - */ -struct encrypt_desc *ike_alg_get_crypter(u_int alg) -{ - return (struct encrypt_desc *) ike_alg_find(IKE_ALG_ENCRYPT, alg, 0); -} - -/** - * Get IKE dh group - */ -struct dh_desc *ike_alg_get_dh_group(u_int alg) -{ - return (struct dh_desc *) ike_alg_find(IKE_ALG_DH_GROUP, alg, 0); -} - -/** - * Get pfsgroup for this connection - */ -const struct dh_desc *ike_alg_pfsgroup(connection_t *c, lset_t policy) -{ - const struct dh_desc *ret = NULL; - - if ((policy & POLICY_PFS) && - c->alg_info_esp && c->alg_info_esp->esp_pfsgroup) - { - ret = ike_alg_get_dh_group(c->alg_info_esp->esp_pfsgroup); - } - return ret; -} - -/** - * Create an OAKLEY proposal based on alg_info and policy - */ -struct db_context *ike_alg_db_new(connection_t *c, lset_t policy) -{ - struct alg_info_ike *ai = c->alg_info_ike; - struct db_context *db_ctx = NULL; - struct ike_info *ike_info; - u_int ealg, halg, modp, eklen = 0; - int i; - - bool is_xauth_server = (policy & POLICY_XAUTH_SERVER) != LEMPTY; - - if (!ai) - { - whack_log(RC_LOG_SERIOUS, "no IKE algorithms " - "for this connection " - "(check ike algorithm string)"); - goto fail; - } - policy &= POLICY_ID_AUTH_MASK; - db_ctx = db_prop_new(PROTO_ISAKMP, 8, 8 * 5); - - /* for each group */ - ALG_INFO_IKE_FOREACH(ai, ike_info, i) - { - ealg = ike_info->ike_ealg; - halg = ike_info->ike_halg; - modp = ike_info->ike_modp; - eklen= ike_info->ike_eklen; - - if (!ike_alg_get_crypter(ealg)) - { - plog("ike alg: crypter %s not present", - enum_show(&oakley_enc_names, ealg)); - continue; - } - if (!ike_alg_get_hasher(halg)) - { - plog("ike alg: hasher %s not present", - enum_show(&oakley_hash_names, halg)); - continue; - } - if (!ike_alg_get_dh_group(modp)) - { - plog("ike alg: dh group %s not present", - enum_show(&oakley_group_names, modp)); - continue; - } - - if (policy & POLICY_PUBKEY) - { - int auth_method = 0, key_size = 0; - key_type_t key_type = KEY_ANY; - - if (c->spd.this.cert) - { - certificate_t *certificate = c->spd.this.cert->cert; - public_key_t *key = certificate->get_public_key(certificate); - - if (key == NULL) - { - plog("ike alg: unable to retrieve my public key"); - continue; - } - key_type = key->get_type(key); - key_size = key->get_keysize(key); - key->destroy(key); - } - else - { - private_key_t *key = get_private_key(c); - - if (key == NULL) - { - plog("ike alg: unable to retrieve my private key"); - continue; - } - key_type = key->get_type(key); - key_size = key->get_keysize(key); - } - switch (key_type) - { - case KEY_RSA: - auth_method = OAKLEY_RSA_SIG; - break; - case KEY_ECDSA: - switch (key_size) - { - case 256: - auth_method = OAKLEY_ECDSA_256; - break; - case 384: - auth_method = OAKLEY_ECDSA_384; - break; - case 521: - auth_method = OAKLEY_ECDSA_521; - break; - default: - continue; - } - break; - default: - continue; - } - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, auth_method); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - - if (policy & POLICY_PSK) - { - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - - if (policy & POLICY_XAUTH_RSASIG) - { - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD - , is_xauth_server ? XAUTHRespRSA : XAUTHInitRSA); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - - if (policy & POLICY_XAUTH_PSK) - { - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD - , is_xauth_server ? XAUTHRespPreShared : XAUTHInitPreShared); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - } -fail: - return db_ctx; -} - -/** - * Print the name of an algorithm plus the name of the plugin that registered it - */ -static void print_alg(char *buf, int *len, enum_names *alg_names, int alg_type, - const char *plugin_name) -{ - char alg_name[BUF_LEN]; - int alg_name_len; - - alg_name_len = sprintf(alg_name, " %s[%s]", enum_name(alg_names, alg_type), - plugin_name); - if (*len + alg_name_len > CRYPTO_MAX_ALG_LINE) - { - whack_log(RC_COMMENT, "%s", buf); - *len = sprintf(buf, " "); - } - sprintf(buf + *len, "%s", alg_name); - *len += alg_name_len; -} - -/** - * Show registered IKE algorithms - */ -void ike_alg_list(void) -{ - rng_quality_t quality; - enumerator_t *enumerator; - const char *plugin_name; - char buf[BUF_LEN]; - int len; - struct ike_alg *a; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of registered IKEv1 Algorithms:"); - whack_log(RC_COMMENT, " "); - - len = sprintf(buf, " encryption:"); - for (a = ike_alg_base[IKE_ALG_ENCRYPT]; a != NULL; a = a->algo_next) - { - print_alg(buf, &len, &oakley_enc_names, a->algo_id, a->plugin_name); - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " integrity: "); - for (a = ike_alg_base[IKE_ALG_HASH]; a != NULL; a = a->algo_next) - { - print_alg(buf, &len, &oakley_hash_names, a->algo_id, a->plugin_name); - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " dh-group: "); - for (a = ike_alg_base[IKE_ALG_DH_GROUP]; a != NULL; a = a->algo_next) - { - print_alg(buf, &len, &oakley_group_names, a->algo_id, a->plugin_name); - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " random-gen:"); - enumerator = lib->crypto->create_rng_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &quality, &plugin_name)) - { - len += sprintf(buf + len, " %N[%s]", rng_quality_names, quality, - plugin_name); - } - enumerator->destroy(enumerator); - whack_log(RC_COMMENT, "%s", buf); -} - -/** - * Show IKE algorithms for this connection (result from ike= string) - * and newest SA - */ -void ike_alg_show_connection(connection_t *c, const char *instance) -{ - struct state *st = state_with_serialno(c->newest_isakmp_sa); - - if (st) - { - if (st->st_oakley.encrypt == OAKLEY_3DES_CBC) - { - whack_log(RC_COMMENT, - "\"%s\"%s: IKE proposal: %s/%s/%s", - c->name, instance, - enum_show(&oakley_enc_names, st->st_oakley.encrypt), - enum_show(&oakley_hash_names, st->st_oakley.hash), - enum_show(&oakley_group_names, st->st_oakley.group->algo_id) - ); - } - else - { - whack_log(RC_COMMENT, - "\"%s\"%s: IKE proposal: %s_%u/%s/%s", - c->name, instance, - enum_show(&oakley_enc_names, st->st_oakley.encrypt), - st->st_oakley.enckeylen, - enum_show(&oakley_hash_names, st->st_oakley.hash), - enum_show(&oakley_group_names, st->st_oakley.group->algo_id) - ); - } - } -} - -/** - * ML: make F_STRICT logic consider enc,hash/auth,modp algorithms - */ -bool ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group, - struct alg_info_ike *alg_info_ike) -{ - /* - * simple test to discard low key_len, will accept it only - * if specified in "esp" string - */ - bool ealg_insecure = (key_len < 128); - - if (ealg_insecure - || (alg_info_ike && alg_info_ike->alg_info_flags & ALG_INFO_F_STRICT)) - { - int i; - struct ike_info *ike_info; - - if (alg_info_ike) - { - ALG_INFO_IKE_FOREACH(alg_info_ike, ike_info, i) - { - if (ike_info->ike_ealg == ealg - && (ike_info->ike_eklen == 0 || key_len == 0 || ike_info->ike_eklen == key_len) - && ike_info->ike_halg == aalg - && ike_info->ike_modp == group) - { - if (ealg_insecure) - loglog(RC_LOG_SERIOUS, "You should NOT use insecure IKE algorithms (%s)!" - , enum_name(&oakley_enc_names, ealg)); - return TRUE; - } - } - } - plog("Oakley Transform [%s (%d), %s, %s] refused due to %s" - , enum_name(&oakley_enc_names, ealg), key_len - , enum_name(&oakley_hash_names, aalg) - , enum_name(&oakley_group_names, group) - , ealg_insecure ? - "insecure key_len and enc. alg. not listed in \"ike\" string" : "strict flag" - ); - return FALSE; - } - return TRUE; -} - diff --git a/src/pluto/ike_alg.h b/src/pluto/ike_alg.h deleted file mode 100644 index c3ce8bb38..000000000 --- a/src/pluto/ike_alg.h +++ /dev/null @@ -1,76 +0,0 @@ -/* IKE modular algorithm handling interface - * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _IKE_ALG_H -#define _IKE_ALG_H - -#include <freeswan.h> - -#include "connections.h" - -struct ike_alg { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; -}; - -struct encrypt_desc { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; - - size_t enc_blocksize; - u_int keydeflen; - u_int keymaxlen; - u_int keyminlen; -}; - -struct hash_desc { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; - - size_t hash_digest_size; -}; - -struct dh_desc { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; - - size_t ke_size; -}; - -#define IKE_ALG_ENCRYPT 0 -#define IKE_ALG_HASH 1 -#define IKE_ALG_DH_GROUP 2 -#define IKE_ALG_MAX IKE_ALG_DH_GROUP - -extern int ike_alg_add(struct ike_alg *a, const char *plugin_name); -extern struct hash_desc *ike_alg_get_hasher(u_int alg); -extern struct encrypt_desc *ike_alg_get_crypter(u_int alg); -extern struct dh_desc *ike_alg_get_dh_group(u_int alg); -extern const struct dh_desc* ike_alg_pfsgroup(struct connection *c, lset_t policy); -extern struct db_context * ike_alg_db_new(struct connection *c, lset_t policy); -extern void ike_alg_list(void); -extern void ike_alg_show_connection(struct connection *c, const char *instance); -extern bool ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group - , struct alg_info_ike *alg_info_ike); -extern int ike_alg_init(void); - -#endif /* _IKE_ALG_H */ diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c deleted file mode 100644 index 3e7adcc40..000000000 --- a/src/pluto/ipsec_doi.c +++ /dev/null @@ -1,5921 +0,0 @@ -/* IPsec DOI and Oakley resolution routines - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <string.h> -#include <stddef.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ -#include <sys/queue.h> - -#include <freeswan.h> - -#include <library.h> -#include <asn1/asn1.h> -#include <crypto/hashers/hasher.h> -#include <crypto/prfs/prf.h> -#include <crypto/rngs/rng.h> -#include <credentials/keys/private_key.h> -#include <credentials/keys/public_key.h> -#include <utils/identification.h> - -#include "constants.h" -#include "defs.h" -#include "myid.h" -#include "state.h" -#include "x509.h" -#include "ac.h" -#include "crl.h" -#include "ca.h" -#include "certs.h" -#include "smartcard.h" -#include "connections.h" -#include "keys.h" -#include "packet.h" -#include "demux.h" /* needs packet.h */ -#include "adns.h" /* needs <resolv.h> */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "kernel.h" -#include "log.h" -#include "cookie.h" -#include "server.h" -#include "spdb.h" -#include "timer.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "whack.h" -#include "fetch.h" -#include "pkcs7.h" -#include "crypto.h" -#include "vendor.h" -#include "alg_info.h" -#include "ike_alg.h" -#include "kernel_alg.h" -#include "nat_traversal.h" -#include "virtual.h" - -/* - * are we sending Pluto's Vendor ID? - */ -#ifdef VENDORID -#define SEND_PLUTO_VID 1 -#else /* !VENDORID */ -#define SEND_PLUTO_VID 0 -#endif /* !VENDORID */ - -/* - * are we sending an XAUTH VID? - */ -#ifdef XAUTH_VID -#define SEND_XAUTH_VID 1 -#else /* !XAUTH_VID */ -#define SEND_XAUTH_VID 0 -#endif /* !XAUTH_VID */ - -/* - * are we sending a Cisco Unity VID? - */ -#ifdef CISCO_QUIRKS -#define SEND_CISCO_UNITY_VID 1 -#else /* !CISCO_QUIRKS */ -#define SEND_CISCO_UNITY_VID 0 -#endif /* !CISCO_QUIRKS */ - -/* MAGIC: perform f, a function that returns notification_t - * and return from the ENCLOSING stf_status returning function if it fails. - */ -#define RETURN_STF_FAILURE(f) \ - { int r = (f); if (r != ISAKMP_NOTHING_WRONG) return STF_FAIL + r; } - -/* The endpoint(s) for which an SA is getting installed, so keying material - * can be properly wiped. - */ -enum endpoint { - EP_LOCAL = 1, - EP_REMOTE = 1 << 1, -}; - -/* create output HDR as replica of input HDR */ -void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np) -{ - struct isakmp_hdr r_hdr = md->hdr; /* mostly same as incoming header */ - - r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT; /* we won't ever turn on this bit */ - if (enc) - { - r_hdr.isa_flags |= ISAKMP_FLAG_ENCRYPTION; - } - /* some day, we may have to set r_hdr.isa_version */ - r_hdr.isa_np = np; - if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody)) - { - impossible(); /* surely must have room and be well-formed */ - } -} - -/* Compute DH shared secret from our local secret and the peer's public value. - * We make the leap that the length should be that of the group - * (see quoted passage at start of ACCEPT_KE). - */ -static void compute_dh_shared(struct state *st, const chunk_t g) -{ - passert(st->st_dh); - st->st_dh->set_other_public_value(st->st_dh, g); - st->st_dh->get_shared_secret(st->st_dh, &st->st_shared); - DBG_cond_dump_chunk(DBG_CRYPT, "DH shared secret:\n", st->st_shared); -} - -/* if we haven't already done so, compute a local DH secret (st->st_sec) and - * the corresponding public value (g). This is emitted as a KE payload. - */ -static bool build_and_ship_KE(struct state *st, chunk_t *g, - const struct dh_desc *group, - pb_stream *outs, u_int8_t np) -{ - if (st->st_dh == NULL) - { - st->st_dh = lib->crypto->create_dh(lib->crypto, group->algo_id); - if (st->st_dh == NULL) - { - plog("Diffie Hellman group %N is not available", - diffie_hellman_group_names, group->algo_id); - return FALSE; - } - } - st->st_dh->get_my_public_value(st->st_dh, g); - DBG(DBG_CRYPT, - DBG_dump_chunk("Public DH value sent:\n", *g) - ) - return out_generic_chunk(np, &isakmp_keyex_desc, outs, *g, "keyex value"); -} - -/* accept_ke - * - * Check and accept DH public value (Gi or Gr) from peer's message. - * According to RFC2409 "The Internet key exchange (IKE)" 5: - * The Diffie-Hellman public value passed in a KE payload, in either - * a phase 1 or phase 2 exchange, MUST be the length of the negotiated - * Diffie-Hellman group enforced, if necessary, by pre-pending the - * value with zeros. - */ -static notification_t accept_KE(chunk_t *dest, const char *val_name, - const struct dh_desc *gr, - pb_stream *pbs) -{ - if (pbs_left(pbs) != gr->ke_size) - { - loglog(RC_LOG_SERIOUS, "KE has %u byte DH public value; %u required" - , (unsigned) pbs_left(pbs), gr->ke_size); - /* XXX Could send notification back */ - return ISAKMP_INVALID_KEY_INFORMATION; - } - free(dest->ptr); - *dest = chunk_create(pbs->cur, pbs_left(pbs)); - *dest = chunk_clone(*dest); - DBG_cond_dump_chunk(DBG_CRYPT, "DH public value received:\n", *dest); - return ISAKMP_NOTHING_WRONG; -} - -/* accept_PFS_KE - * - * Check and accept optional Quick Mode KE payload for PFS. - * Extends ACCEPT_PFS to check whether KE is allowed or required. - */ -static notification_t accept_PFS_KE(struct msg_digest *md, chunk_t *dest, - const char *val_name, const char *msg_name) -{ - struct state *st = md->st; - struct payload_digest *const ke_pd = md->chain[ISAKMP_NEXT_KE]; - - if (ke_pd == NULL) - { - if (st->st_pfs_group != NULL) - { - loglog(RC_LOG_SERIOUS, "missing KE payload in %s message", msg_name); - return ISAKMP_INVALID_KEY_INFORMATION; - } - } - else - { - if (st->st_pfs_group == NULL) - { - loglog(RC_LOG_SERIOUS, "%s message KE payload requires a GROUP_DESCRIPTION attribute in SA" - , msg_name); - return ISAKMP_INVALID_KEY_INFORMATION; - } - if (ke_pd->next != NULL) - { - loglog(RC_LOG_SERIOUS, "%s message contains several KE payloads; we accept at most one", msg_name); - return ISAKMP_INVALID_KEY_INFORMATION; /* ??? */ - } - return accept_KE(dest, val_name, st->st_pfs_group, &ke_pd->pbs); - } - return ISAKMP_NOTHING_WRONG; -} - -static bool build_and_ship_nonce(chunk_t *n, pb_stream *outs, u_int8_t np, - const char *name) -{ - rng_t *rng; - - free(n->ptr); - *n = chunk_create(malloc(DEFAULT_NONCE_SIZE), DEFAULT_NONCE_SIZE); - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->get_bytes(rng, DEFAULT_NONCE_SIZE, n->ptr); - rng->destroy(rng); - return out_generic_chunk(np, &isakmp_nonce_desc, outs, *n, name); -} - -static linked_list_t* collect_rw_ca_candidates(struct msg_digest *md) -{ - linked_list_t *list = linked_list_create(); - connection_t *d; - - d = find_host_connection(&md->iface->addr, pluto_port, (ip_address*)NULL, - md->sender_port, LEMPTY); - - for (; d != NULL; d = d->hp_next) - { - /* must be a road warrior connection */ - if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO) && - d->spd.that.ca) - { - enumerator_t *enumerator; - identification_t *ca; - bool new_entry = TRUE; - - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &ca)) - { - if (ca->equals(ca, d->spd.that.ca)) - { - new_entry = FALSE; - break; - } - } - enumerator->destroy(enumerator); - - if (new_entry) - { - list->insert_last(list, d->spd.that.ca->clone(d->spd.that.ca)); - } - } - } - return list; -} - -static bool build_and_ship_CR(u_int8_t type, chunk_t ca, pb_stream *outs, - u_int8_t np) -{ - pb_stream cr_pbs; - struct isakmp_cr cr_hd; - cr_hd.isacr_np = np; - cr_hd.isacr_type = type; - - /* build CR header */ - if (!out_struct(&cr_hd, &isakmp_ipsec_cert_req_desc, outs, &cr_pbs)) - { - return FALSE; - } - if (ca.ptr != NULL) - { - /* build CR body containing the distinguished name of the CA */ - if (!out_chunk(ca, &cr_pbs, "CA")) - return FALSE; - } - close_output_pbs(&cr_pbs); - return TRUE; -} - -/* Send a notification to the peer. We could decide - * whether to send the notification, based on the type and the - * destination, if we care to. - */ -static void send_notification(struct state *sndst, u_int16_t type, - struct state *encst, msgid_t msgid, - u_char *icookie, u_char *rcookie, - u_char *spi, size_t spisize, u_char protoid) -{ - u_char buffer[1024]; - pb_stream pbs, r_hdr_pbs; - u_char *r_hashval = NULL; /* where in reply to jam hash value */ - u_char *r_hash_start = NULL; /* start of what is to be hashed */ - - passert((sndst) && (sndst->st_connection)); - - plog("sending %snotification %s to %s:%u" - , encst ? "encrypted " : "" - , enum_name(¬ification_names, type) - , ip_str(&sndst->st_connection->spd.that.host_addr) - , (unsigned)sndst->st_connection->spd.that.host_port); - - memset(buffer, 0, sizeof(buffer)); - init_pbs(&pbs, buffer, sizeof(buffer), "ISAKMP notify"); - - /* HDR* */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = encst ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_N; - hdr.isa_xchg = ISAKMP_XCHG_INFO; - hdr.isa_msgid = msgid; - hdr.isa_flags = encst ? ISAKMP_FLAG_ENCRYPTION : 0; - if (icookie) - { - memcpy(hdr.isa_icookie, icookie, COOKIE_SIZE); - } - if (rcookie) - { - memcpy(hdr.isa_rcookie, rcookie, COOKIE_SIZE); - } - if (!out_struct(&hdr, &isakmp_hdr_desc, &pbs, &r_hdr_pbs)) - { - impossible(); - } - } - - /* HASH -- value to be filled later */ - if (encst) - { - pb_stream hash_pbs; - if (!out_generic(ISAKMP_NEXT_N, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs)) - { - impossible(); - } - r_hashval = hash_pbs.cur; /* remember where to plant value */ - if (!out_zero( - encst->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH")) - { - impossible(); - } - close_output_pbs(&hash_pbs); - r_hash_start = r_hdr_pbs.cur; /* hash from after HASH */ - } - - /* Notification Payload */ - { - pb_stream not_pbs; - struct isakmp_notification isan; - - isan.isan_doi = ISAKMP_DOI_IPSEC; - isan.isan_np = ISAKMP_NEXT_NONE; - isan.isan_type = type; - isan.isan_spisize = spisize; - isan.isan_protoid = protoid; - - if (!out_struct(&isan, &isakmp_notification_desc, &r_hdr_pbs, ¬_pbs) - || !out_raw(spi, spisize, ¬_pbs, "spi")) - { - impossible(); - } - close_output_pbs(¬_pbs); - } - - /* calculate hash value and patch into Hash Payload */ - if (encst) - { - chunk_t msgid_chunk = chunk_from_thing(msgid); - chunk_t msg_chunk = { r_hash_start, r_hdr_pbs.cur-r_hash_start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(encst->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, encst->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, r_hashval); - - DBG(DBG_CRYPT, - DBG_log("HASH computed:"); - DBG_dump("", r_hashval, prf->get_block_size(prf)); - ) - prf->destroy(prf); - } - - /* Encrypt message (preserve st_iv and st_new_iv) */ - if (encst) - { - u_char old_iv[MAX_DIGEST_LEN]; - u_char new_iv[MAX_DIGEST_LEN]; - - u_int old_iv_len = encst->st_iv_len; - u_int new_iv_len = encst->st_new_iv_len; - - if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN) - { - impossible(); - } - memcpy(old_iv, encst->st_iv, old_iv_len); - memcpy(new_iv, encst->st_new_iv, new_iv_len); - - if (!IS_ISAKMP_SA_ESTABLISHED(encst->st_state)) - { - memcpy(encst->st_ph1_iv, encst->st_new_iv, encst->st_new_iv_len); - encst->st_ph1_iv_len = encst->st_new_iv_len; - } - init_phase2_iv(encst, &msgid); - if (!encrypt_message(&r_hdr_pbs, encst)) - { - impossible(); - } - - /* restore preserved st_iv and st_new_iv */ - memcpy(encst->st_iv, old_iv, old_iv_len); - memcpy(encst->st_new_iv, new_iv, new_iv_len); - encst->st_iv_len = old_iv_len; - encst->st_new_iv_len = new_iv_len; - } - else - { - close_output_pbs(&r_hdr_pbs); - } - - /* Send packet (preserve st_tpacket) */ - { - chunk_t saved_tpacket = sndst->st_tpacket; - - sndst->st_tpacket = chunk_create(pbs.start, pbs_offset(&pbs)); - send_packet(sndst, "ISAKMP notify"); - sndst->st_tpacket = saved_tpacket; - } -} - -void send_notification_from_state(struct state *st, enum state_kind state, - u_int16_t type) -{ - struct state *p1st; - - passert(st); - - if (state == STATE_UNDEFINED) - state = st->st_state; - - if (IS_QUICK(state)) - { - p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); - if ((p1st == NULL) || (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state))) - { - loglog(RC_LOG_SERIOUS, - "no Phase1 state for Quick mode notification"); - return; - } - send_notification(st, type, p1st, generate_msgid(p1st), - st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); - } - else if (IS_ISAKMP_ENCRYPTED(state) && st->st_enc_key.ptr != NULL) - { - send_notification(st, type, st, generate_msgid(st), - st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); - } - else - { - /* no ISAKMP SA established - don't encrypt notification */ - send_notification(st, type, NULL, 0, - st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); - } -} - -void send_notification_from_md(struct msg_digest *md, u_int16_t type) -{ - /** - * Create a dummy state to be able to use send_packet in - * send_notification - * - * we need to set: - * st_connection->that.host_addr - * st_connection->that.host_port - * st_connection->interface - */ - struct state st; - connection_t cnx; - - passert(md); - - memset(&st, 0, sizeof(st)); - memset(&cnx, 0, sizeof(cnx)); - st.st_connection = &cnx; - cnx.spd.that.host_addr = md->sender; - cnx.spd.that.host_port = md->sender_port; - cnx.interface = md->iface; - - send_notification(&st, type, NULL, 0, - md->hdr.isa_icookie, md->hdr.isa_rcookie, NULL, 0, PROTO_ISAKMP); -} - -/* Send a Delete Notification to announce deletion of ISAKMP SA or - * inbound IPSEC SAs. Does nothing if no such SAs are being deleted. - * Delete Notifications cannot announce deletion of outbound IPSEC/ISAKMP SAs. - */ -void send_delete(struct state *st) -{ - pb_stream reply_pbs; - pb_stream r_hdr_pbs; - msgid_t msgid; - u_char buffer[8192]; - struct state *p1st; - ip_said said[EM_MAXRELSPIS]; - ip_said *ns = said; - u_char - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - bool isakmp_sa = FALSE; - - if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); - if (p1st == NULL) - { - DBG(DBG_CONTROL, DBG_log("no Phase 1 state for Delete")); - return; - } - - if (st->st_ah.present) - { - ns->spi = st->st_ah.our_spi; - ns->dst = st->st_connection->spd.this.host_addr; - ns->proto = PROTO_IPSEC_AH; - ns++; - } - if (st->st_esp.present) - { - ns->spi = st->st_esp.our_spi; - ns->dst = st->st_connection->spd.this.host_addr; - ns->proto = PROTO_IPSEC_ESP; - ns++; - } - - passert(ns != said); /* there must be some SAs to delete */ - } - else if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - p1st = st; - isakmp_sa = TRUE; - } - else - { - return; /* nothing to do */ - } - - msgid = generate_msgid(p1st); - - zero(buffer); - init_pbs(&reply_pbs, buffer, sizeof(buffer), "delete msg"); - - /* HDR* */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_INFO; - hdr.isa_msgid = msgid; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, p1st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, p1st->st_rcookie, COOKIE_SIZE); - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply_pbs, &r_hdr_pbs)) - impossible(); - } - - /* HASH -- value to be filled later */ - { - pb_stream hash_pbs; - - if (!out_generic(ISAKMP_NEXT_D, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs)) - { - impossible(); - } - r_hashval = hash_pbs.cur; /* remember where to plant value */ - if (!out_zero(p1st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH(1)")) - { - impossible(); - } - close_output_pbs(&hash_pbs); - r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */ - } - - /* Delete Payloads */ - if (isakmp_sa) - { - pb_stream del_pbs; - struct isakmp_delete isad; - u_char isakmp_spi[2*COOKIE_SIZE]; - - isad.isad_doi = ISAKMP_DOI_IPSEC; - isad.isad_np = ISAKMP_NEXT_NONE; - isad.isad_spisize = (2 * COOKIE_SIZE); - isad.isad_protoid = PROTO_ISAKMP; - isad.isad_nospi = 1; - - memcpy(isakmp_spi, st->st_icookie, COOKIE_SIZE); - memcpy(isakmp_spi+COOKIE_SIZE, st->st_rcookie, COOKIE_SIZE); - - if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs) - || !out_raw(&isakmp_spi, (2*COOKIE_SIZE), &del_pbs, "delete payload")) - { - impossible(); - } - close_output_pbs(&del_pbs); - } - else - { - while (ns != said) - { - - pb_stream del_pbs; - struct isakmp_delete isad; - - ns--; - isad.isad_doi = ISAKMP_DOI_IPSEC; - isad.isad_np = ns == said? ISAKMP_NEXT_NONE : ISAKMP_NEXT_D; - isad.isad_spisize = sizeof(ipsec_spi_t); - isad.isad_protoid = ns->proto; - - isad.isad_nospi = 1; - if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs) - || !out_raw(&ns->spi, sizeof(ipsec_spi_t), &del_pbs, "delete payload")) - { - impossible(); - } - close_output_pbs(&del_pbs); - } - } - - /* calculate hash value and patch into Hash Payload */ - { - chunk_t msgid_chunk = chunk_from_thing(msgid); - chunk_t msg_chunk = { r_hash_start, r_hdr_pbs.cur-r_hash_start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(p1st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, p1st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, r_hashval); - - DBG(DBG_CRYPT, - DBG_log("HASH(1) computed:"); - DBG_dump("", r_hashval, prf->get_block_size(prf)); - ) - - prf->destroy(prf); - } - - /* Do a dance to avoid needing a new state object. - * We use the Phase 1 State. This is the one with right - * IV, for one thing. - * The tricky bits are: - * - we need to preserve (save/restore) st_iv (but not st_iv_new) - * - we need to preserve (save/restore) st_tpacket. - */ - { - u_char old_iv[MAX_DIGEST_LEN]; - chunk_t saved_tpacket = p1st->st_tpacket; - - memcpy(old_iv, p1st->st_iv, p1st->st_iv_len); - init_phase2_iv(p1st, &msgid); - - if (!encrypt_message(&r_hdr_pbs, p1st)) - { - impossible(); - } - p1st->st_tpacket = chunk_create(reply_pbs.start, pbs_offset(&reply_pbs)); - send_packet(p1st, "delete notify"); - p1st->st_tpacket = saved_tpacket; - - /* get back old IV for this state */ - memcpy(p1st->st_iv, old_iv, p1st->st_iv_len); - } -} - -void accept_delete(struct state *st, struct msg_digest *md, - struct payload_digest *p) -{ - struct isakmp_delete *d = &(p->payload.delete); - identification_t *this_id = NULL, *that_id = NULL; - ip_address peer_addr; - size_t sizespi; - int i; - - if (!md->encrypted) - { - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: not encrypted"); - return; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - /* can't happen (if msg is encrypt), but just to be sure */ - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " - "ISAKMP SA not established"); - return; - } - - if (d->isad_nospi == 0) - { - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: no SPI"); - return; - } - - switch (d->isad_protoid) - { - case PROTO_ISAKMP: - sizespi = 2 * COOKIE_SIZE; - break; - case PROTO_IPSEC_AH: - case PROTO_IPSEC_ESP: - sizespi = sizeof(ipsec_spi_t); - break; - case PROTO_IPCOMP: - /* nothing interesting to delete */ - return; - default: - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: unknown Protocol ID (%s)" - , enum_show(&protocol_names, d->isad_protoid)); - return; - } - - if (d->isad_spisize != sizespi) - { - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: bad SPI size (%d) for %s" - , d->isad_spisize, enum_show(&protocol_names, d->isad_protoid)); - return; - } - - if (pbs_left(&p->pbs) != d->isad_nospi * sizespi) - { - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: invalid payload size"); - return; - } - - if (d->isad_protoid == PROTO_ISAKMP) - { - struct end *this = &st->st_connection->spd.this; - struct end *that = &st->st_connection->spd.that; - this_id = this->id->clone(this->id); - that_id = that->id->clone(that->id); - peer_addr = st->st_connection->spd.that.host_addr; - } - - for (i = 0; i < d->isad_nospi; i++) - { - u_char *spi = p->pbs.cur + (i * sizespi); - - if (d->isad_protoid == PROTO_ISAKMP) - { - /** - * ISAKMP - */ - struct state *dst = find_state(spi /*iCookie*/ - , spi+COOKIE_SIZE /*rCookie*/ - , &peer_addr - , MAINMODE_MSGID); - - if (dst == NULL) - { - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " - "ISAKMP SA not found (maybe expired)"); - } - else if (! this_id->equals(this_id, dst->st_connection->spd.this.id) || - ! that_id->equals(that_id, dst->st_connection->spd.that.id)) - { - /* we've not authenticated the relevant identities */ - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " - "ISAKMP SA used to convey Delete has different IDs from ISAKMP SA it deletes"); - } - else - { - connection_t *oldc; - - oldc = cur_connection; - set_cur_connection(dst->st_connection); - - if (nat_traversal_enabled) - { - nat_traversal_change_port_lookup(md, dst); - } - loglog(RC_LOG_SERIOUS, "received Delete SA payload: " - "deleting ISAKMP State #%lu", dst->st_serialno); - delete_state(dst); - set_cur_connection(oldc); - } - } - else - { - /** - * IPSEC (ESP/AH) - */ - bool bogus; - struct state *dst = find_phase2_state_to_delete(st - , d->isad_protoid - , *(ipsec_spi_t *)spi /* network order */ - , &bogus); - - if (dst == NULL) - { - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: %s SA(0x%08lx) not found (%s)" - , enum_show(&protocol_names, d->isad_protoid) - , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi) - , bogus ? "our SPI - bogus implementation" : "maybe expired"); - } - else - { - connection_t *rc = dst->st_connection; - connection_t *oldc; - - oldc = cur_connection; - set_cur_connection(rc); - - if (nat_traversal_enabled) - { - nat_traversal_change_port_lookup(md, dst); - } - if (rc->newest_ipsec_sa == dst->st_serialno - && (rc->policy & POLICY_UP)) - { - /* Last IPSec SA for a permanent connection that we - * have initiated. Replace it in a few seconds. - * - * Useful if the other peer is rebooting. - */ -#define DELETE_SA_DELAY EVENT_RETRANSMIT_DELAY_0 - if (dst->st_event != NULL - && dst->st_event->ev_type == EVENT_SA_REPLACE - && dst->st_event->ev_time <= DELETE_SA_DELAY + now()) - { - /* Patch from Angus Lees to ignore retransmited - * Delete SA. - */ - loglog(RC_LOG_SERIOUS, "received Delete SA payload: " - "already replacing IPSEC State #%lu in %d seconds" - , dst->st_serialno, (int)(dst->st_event->ev_time - now())); - } - else - { - loglog(RC_LOG_SERIOUS, "received Delete SA payload: " - "replace IPSEC State #%lu in %d seconds" - , dst->st_serialno, DELETE_SA_DELAY); - dst->st_margin = DELETE_SA_DELAY; - delete_event(dst); - event_schedule(EVENT_SA_REPLACE, DELETE_SA_DELAY, dst); - } - } - else - { - loglog(RC_LOG_SERIOUS, "received Delete SA(0x%08lx) payload: " - "deleting IPSEC State #%lu" - , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi) - , dst->st_serialno); - delete_state(dst); - } - - /* reset connection */ - set_cur_connection(oldc); - } - } - } - - if (d->isad_protoid == PROTO_ISAKMP) - { - this_id->destroy(this_id); - that_id->destroy(that_id); - } -} - -/* The whole message must be a multiple of 4 octets. - * I'm not sure where this is spelled out, but look at - * rfc2408 3.6 Transform Payload. - * Note: it talks about 4 BYTE boundaries! - */ -void close_message(pb_stream *pbs) -{ - size_t padding = pad_up(pbs_offset(pbs), 4); - - if (padding != 0) - { - (void) out_zero(padding, pbs, "message padding"); - } - close_output_pbs(pbs); -} - -/* Initiate an Oakley Main Mode exchange. - * --> HDR;SA - * Note: this is not called from demux.c - */ -static stf_status -main_outI1(int whack_sock, connection_t *c, struct state *predecessor - , lset_t policy, unsigned long try) -{ - struct state *st = new_state(); - pb_stream reply; /* not actually a reply, but you know what I mean */ - pb_stream rbody; - int vids_to_send = 0; - - /* set up new state */ - st->st_connection = c; - set_cur_state(st); /* we must reset before exit */ - st->st_policy = policy & ~POLICY_IPSEC_MASK; - st->st_whack_sock = whack_sock; - st->st_try = try; - st->st_state = STATE_MAIN_I1; - - /* determine how many Vendor ID payloads we will be sending */ - if (SEND_PLUTO_VID) - { - vids_to_send++; - } - if (SEND_CISCO_UNITY_VID) - { - vids_to_send++; - } - if (c->spd.this.cert && - c->spd.this.cert->cert->get_type(c->spd.this.cert->cert) == CERT_GPG) - { - vids_to_send++; - } - if (SEND_XAUTH_VID) - { - vids_to_send++; - } - - /* always send DPD Vendor ID */ - vids_to_send++; - - if (nat_traversal_enabled) - { - vids_to_send++; - } - - get_cookie(TRUE, st->st_icookie, COOKIE_SIZE, &c->spd.that.host_addr); - - insert_state(st); /* needs cookies, connection, and msgid (0) */ - - if (HAS_IPSEC_POLICY(policy)) - { - add_pending(dup_any(whack_sock), st, c, policy, 1 - , predecessor == NULL? SOS_NOBODY : predecessor->st_serialno); - } - if (predecessor == NULL) - { - plog("initiating Main Mode"); - } - else - { - plog("initiating Main Mode to replace #%lu", predecessor->st_serialno); - } - - /* set up reply */ - init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet"); - - /* HDR out */ - { - struct isakmp_hdr hdr; - - zero(&hdr); /* default to 0 */ - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_SA; - hdr.isa_xchg = ISAKMP_XCHG_IDPROT; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - /* R-cookie, flags and MessageID are left zero */ - - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* SA out */ - { - u_char *sa_start = rbody.cur; - - if (!out_sa(&rbody, &oakley_sadb, st, TRUE - , vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - - /* save initiator SA for later HASH */ - passert(st->st_p1isa.ptr == NULL); /* no leak! (MUST be first time) */ - st->st_p1isa = chunk_create(sa_start, rbody.cur - sa_start); - st->st_p1isa = chunk_clone(st->st_p1isa); - } - - /* if enabled send Pluto Vendor ID */ - if (SEND_PLUTO_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_STRONGSWAN)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* if enabled send Cisco Unity Vendor ID */ - if (SEND_CISCO_UNITY_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_CISCO_UNITY)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - /* if we have an OpenPGP certificate we assume an - * OpenPGP peer and have to send the Vendor ID - */ - if (c->spd.this.cert && - c->spd.this.cert->cert->get_type(c->spd.this.cert->cert) == CERT_GPG) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_OPENPGP)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do eXtended AUTHentication to the peer */ - if (SEND_XAUTH_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_MISC_XAUTH)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do Dead Peer Detection to the peer */ - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_MISC_DPD)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - if (nat_traversal_enabled) - { - /* Add supported NAT-Traversal VID */ - if (!nat_traversal_add_vid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - close_message(&rbody); - close_output_pbs(&reply); - st->st_tpacket = chunk_create(reply.start, pbs_offset(&reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - /* Transmit */ - - send_packet(st, "main_outI1"); - - /* Set up a retransmission event, half a minute henceforth */ - delete_event(st); - event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); - - if (predecessor != NULL) - { - update_pending(predecessor, st); - whack_log(RC_NEW_STATE + STATE_MAIN_I1 - , "%s: initiate, replacing #%lu" - , enum_name(&state_names, st->st_state) - , predecessor->st_serialno); - } - else - { - whack_log(RC_NEW_STATE + STATE_MAIN_I1 - , "%s: initiate", enum_name(&state_names, st->st_state)); - } - reset_cur_state(); - return STF_OK; -} - -void ipsecdoi_initiate(int whack_sock, connection_t *c, lset_t policy, - unsigned long try, so_serial_t replacing) -{ - /* If there's already an ISAKMP SA established, use that and - * go directly to Quick Mode. We are even willing to use one - * that is still being negotiated, but only if we are the Initiator - * (thus we can be sure that the IDs are not going to change; - * other issues around intent might matter). - * Note: there is no way to initiate with a Road Warrior. - */ - struct state *st = find_phase1_state(c - , ISAKMP_SA_ESTABLISHED_STATES | PHASE1_INITIATOR_STATES); - - if (st == NULL) - { - (void) main_outI1(whack_sock, c, NULL, policy, try); - } - else if (HAS_IPSEC_POLICY(policy)) - { - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - /* leave our Phase 2 negotiation pending */ - add_pending(whack_sock, st, c, policy, try, replacing); - } - else - { - /* ??? we assume that peer_nexthop_sin isn't important: - * we already have it from when we negotiated the ISAKMP SA! - * It isn't clear what to do with the error return. - */ - (void) quick_outI1(whack_sock, st, c, policy, try, replacing); - } - } - else - { - close_any(whack_sock); - } -} - -/* Replace SA with a fresh one that is similar - * - * Shares some logic with ipsecdoi_initiate, but not the same! - * - we must not reuse the ISAKMP SA if we are trying to replace it! - * - if trying to replace IPSEC SA, use ipsecdoi_initiate to build - * ISAKMP SA if needed. - * - duplicate whack fd, if live. - * Does not delete the old state -- someone else will do that. - */ -void ipsecdoi_replace(struct state *st, unsigned long try) -{ - int whack_sock = dup_any(st->st_whack_sock); - lset_t policy = st->st_policy; - - if (IS_PHASE1(st->st_state)) - { - passert(!HAS_IPSEC_POLICY(policy)); - (void) main_outI1(whack_sock, st->st_connection, st, policy, try); - } - else - { - /* Add features of actual old state to policy. This ensures - * that rekeying doesn't downgrade security. I admit that - * this doesn't capture everything. - */ - if (st->st_pfs_group != NULL) - policy |= POLICY_PFS; - if (st->st_ah.present) - { - policy |= POLICY_AUTHENTICATE; - if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; - } - if (st->st_esp.present && st->st_esp.attrs.transid != ESP_NULL) - { - policy |= POLICY_ENCRYPT; - if (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; - } - if (st->st_ipcomp.present) - { - policy |= POLICY_COMPRESS; - if (st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; - } - passert(HAS_IPSEC_POLICY(policy)); - ipsecdoi_initiate(whack_sock, st->st_connection, policy, try - , st->st_serialno); - } -} - -/* SKEYID for preshared keys. - * See draft-ietf-ipsec-ike-01.txt 4.1 - */ -static bool skeyid_preshared(struct state *st) -{ - const chunk_t *pss = get_preshared_secret(st->st_connection); - - if (pss == NULL) - { - loglog(RC_LOG_SERIOUS, "preshared secret disappeared!"); - return FALSE; - } - else - { - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - if (prf == NULL) - { - loglog(RC_LOG_SERIOUS, "%N not available to compute skeyid", - pseudo_random_function_names, prf_alg); - return FALSE; - } - free(st->st_skeyid.ptr); - prf->set_key(prf, *pss); - prf->allocate_bytes(prf, st->st_ni, NULL); - prf->allocate_bytes(prf, st->st_nr, &st->st_skeyid); - prf->destroy(prf); - return TRUE; - } -} - -static bool skeyid_digisig(struct state *st) -{ - chunk_t nir; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - if (prf == NULL) - { - loglog(RC_LOG_SERIOUS, "%N not available to compute skeyid", - pseudo_random_function_names, prf_alg); - return FALSE; - } - free(st->st_skeyid.ptr); - nir = chunk_cat("cc", st->st_ni, st->st_nr); - prf->set_key(prf, nir); - prf->allocate_bytes(prf, st->st_shared, &st->st_skeyid); - prf->destroy(prf); - free(nir.ptr); - return TRUE; -} - -/* Generate the SKEYID_* and new IV - * See draft-ietf-ipsec-ike-01.txt 4.1 - */ -static bool generate_skeyids_iv(struct state *st) -{ - /* Generate the SKEYID */ - switch (st->st_oakley.auth) - { - case OAKLEY_PRESHARED_KEY: - case XAUTHInitPreShared: - case XAUTHRespPreShared: - if (!skeyid_preshared(st)) - { - return FALSE; - } - break; - - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - case XAUTHInitRSA: - case XAUTHRespRSA: - if (!skeyid_digisig(st)) - { - return FALSE; - } - break; - - case OAKLEY_DSS_SIG: - /* XXX */ - - case OAKLEY_RSA_ENC: - case OAKLEY_RSA_ENC_REV: - case OAKLEY_ELGAMAL_ENC: - case OAKLEY_ELGAMAL_ENC_REV: - /* XXX */ - - default: - bad_case(st->st_oakley.auth); - } - - /* generate SKEYID_* from SKEYID */ - { - chunk_t seed_skeyid_d = chunk_from_chars(0x00); - chunk_t seed_skeyid_a = chunk_from_chars(0x01); - chunk_t seed_skeyid_e = chunk_from_chars(0x02); - chunk_t icookie = { st->st_icookie, COOKIE_SIZE }; - chunk_t rcookie = { st->st_rcookie, COOKIE_SIZE }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid); - - /* SKEYID_D */ - free(st->st_skeyid_d.ptr); - prf->allocate_bytes(prf, st->st_shared, NULL); - prf->allocate_bytes(prf, icookie, NULL); - prf->allocate_bytes(prf, rcookie, NULL); - prf->allocate_bytes(prf, seed_skeyid_d, &st->st_skeyid_d); - - /* SKEYID_A */ - free(st->st_skeyid_a.ptr); - prf->allocate_bytes(prf, st->st_skeyid_d, NULL); - prf->allocate_bytes(prf, st->st_shared, NULL); - prf->allocate_bytes(prf, icookie, NULL); - prf->allocate_bytes(prf, rcookie, NULL); - prf->allocate_bytes(prf, seed_skeyid_a, &st->st_skeyid_a); - - /* SKEYID_E */ - free(st->st_skeyid_e.ptr); - prf->allocate_bytes(prf, st->st_skeyid_a, NULL); - prf->allocate_bytes(prf, st->st_shared, NULL); - prf->allocate_bytes(prf, icookie, NULL); - prf->allocate_bytes(prf, rcookie, NULL); - prf->allocate_bytes(prf, seed_skeyid_e, &st->st_skeyid_e); - - prf->destroy(prf); - } - - /* generate IV */ - { - hash_algorithm_t hash_alg; - hasher_t *hasher; - - hash_alg = oakley_to_hash_algorithm(st->st_oakley.hash); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - st->st_new_iv_len = hasher->get_hash_size(hasher); - passert(st->st_new_iv_len <= sizeof(st->st_new_iv)); - - DBG(DBG_CRYPT, - DBG_dump_chunk("DH_i:", st->st_gi); - DBG_dump_chunk("DH_r:", st->st_gr); - ); - - hasher->get_hash(hasher, st->st_gi, NULL); - hasher->get_hash(hasher, st->st_gr, st->st_new_iv); - hasher->destroy(hasher); - } - - /* Oakley Keying Material - * Derived from Skeyid_e: if it is not big enough, generate more - * using the PRF. - * See RFC 2409 "IKE" Appendix B - */ - { - size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE; - - /* free any existing key */ - free(st->st_enc_key.ptr); - - if (keysize > st->st_skeyid_e.len) - { - u_char keytemp[MAX_OAKLEY_KEY_LEN + MAX_DIGEST_LEN]; - chunk_t seed = chunk_from_chars(0x00); - size_t prf_block_size, i; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_e); - prf_block_size = prf->get_block_size(prf); - - for (i = 0;;) - { - prf->get_bytes(prf, seed, &keytemp[i]); - i += prf_block_size; - if (i >= keysize) - { - break; - } - seed = chunk_create(&keytemp[i-prf_block_size], prf_block_size); - } - prf->destroy(prf); - st->st_enc_key = chunk_create(keytemp, keysize); - } - else - { - st->st_enc_key = chunk_create(st->st_skeyid_e.ptr, keysize); - } - st->st_enc_key = chunk_clone(st->st_enc_key); - } - - DBG(DBG_CRYPT, - DBG_dump_chunk("Skeyid: ", st->st_skeyid); - DBG_dump_chunk("Skeyid_d:", st->st_skeyid_d); - DBG_dump_chunk("Skeyid_a:", st->st_skeyid_a); - DBG_dump_chunk("Skeyid_e:", st->st_skeyid_e); - DBG_dump_chunk("enc key:", st->st_enc_key); - DBG_dump("IV:", st->st_new_iv, st->st_new_iv_len)); - return TRUE; -} - -/* Generate HASH_I or HASH_R for ISAKMP Phase I. - * This will *not* generate other hash payloads (eg. Phase II or Quick Mode, - * New Group Mode, or ISAKMP Informational Exchanges). - * If the hashi argument is TRUE, generate HASH_I; if FALSE generate HASH_R. - * If hashus argument is TRUE, we're generating a hash for our end. - * See RFC2409 IKE 5. - */ - static void main_mode_hash(struct state *st, chunk_t *hash, bool hashi, - const pb_stream *idpl) -{ - chunk_t icookie = { st->st_icookie, COOKIE_SIZE }; - chunk_t rcookie = { st->st_rcookie, COOKIE_SIZE }; - chunk_t sa_body = { st->st_p1isa.ptr + sizeof(struct isakmp_generic), - st->st_p1isa.len - sizeof(struct isakmp_generic) }; - chunk_t id_body = { idpl->start + sizeof(struct isakmp_generic), - pbs_offset(idpl) - sizeof(struct isakmp_generic) }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - switch (st->st_oakley.auth) - { - case OAKLEY_ECDSA_256: - prf_alg = PRF_HMAC_SHA2_256; - break; - case OAKLEY_ECDSA_384: - prf_alg = PRF_HMAC_SHA2_384; - break; - case OAKLEY_ECDSA_521: - prf_alg = PRF_HMAC_SHA2_512; - break; - default: - prf_alg = oakley_to_prf(st->st_oakley.hash); - } - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid); - - if (hashi) - { - prf->get_bytes(prf, st->st_gi, NULL); - prf->get_bytes(prf, st->st_gr, NULL); - prf->get_bytes(prf, icookie, NULL); - prf->get_bytes(prf, rcookie, NULL); - } - else - { - prf->get_bytes(prf, st->st_gr, NULL); - prf->get_bytes(prf, st->st_gi, NULL); - prf->get_bytes(prf, rcookie, NULL); - prf->get_bytes(prf, icookie, NULL); - } - - DBG(DBG_CRYPT, - DBG_log("hashing %u bytes of SA", sa_body.len) - ) - prf->get_bytes(prf, sa_body, NULL); - - /* Hash identification payload, without generic payload header. - * We used to reconstruct ID Payload for this purpose, but now - * we use the bytes as they appear on the wire to avoid - * "spelling problems". - */ - prf->get_bytes(prf, id_body, hash->ptr); - hash->len = prf->get_block_size(prf); - prf->destroy(prf); -} - -/* Create a public key signature of a hash. - * Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2. - * Use PKCS#1 version 1.5 encryption of hash (called - * RSAES-PKCS1-V1_5) in PKCS#2. - */ -static size_t sign_hash(signature_scheme_t scheme, connection_t *c, - u_char sig_val[RSA_MAX_OCTETS], chunk_t hash) -{ - size_t sz = 0; - smartcard_t *sc = c->spd.this.sc; - - if (sc == NULL) /* no smartcard */ - { - chunk_t sig; - private_key_t *private = get_private_key(c); - - if (private == NULL) - { - return 0; /* failure: no key to use */ - } - if (!private->sign(private, scheme, hash, &sig)) - { - return 0; - } - memcpy(sig_val, sig.ptr, sig.len); - sz = sig.len; - free(sig.ptr); - } - else if (sc->valid) /* if valid pin then sign hash on the smartcard */ - { - lock_certs_and_keys("sign_hash"); - if (!scx_establish_context(sc) || !scx_login(sc)) - { - scx_release_context(sc); - unlock_certs_and_keys("sign_hash"); - return 0; - } - - sz = scx_get_keylength(sc); - if (sz == 0) - { - plog("failed to get keylength from smartcard"); - scx_release_context(sc); - unlock_certs_and_keys("sign_hash"); - return 0; - } - - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("signing hash with private key from smartcard (slot: %d, id: %s)" - , (int)sc->slot, sc->id) - ) - sz = scx_sign_hash(sc, hash.ptr, hash.len, sig_val, sz) ? sz : 0; - if (!pkcs11_keep_state) - { - scx_release_context(sc); - } - unlock_certs_and_keys("sign_hash"); - } - return sz; -} - -/* Check signature against all public keys we can find. - * If we need keys from DNS KEY records, and they haven't been fetched, - * return STF_SUSPEND to ask for asynch DNS lookup. - * - * Note: parameter keys_from_dns contains results of DNS lookup for key - * or is NULL indicating lookup not yet tried. - * - * take_a_crack is a helper function. Mostly forensic. - * If only we had coroutines. - */ -struct tac_state { - struct state *st; - chunk_t hash; - chunk_t sig; - int tried_cnt; /* number of keys tried */ -}; - -static bool take_a_crack(struct tac_state *s, pubkey_t *kr) -{ - public_key_t *pub_key = kr->public_key; - chunk_t keyid = chunk_empty; - signature_scheme_t scheme; - - s->tried_cnt++; - scheme = oakley_to_signature_scheme(s->st->st_oakley.auth); - pub_key->get_fingerprint(pub_key, KEYID_PUBKEY_INFO_SHA1, &keyid); - - if (pub_key->verify(pub_key, scheme, s->hash, s->sig)) - { - DBG(DBG_CRYPT | DBG_CONTROL, - DBG_log("%s check passed with keyid %#B", - enum_show(&oakley_auth_names, s->st->st_oakley.auth), &keyid) - ) - unreference_key(&s->st->st_peer_pubkey); - s->st->st_peer_pubkey = reference_key(kr); - return TRUE; - } - else - { - DBG(DBG_CRYPT, - DBG_log("%s check failed with keyid %#B", - enum_show(&oakley_auth_names, s->st->st_oakley.auth), &keyid) - ) - return FALSE; - } -} - -static stf_status check_signature(key_type_t key_type, identification_t* peer, - struct state *st, chunk_t hash, - const pb_stream *sig_pbs, -#ifdef USE_KEYRR - const pubkey_list_t *keys_from_dns, -#endif /* USE_KEYRR */ - const struct gw_info *gateways_from_dns) -{ - const connection_t *c = st->st_connection; - struct tac_state s; - - s.st = st; - s.hash = hash; - s.sig = chunk_create(sig_pbs->cur, pbs_left(sig_pbs)); - s.tried_cnt = 0; - - /* try all gateway records hung off c */ - if (c->policy & POLICY_OPPO) - { - struct gw_info *gw; - - for (gw = c->gw_info; gw != NULL; gw = gw->next) - { - /* only consider entries that have a key and are for our peer */ - if (gw->gw_key_present && - gw->gw_id->equals(gw->gw_id, c->spd.that.id) && - take_a_crack(&s, gw->key)) - { - return STF_OK; - } - } - } - - /* try all appropriate Public keys */ - { - pubkey_list_t *p, **pp; - - pp = &pubkeys; - - for (p = pubkeys; p != NULL; p = *pp) - { - pubkey_t *key = p->key; - key_type_t type = key->public_key->get_type(key->public_key); - - if (type == key_type && peer->equals(peer, key->id)) - { - time_t now = time(NULL); - - /* check if found public key has expired */ - if (key->until_time != UNDEFINED_TIME && key->until_time < now) - { - loglog(RC_LOG_SERIOUS, - "cached public key has expired and has been deleted"); - *pp = free_public_keyentry(p); - continue; /* continue with next public key */ - } - if (take_a_crack(&s, key)) - { - return STF_OK; - } - } - pp = &p->next; - } - } - - /* if no key was found and that side of connection is - * key_from_DNS_on_demand then go search DNS for keys for peer. - */ - if (s.tried_cnt == 0 && c->spd.that.key_from_DNS_on_demand) - { - if (gateways_from_dns != NULL) - { - /* TXT keys */ - const struct gw_info *gwp; - - for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - if (gwp->gw_key_present && take_a_crack(&s, gwp->key)) - { - return STF_OK; - } - } - } -#ifdef USE_KEYRR - else if (keys_from_dns != NULL) - { - /* KEY keys */ - const pubkey_list_t *kr; - - for (kr = keys_from_dns; kr != NULL; kr = kr->next) - { - if (kr->key->alg == PUBKEY_ALG_RSA && take_a_crack(&s, kr->key)) - { - return STF_OK; - } - } - } -#endif /* USE_KEYRR */ - else - { - /* nothing yet: ask for asynch DNS lookup */ - return STF_SUSPEND; - } - } - - /* no acceptable key was found: diagnose */ - { - if (s.tried_cnt == 0) - { - loglog(RC_LOG_SERIOUS, "no public key known for '%Y'", peer); - } - else if (s.tried_cnt == 1) - { - loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: " - " wrong key?; tried %d", peer, s.tried_cnt); - DBG(DBG_CONTROL, - DBG_log("public key for '%Y' failed: " - "decrypted SIG payload into a malformed ECB", peer) - ) - } - else - { - loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: " - "tried %d keys but none worked.", peer, s.tried_cnt); - DBG(DBG_CONTROL, - DBG_log("all %d public keys for '%Y' failed: " - "best decrypted SIG payload into a malformed ECB", - s.tried_cnt, peer) - ) - } - return STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; - } -} - -static notification_t accept_nonce(struct msg_digest *md, chunk_t *dest, - const char *name) -{ - pb_stream *nonce_pbs = &md->chain[ISAKMP_NEXT_NONCE]->pbs; - size_t len = pbs_left(nonce_pbs); - - if (len < MINIMUM_NONCE_SIZE || MAXIMUM_NONCE_SIZE < len) - { - loglog(RC_LOG_SERIOUS, "%s length not between %d and %d" - , name , MINIMUM_NONCE_SIZE, MAXIMUM_NONCE_SIZE); - return ISAKMP_PAYLOAD_MALFORMED; /* ??? */ - } - free(dest->ptr); - *dest = chunk_create(nonce_pbs->cur, len); - *dest = chunk_clone(*dest); - return ISAKMP_NOTHING_WRONG; -} - -/* encrypt message, sans fixed part of header - * IV is fetched from st->st_new_iv and stored into st->st_iv. - * The theory is that there will be no "backing out", so we commit to IV. - * We also close the pbs. - */ -bool encrypt_message(pb_stream *pbs, struct state *st) -{ - u_int8_t *enc_start = pbs->start + sizeof(struct isakmp_hdr); - size_t enc_len = pbs_offset(pbs) - sizeof(struct isakmp_hdr); - chunk_t data, iv; - char *new_iv; - size_t crypter_block_size, crypter_iv_size; - encryption_algorithm_t enc_alg; - crypter_t *crypter; - - DBG_cond_dump(DBG_CRYPT | DBG_RAW, "encrypting:\n", enc_start, enc_len); - enc_alg = oakley_to_encryption_algorithm(st->st_oakley.encrypt); - crypter = lib->crypto->create_crypter(lib->crypto, enc_alg, st->st_enc_key.len); - crypter_block_size = crypter->get_block_size(crypter); - crypter_iv_size = crypter->get_iv_size(crypter); - - /* Pad up to multiple of encryption blocksize. - * See the description associated with the definition of - * struct isakmp_hdr in packet.h. - */ - { - size_t padding = pad_up(enc_len, crypter_block_size); - - if (padding != 0) - { - if (!out_zero(padding, pbs, "encryption padding")) - return FALSE; - enc_len += padding; - } - } - - DBG(DBG_CRYPT, DBG_log("encrypting using %s", enum_show(&oakley_enc_names, st->st_oakley.encrypt))); - data = chunk_create(enc_start, enc_len); - - /* form iv by truncation */ - st->st_new_iv_len = crypter_iv_size; - iv = chunk_create(st->st_new_iv, st->st_new_iv_len); - - crypter->set_key(crypter, st->st_enc_key); - crypter->encrypt(crypter, data, iv, NULL); - crypter->destroy(crypter); - - new_iv = data.ptr + data.len - crypter_iv_size; - memcpy(st->st_new_iv, new_iv, crypter_iv_size); - update_iv(st); - DBG_cond_dump(DBG_CRYPT, "next IV:", st->st_iv, st->st_iv_len); - close_message(pbs); - return TRUE; -} - -/* Compute HASH(1), HASH(2) of Quick Mode. - * HASH(1) is part of Quick I1 message. - * HASH(2) is part of Quick R1 message. - * Used by: quick_outI1, quick_inI1_outR1 (twice), quick_inR1_outI2 - * (see RFC 2409 "IKE" 5.5, pg. 18 or draft-ietf-ipsec-ike-01.txt 6.2 pg 25) - */ -static size_t quick_mode_hash12(u_char *dest, u_char *start, u_char *roof, - const struct state *st, const msgid_t *msgid, - bool hash2) -{ - chunk_t msgid_chunk = chunk_from_thing(*msgid); - chunk_t msg_chunk = { start, roof - start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - size_t prf_block_size; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - if (hash2) - { - prf->get_bytes(prf, st->st_ni, NULL); /* include Ni_b in the hash */ - } - prf->get_bytes(prf, msg_chunk, dest); - prf_block_size = prf->get_block_size(prf); - prf->destroy(prf); - - DBG(DBG_CRYPT, - DBG_log("HASH(%d) computed:", hash2 + 1); - DBG_dump("", dest, prf_block_size) - ) - return prf_block_size; -} - -/* Compute HASH(3) in Quick Mode (part of Quick I2 message). - * Used by: quick_inR1_outI2, quick_inI2 - * See RFC2409 "The Internet Key Exchange (IKE)" 5.5. - * NOTE: this hash (unlike HASH(1) and HASH(2)) ONLY covers the - * Message ID and Nonces. This is a mistake. - */ -static size_t quick_mode_hash3(u_char *dest, struct state *st) -{ - chunk_t seed_chunk = chunk_from_chars(0x00); - chunk_t msgid_chunk = chunk_from_thing(st->st_msgid); - pseudo_random_function_t prf_alg; - prf_t *prf; - size_t prf_block_size; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, seed_chunk, NULL ); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, st->st_ni, NULL); - prf->get_bytes(prf, st->st_nr, dest); - prf_block_size = prf->get_block_size(prf); - prf->destroy(prf); - - DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, prf_block_size); - return prf_block_size; -} - -/* Compute Phase 2 IV. - * Uses Phase 1 IV from st_iv; puts result in st_new_iv. - */ -void init_phase2_iv(struct state *st, const msgid_t *msgid) -{ - chunk_t iv_chunk = { st->st_ph1_iv, st->st_ph1_iv_len }; - chunk_t msgid_chunk = chunk_from_thing(*msgid); - hash_algorithm_t hash_alg; - hasher_t *hasher; - - hash_alg = oakley_to_hash_algorithm(st->st_oakley.hash); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - - DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:", - st->st_ph1_iv, st->st_ph1_iv_len); - - st->st_new_iv_len = hasher->get_hash_size(hasher); - passert(st->st_new_iv_len <= sizeof(st->st_new_iv)); - - hasher->get_hash(hasher, iv_chunk, NULL); - hasher->get_hash(hasher, msgid_chunk, st->st_new_iv); - hasher->destroy(hasher); - - DBG_cond_dump(DBG_CRYPT, "computed Phase 2 IV:", - st->st_new_iv, st->st_new_iv_len); -} - -/* Initiate quick mode. - * --> HDR*, HASH(1), SA, Nr [, KE ] [, IDci, IDcr ] - * (see RFC 2409 "IKE" 5.5) - * Note: this is not called from demux.c - */ - -static bool emit_subnet_id(ip_subnet *net, u_int8_t np, u_int8_t protoid, - u_int16_t port, pb_stream *outs) -{ - struct isakmp_ipsec_id id; - pb_stream id_pbs; - ip_address ta; - const unsigned char *tbp; - size_t tal; - - id.isaiid_np = np; - id.isaiid_idtype = subnetishost(net) - ? aftoinfo(subnettypeof(net))->id_addr - : aftoinfo(subnettypeof(net))->id_subnet; - id.isaiid_protoid = protoid; - id.isaiid_port = port; - - if (!out_struct(&id, &isakmp_ipsec_identification_desc, outs, &id_pbs)) - { - return FALSE; - } - networkof(net, &ta); - tal = addrbytesptr(&ta, &tbp); - if (!out_raw(tbp, tal, &id_pbs, "client network")) - { - return FALSE; - } - if (!subnetishost(net)) - { - maskof(net, &ta); - tal = addrbytesptr(&ta, &tbp); - if (!out_raw(tbp, tal, &id_pbs, "client mask")) - { - return FALSE; - } - } - close_output_pbs(&id_pbs); - return TRUE; -} - -stf_status quick_outI1(int whack_sock, struct state *isakmp_sa, - connection_t *c, lset_t policy, unsigned long try, - so_serial_t replacing) -{ - struct state *st = duplicate_state(isakmp_sa); - pb_stream reply; /* not really a reply */ - pb_stream rbody; - u_char /* set by START_HASH_PAYLOAD: */ - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - bool has_client = c->spd.this.has_client || c->spd.that.has_client || - c->spd.this.protocol || c->spd.that.protocol || - c->spd.this.port || c->spd.that.port; - bool send_natoa = FALSE; - u_int8_t np = ISAKMP_NEXT_NONE; - connection_t *ph1_c = isakmp_sa->st_connection; - - if (c->spd.this.modecfg && !c->spd.this.has_client && - c->spd.this.host_srcip->is_anyaddr(c->spd.this.host_srcip)) - { - host_t * ph1_srcip = ph1_c->spd.this.host_srcip; - - if (ph1_c->spd.this.modecfg && !ph1_srcip->is_anyaddr(ph1_srcip)) - { - c->spd.this.host_srcip->destroy(c->spd.this.host_srcip); - c->spd.this.host_srcip = ph1_srcip->clone(ph1_srcip); - c->spd.this.client = ph1_c->spd.this.client; - c->spd.this.has_client = TRUE; - plog("inheriting virtual IP source address %H from ModeCfg", ph1_srcip); - } - } - - if (ph1_c->policy & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK) && - ph1_c->xauth_identity && !c->xauth_identity) - { - DBG(DBG_CONTROL, - DBG_log("inheriting XAUTH identity %Y", ph1_c->xauth_identity) - ) - c->xauth_identity = ph1_c->xauth_identity->clone(ph1_c->xauth_identity); - } - - st->st_whack_sock = whack_sock; - st->st_connection = c; - set_cur_state(st); /* we must reset before exit */ - st->st_policy = policy; - st->st_try = try; - - st->st_myuserprotoid = c->spd.this.protocol; - st->st_peeruserprotoid = c->spd.that.protocol; - st->st_myuserport = c->spd.this.port; - st->st_peeruserport = c->spd.that.port; - - st->st_msgid = generate_msgid(isakmp_sa); - st->st_state = STATE_QUICK_I1; - - insert_state(st); /* needs cookies, connection, and msgid */ - - if (replacing == SOS_NOBODY) - { - plog("initiating Quick Mode %s {using isakmp#%lu}", - prettypolicy(policy), isakmp_sa->st_serialno); - } - else - { - plog("initiating Quick Mode %s to replace #%lu {using isakmp#%lu}", - prettypolicy(policy), replacing, isakmp_sa->st_serialno); - } - if (isakmp_sa->nat_traversal & NAT_T_DETECTED) - { - /* Duplicate nat_traversal status in new state */ - st->nat_traversal = isakmp_sa->nat_traversal; - - if (isakmp_sa->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) - { - has_client = TRUE; - } - nat_traversal_change_port_lookup(NULL, st); - } - else - { - st->nat_traversal = 0; - } - - /* are we going to send a NAT-OA payload? */ - if ((st->nat_traversal & NAT_T_WITH_NATOA) - && !(st->st_policy & POLICY_TUNNEL) - && (st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))) - { - send_natoa = TRUE; - np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ? - ISAKMP_NEXT_NATOA_RFC : ISAKMP_NEXT_NATOA_DRAFTS; - } - - /* set up reply */ - init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet"); - - /* HDR* out */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_QUICK; - hdr.isa_msgid = st->st_msgid; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* HASH(1) -- create and note space to be filled later */ - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA); - - /* SA out */ - - /* - * See if pfs_group has been specified for this conn, - * if not, fallback to old use-same-as-P1 behaviour - */ -#ifndef NO_IKE_ALG - if (st->st_connection) - { - st->st_pfs_group = ike_alg_pfsgroup(st->st_connection, policy); - } - if (!st->st_pfs_group) -#endif - /* If PFS specified, use the same group as during Phase 1: - * since no negotiation is possible, we pick one that is - * very likely supported. - */ - st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL; - - /* Emit SA payload based on a subset of the policy bits. - * POLICY_COMPRESS is considered iff we can do IPcomp. - */ - { - lset_t pm = POLICY_ENCRYPT | POLICY_AUTHENTICATE; - - if (can_do_IPcomp) - { - pm |= POLICY_COMPRESS; - } - if (!out_sa(&rbody, - &ipsec_sadb[(st->st_policy & pm) >> POLICY_IPSEC_SHIFT], - st, FALSE, ISAKMP_NEXT_NONCE)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Ni out */ - if (!build_and_ship_nonce(&st->st_ni, &rbody - , policy & POLICY_PFS? ISAKMP_NEXT_KE : has_client? ISAKMP_NEXT_ID : np - , "Ni")) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - - /* [ KE ] out (for PFS) */ - - if (st->st_pfs_group != NULL) - { - if (!build_and_ship_KE(st, &st->st_gi, st->st_pfs_group - , &rbody, has_client? ISAKMP_NEXT_ID : np)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* [ IDci, IDcr ] out */ - if (has_client) - { - /* IDci (we are initiator), then IDcr (peer is responder) */ - if (!emit_subnet_id(&c->spd.this.client - , ISAKMP_NEXT_ID, st->st_myuserprotoid, st->st_myuserport, &rbody) - || !emit_subnet_id(&c->spd.that.client - , np, st->st_peeruserprotoid, st->st_peeruserport, &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Send NAT-OA if our address is NATed */ - if (send_natoa) - { - if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &rbody, st)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* finish computing HASH(1), inserting it in output */ - (void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur - , st, &st->st_msgid, FALSE); - - /* encrypt message, except for fixed part of header */ - - init_phase2_iv(isakmp_sa, &st->st_msgid); - st->st_new_iv_len = isakmp_sa->st_new_iv_len; - memcpy(st->st_new_iv, isakmp_sa->st_new_iv, st->st_new_iv_len); - - if (!encrypt_message(&rbody, st)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - - /* save packet, now that we know its size */ - st->st_tpacket = chunk_create(reply.start, pbs_offset(&reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - /* send the packet */ - - send_packet(st, "quick_outI1"); - - delete_event(st); - event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); - - if (replacing == SOS_NOBODY) - { - whack_log(RC_NEW_STATE + STATE_QUICK_I1 - , "%s: initiate" - , enum_name(&state_names, st->st_state)); - } - else - { - whack_log(RC_NEW_STATE + STATE_QUICK_I1 - , "%s: initiate to replace #%lu" - , enum_name(&state_names, st->st_state) - , replacing); - } - reset_cur_state(); - return STF_OK; -} - - -/* - * Decode the CERT payload of Phase 1. - */ -static void decode_cert(struct msg_digest *md) -{ - struct payload_digest *p; - - for (p = md->chain[ISAKMP_NEXT_CERT]; p != NULL; p = p->next) - { - struct isakmp_cert *const cert = &p->payload.cert; - chunk_t blob; - time_t valid_until; - blob.ptr = p->pbs.cur; - blob.len = pbs_left(&p->pbs); - if (cert->isacert_type == CERT_X509_SIGNATURE) - { - cert_t x509cert = cert_empty; - - x509cert.cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, blob, - BUILD_END); - if (x509cert.cert) - { - if (verify_x509cert(&x509cert, strict_crl_policy, &valid_until)) - { - DBG(DBG_PARSING, - DBG_log("Public key validated") - ) - add_public_key_from_cert(&x509cert, valid_until, DAL_SIGNED); - } - else - { - plog("X.509 certificate rejected"); - } - x509cert.cert->destroy(x509cert.cert); - } - else - { - plog("Syntax error in X.509 certificate"); - } - } - else if (cert->isacert_type == CERT_PKCS7_WRAPPED_X509) - { - linked_list_t *certs = linked_list_create(); - - if (pkcs7_parse_signedData(blob, NULL, certs, NULL, NULL)) - { - store_x509certs(certs, strict_crl_policy); - } - else - { - plog("Syntax error in PKCS#7 wrapped X.509 certificates"); - } - certs->destroy_offset(certs, offsetof(certificate_t, destroy)); - } - else - { - loglog(RC_LOG_SERIOUS, "ignoring %s certificate payload", - enum_show(&cert_type_names, cert->isacert_type)); - DBG_cond_dump_chunk(DBG_PARSING, "CERT:\n", blob); - } - } -} - -/* - * Decode the CR payload of Phase 1. - */ -static void decode_cr(struct msg_digest *md, connection_t *c) -{ - struct payload_digest *p; - - for (p = md->chain[ISAKMP_NEXT_CR]; p != NULL; p = p->next) - { - struct isakmp_cr *const cr = &p->payload.cr; - chunk_t ca_name; - - ca_name.len = pbs_left(&p->pbs); - ca_name.ptr = (ca_name.len > 0)? p->pbs.cur : NULL; - - DBG_cond_dump_chunk(DBG_PARSING, "CR", ca_name); - - if (cr->isacr_type == CERT_X509_SIGNATURE) - { - if (ca_name.len > 0) - { - identification_t *ca; - - if (!is_asn1(ca_name)) - { - continue; - } - if (c->requested_ca == NULL) - { - c->requested_ca = linked_list_create(); - } - ca = identification_create_from_encoding(ID_DER_ASN1_DN, ca_name); - c->requested_ca->insert_last(c->requested_ca, ca); - DBG(DBG_PARSING | DBG_CONTROL, - DBG_log("requested CA: \"%Y\"", ca) - ) - } - else - { - DBG(DBG_PARSING | DBG_CONTROL, - DBG_log("requested CA: %%any") - ) - } - c->got_certrequest = TRUE; - } - else - { - loglog(RC_LOG_SERIOUS, "ignoring %s certificate request payload", - enum_show(&cert_type_names, cr->isacr_type)); - } - } -} - -/* Decode the ID payload of Phase 1 (main_inI3_outR3 and main_inR3) - * Note: we may change connections as a result. - * We must be called before SIG or HASH are decoded since we - * may change the peer's public key or ID. - */ -static bool decode_peer_id(struct msg_digest *md, identification_t **peer) -{ - struct state *const st = md->st; - struct payload_digest *const id_pld = md->chain[ISAKMP_NEXT_ID]; - const pb_stream *const id_pbs = &id_pld->pbs; - struct isakmp_id *const id = &id_pld->payload.id; - chunk_t id_payload; - - /* I think that RFC2407 (IPSEC DOI) 4.6.2 is confused. - * It talks about the protocol ID and Port fields of the ID - * Payload, but they don't exist as such in Phase 1. - * We use more appropriate names. - * isaid_doi_specific_a is in place of Protocol ID. - * isaid_doi_specific_b is in place of Port. - * Besides, there is no good reason for allowing these to be - * other than 0 in Phase 1. - */ - if ((st->nat_traversal & NAT_T_WITH_PORT_FLOATING) - && id->isaid_doi_specific_a == IPPROTO_UDP - && (id->isaid_doi_specific_b == 0 || id->isaid_doi_specific_b == NAT_T_IKE_FLOAT_PORT)) - { - DBG_log("protocol/port in Phase 1 ID Payload is %d/%d. " - "accepted with port_floating NAT-T", - id->isaid_doi_specific_a, id->isaid_doi_specific_b); - } - else if (!(id->isaid_doi_specific_a == 0 && id->isaid_doi_specific_b == 0) - && !(id->isaid_doi_specific_a == IPPROTO_UDP && id->isaid_doi_specific_b == IKE_UDP_PORT)) - { - loglog(RC_LOG_SERIOUS, "protocol/port in Phase 1 ID Payload must be 0/0 or %d/%d" - " but are %d/%d" - , IPPROTO_UDP, IKE_UDP_PORT - , id->isaid_doi_specific_a, id->isaid_doi_specific_b); - return FALSE; - } - - id_payload = chunk_create(id_pbs->cur, pbs_left(id_pbs)); - - switch (id->isaid_idtype) - { - case ID_IPV4_ADDR: - if (id_payload.len != 4) - { - loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - break; - case ID_IPV6_ADDR: - if (id_payload.len != 16) - { - loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - break; - case ID_USER_FQDN: - case ID_FQDN: - if (memchr(id_payload.ptr, '\0', id_payload.len) != NULL) - { - loglog(RC_LOG_SERIOUS, "%s Phase 1 ID payload contains " - "a NUL character", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - break; - case ID_KEY_ID: - case ID_DER_ASN1_DN: - break; - default: - /* XXX Could send notification back */ - loglog(RC_LOG_SERIOUS, "unacceptable identity type (%s) " - "in Phase 1 ID payload", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - *peer = identification_create_from_encoding(id->isaid_idtype, id_payload); - - plog("Peer ID is %s: '%Y'", enum_show(&ident_names, id->isaid_idtype), - *peer); - - /* check for certificates */ - decode_cert(md); - return TRUE; -} - -/* Now that we've decoded the ID payload, let's see if we - * need to switch connections. - * We must not switch horses if we initiated: - * - if the initiation was explicit, we'd be ignoring user's intent - * - if opportunistic, we'll lose our HOLD info - */ -static bool switch_connection(struct msg_digest *md, identification_t *peer, - bool initiator) -{ - struct state *const st = md->st; - connection_t *c = st->st_connection; - identification_t *peer_ca; - - peer_ca = st->st_peer_pubkey ? st->st_peer_pubkey->issuer : NULL; - if (peer_ca) - { - DBG(DBG_CONTROL, - DBG_log("peer CA: \"%Y\"", peer_ca) - ) - } - else - { - DBG(DBG_CONTROL, - DBG_log("peer CA: %%none") - ) - } - - if (initiator) - { - int pathlen; - - if (!peer->equals(peer, c->spd.that.id)) - { - loglog(RC_LOG_SERIOUS, - "we require peer to have ID '%Y', but peer declares '%Y'", - c->spd.that.id, peer); - return FALSE; - } - - if (c->spd.that.ca) - { - DBG(DBG_CONTROL, - DBG_log("required CA: \"%s\"", c->spd.that.ca); - ) - } - else - { - DBG(DBG_CONTROL, - DBG_log("required CA: %%none"); - ) - } - - if (!trusted_ca(peer_ca, c->spd.that.ca, &pathlen)) - { - loglog(RC_LOG_SERIOUS - , "we don't accept the peer's CA"); - return FALSE; - } - } - else - { - connection_t *r; - - /* check for certificate requests */ - decode_cr(md, c); - - r = refine_host_connection(st, peer, peer_ca); - - /* delete the collected certificate requests */ - if (c->requested_ca) - { - c->requested_ca->destroy_offset(c->requested_ca, - offsetof(identification_t, destroy)); - c->requested_ca = NULL; - } - - if (r == NULL) - { - loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%Y'", peer); - return FALSE; - } - - if (r->spd.this.ca) - { - DBG(DBG_CONTROL, - DBG_log("offered CA: \"%Y\"", r->spd.this.ca) - ) - } - else - { - DBG(DBG_CONTROL, - DBG_log("offered CA: %%none") - ) - } - - if (r != c) - { - /* apparently, r is an improvement on c -- replace */ - - DBG(DBG_CONTROL - , DBG_log("switched from \"%s\" to \"%s\"", c->name, r->name)); - if (r->kind == CK_TEMPLATE) - { - /* instantiate it, filling in peer's ID */ - r = rw_instantiate(r, &c->spd.that.host_addr - , c->spd.that.host_port, NULL, peer); - } - - /* copy certificate request info */ - r->got_certrequest = c->got_certrequest; - - st->st_connection = r; /* kill reference to c */ - set_cur_connection(r); - connection_discard(c); - } - else if (c->spd.that.has_id_wildcards) - { - c->spd.that.id->destroy(c->spd.that.id); - c->spd.that.id = peer->clone(peer); - c->spd.that.has_id_wildcards = FALSE; - } - } - return TRUE; -} - -/* Decode the variable part of an ID packet (during Quick Mode). - * This is designed for packets that identify clients, not peers. - * Rejects 0.0.0.0/32 or IPv6 equivalent because - * (1) it is wrong and (2) we use this value for inband signalling. - */ -static bool decode_net_id(struct isakmp_ipsec_id *id, pb_stream *id_pbs, - ip_subnet *net, const char *which) -{ - const struct af_info *afi = NULL; - - /* Note: the following may be a pointer into static memory - * that may be recycled, but only if the type is not known. - * That case is disposed of very early -- in the first switch. - */ - const char *idtypename = enum_show(&ident_names, id->isaiid_idtype); - - switch (id->isaiid_idtype) - { - case ID_IPV4_ADDR: - case ID_IPV4_ADDR_SUBNET: - case ID_IPV4_ADDR_RANGE: - afi = &af_inet4_info; - break; - case ID_IPV6_ADDR: - case ID_IPV6_ADDR_SUBNET: - case ID_IPV6_ADDR_RANGE: - afi = &af_inet6_info; - break; - case ID_FQDN: - return TRUE; - default: - /* XXX support more */ - loglog(RC_LOG_SERIOUS, "unsupported ID type %s" - , idtypename); - /* XXX Could send notification back */ - return FALSE; - } - - switch (id->isaiid_idtype) - { - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - { - ip_address temp_address; - err_t ugh; - - ugh = initaddr(id_pbs->cur, pbs_left(id_pbs), afi->af, &temp_address); - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s has wrong length in Quick I1 (%s)" - , which, idtypename, ugh); - /* XXX Could send notification back */ - return FALSE; - } - if (isanyaddr(&temp_address)) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s is invalid (%s) in Quick I1" - , which, idtypename, ip_str(&temp_address)); - /* XXX Could send notification back */ - return FALSE; - } - happy(addrtosubnet(&temp_address, net)); - DBG(DBG_PARSING | DBG_CONTROL - , DBG_log("%s is %s", which, ip_str(&temp_address))); - break; - } - - case ID_IPV4_ADDR_SUBNET: - case ID_IPV6_ADDR_SUBNET: - { - ip_address temp_address, temp_mask; - err_t ugh; - - if (pbs_left(id_pbs) != 2 * afi->ia_sz) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1" - , which, idtypename); - /* XXX Could send notification back */ - return FALSE; - } - ugh = initaddr(id_pbs->cur - , afi->ia_sz, afi->af, &temp_address); - if (ugh == NULL) - { - ugh = initaddr(id_pbs->cur + afi->ia_sz - , afi->ia_sz, afi->af, &temp_mask); - } - if (ugh == NULL) - { - ugh = initsubnet(&temp_address, masktocount(&temp_mask) - , '0', net); - } - if (ugh == NULL && subnetisnone(net)) - { - ugh = "contains only anyaddr"; - } - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s bad subnet in Quick I1 (%s)" - , which, idtypename, ugh); - /* XXX Could send notification back */ - return FALSE; - } - DBG(DBG_PARSING | DBG_CONTROL, - { - char temp_buff[SUBNETTOT_BUF]; - - subnettot(net, 0, temp_buff, sizeof(temp_buff)); - DBG_log("%s is subnet %s", which, temp_buff); - }); - break; - } - - case ID_IPV4_ADDR_RANGE: - case ID_IPV6_ADDR_RANGE: - { - ip_address temp_address_from, temp_address_to; - err_t ugh; - - if (pbs_left(id_pbs) != 2 * afi->ia_sz) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1" - , which, idtypename); - /* XXX Could send notification back */ - return FALSE; - } - ugh = initaddr(id_pbs->cur, afi->ia_sz, afi->af, &temp_address_from); - if (ugh == NULL) - { - ugh = initaddr(id_pbs->cur + afi->ia_sz - , afi->ia_sz, afi->af, &temp_address_to); - } - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s malformed (%s) in Quick I1" - , which, idtypename, ugh); - /* XXX Could send notification back */ - return FALSE; - } - - ugh = rangetosubnet(&temp_address_from, &temp_address_to, net); - if (ugh == NULL && subnetisnone(net)) - { - ugh = "contains only anyaddr"; - } - if (ugh != NULL) - { - char temp_buff1[ADDRTOT_BUF], temp_buff2[ADDRTOT_BUF]; - - addrtot(&temp_address_from, 0, temp_buff1, sizeof(temp_buff1)); - addrtot(&temp_address_to, 0, temp_buff2, sizeof(temp_buff2)); - loglog(RC_LOG_SERIOUS, "%s ID payload in Quick I1, %s" - " %s - %s unacceptable: %s" - , which, idtypename, temp_buff1, temp_buff2, ugh); - return FALSE; - } - DBG(DBG_PARSING | DBG_CONTROL, - { - char temp_buff[SUBNETTOT_BUF]; - - subnettot(net, 0, temp_buff, sizeof(temp_buff)); - DBG_log("%s is subnet %s (received as range)" - , which, temp_buff); - }); - break; - } - } - - /* set the port selector */ - setportof(htons(id->isaiid_port), &net->addr); - - DBG(DBG_PARSING | DBG_CONTROL, - DBG_log("%s protocol/port is %d/%d", which, id->isaiid_protoid, id->isaiid_port) - ) - - return TRUE; -} - -/* like decode, but checks that what is received matches what was sent */ -static bool check_net_id(struct isakmp_ipsec_id *id, pb_stream *id_pbs, - u_int8_t *protoid, u_int16_t *port, ip_subnet *net, - const char *which) -{ - ip_subnet net_temp; - - if (!decode_net_id(id, id_pbs, &net_temp, which)) - { - return FALSE; - } - if (!samesubnet(net, &net_temp) - || *protoid != id->isaiid_protoid || *port != id->isaiid_port) - { - loglog(RC_LOG_SERIOUS, "%s ID returned doesn't match my proposal", which); - return FALSE; - } - return TRUE; -} - -/* - * look for the existence of a non-expiring preloaded public key - */ -static bool has_preloaded_public_key(struct state *st) -{ - connection_t *c = st->st_connection; - - /* do not consider rw connections since - * the peer's identity must be known - */ - if (c->kind == CK_PERMANENT) - { - pubkey_list_t *p; - - /* look for a matching RSA public key */ - for (p = pubkeys; p != NULL; p = p->next) - { - pubkey_t *key = p->key; - key_type_t type = key->public_key->get_type(key->public_key); - - if (type == KEY_RSA && - c->spd.that.id->equals(c->spd.that.id, key->id) && - key->until_time == UNDEFINED_TIME) - { - /* found a preloaded public key */ - return TRUE; - } - } - } - return FALSE; -} - -/* Compute keying material for an SA - */ -static void compute_keymat_internal(struct state *st, u_int8_t protoid, - ipsec_spi_t spi, size_t needed_len, - u_char **keymat_out) -{ - size_t i = 0, prf_block_size, needed_space; - chunk_t protoid_chunk = chunk_from_thing(protoid); - chunk_t spi_chunk = chunk_from_thing(spi); - pseudo_random_function_t prf_alg = oakley_to_prf(st->st_oakley.hash); - prf_t *prf = lib->crypto->create_prf(lib->crypto, prf_alg); - - prf->set_key(prf, st->st_skeyid_d); - prf_block_size = prf->get_block_size(prf); - - /* Although only needed_len bytes are desired, we must round up to a - * multiple of prf_block_size so that the buffer isn't overrun */ - needed_space = needed_len + pad_up(needed_len, prf_block_size); - replace(*keymat_out, malloc(needed_space)); - - for (;;) - { - char *keymat_i = (*keymat_out) + i; - chunk_t keymat = { keymat_i, prf_block_size }; - - if (st->st_shared.ptr != NULL) - { /* PFS: include the g^xy */ - prf->get_bytes(prf, st->st_shared, NULL); - } - prf->get_bytes(prf, protoid_chunk, NULL); - prf->get_bytes(prf, spi_chunk, NULL); - prf->get_bytes(prf, st->st_ni, NULL); - prf->get_bytes(prf, st->st_nr, keymat_i); - - i += prf_block_size; - if (i >= needed_space) - { - break; - } - - /* more keying material needed: prepare to go around again */ - prf->get_bytes(prf, keymat, NULL); - } - prf->destroy(prf); -} - -/* - * Produce the new key material of Quick Mode. - * RFC 2409 "IKE" section 5.5 - * specifies how this is to be done. - */ -static void compute_proto_keymat(struct state *st, u_int8_t protoid, - struct ipsec_proto_info *pi, enum endpoint ep) -{ - size_t needed_len = 0; /* bytes of keying material needed */ - - /* Add up the requirements for keying material - * (It probably doesn't matter if we produce too much!) - */ - switch (protoid) - { - case PROTO_IPSEC_ESP: - { - needed_len = kernel_alg_esp_enc_keylen(pi->attrs.transid); - - if (needed_len && pi->attrs.key_len) - { - needed_len = pi->attrs.key_len / BITS_PER_BYTE; - } - - switch (pi->attrs.transid) - { - case ESP_NULL: - needed_len = 0; - break; - case ESP_AES_CCM_8: - case ESP_AES_CCM_12: - case ESP_AES_CCM_16: - needed_len += 3; - break; - case ESP_AES_GCM_8: - case ESP_AES_GCM_12: - case ESP_AES_GCM_16: - case ESP_AES_CTR: - case ESP_AES_GMAC: - needed_len += 4; - break; - default: - if (needed_len == 0) - { - bad_case(pi->attrs.transid); - } - } - - if (kernel_alg_esp_auth_ok(pi->attrs.auth, NULL)) - { - needed_len += kernel_alg_esp_auth_keylen(pi->attrs.auth); - } - else - { - switch (pi->attrs.auth) - { - case AUTH_ALGORITHM_NONE: - break; - case AUTH_ALGORITHM_HMAC_MD5: - needed_len += HMAC_MD5_KEY_LEN; - break; - case AUTH_ALGORITHM_HMAC_SHA1: - needed_len += HMAC_SHA1_KEY_LEN; - break; - case AUTH_ALGORITHM_DES_MAC: - default: - bad_case(pi->attrs.auth); - } - } - break; - } - case PROTO_IPSEC_AH: - { - switch (pi->attrs.transid) - { - case AH_MD5: - needed_len = HMAC_MD5_KEY_LEN; - break; - case AH_SHA: - needed_len = HMAC_SHA1_KEY_LEN; - break; - default: - bad_case(pi->attrs.transid); - } - break; - } - default: - bad_case(protoid); - } - - pi->keymat_len = needed_len; - - if (ep & EP_LOCAL) - { - compute_keymat_internal(st, protoid, pi->our_spi, needed_len, - &pi->our_keymat); - DBG(DBG_CRYPT, - DBG_dump("KEYMAT computed:\n", pi->our_keymat, - pi->keymat_len)); - } - if (ep & EP_REMOTE) - { - compute_keymat_internal(st, protoid, pi->attrs.spi, needed_len, - &pi->peer_keymat); - DBG(DBG_CRYPT, - DBG_dump("Peer KEYMAT computed:\n", pi->peer_keymat, - pi->keymat_len)); - } -} - -static void compute_keymats(struct state *st, enum endpoint ep) -{ - if (st->st_ah.present) - { - compute_proto_keymat(st, PROTO_IPSEC_AH, &st->st_ah, ep); - } - if (st->st_esp.present) - { - compute_proto_keymat(st, PROTO_IPSEC_ESP, &st->st_esp, ep); - } -} - -static void wipe_proto_keymat(struct ipsec_proto_info *pi, enum endpoint ep) -{ - if (ep & EP_LOCAL) - { - memwipe(pi->our_keymat, pi->keymat_len); - } - if (ep & EP_REMOTE) - { - memwipe(pi->peer_keymat, pi->keymat_len); - } -} - -static void wipe_keymats(struct state *st, enum endpoint ep) -{ - if (st->st_ah.present) - { - wipe_proto_keymat(&st->st_ah, ep); - } - if (st->st_esp.present) - { - wipe_proto_keymat(&st->st_esp, ep); - } -} - -static bool uses_pubkey_auth(int auth) -{ - switch (auth) - { - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - case XAUTHInitRSA: - case XAUTHRespRSA: - return TRUE; - default: - return FALSE; - } -} - -/* build an ID payload - * Note: no memory is allocated for the body of the payload (tl->ptr). - * We assume it will end up being a pointer into a sufficiently - * stable datastructure. It only needs to last a short time. - */ -static void build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end) -{ - identification_t *id = resolve_myid(end->id); - - zero(hd); - hd->isaiid_idtype = id->get_type(id); - - switch (id->get_type(id)) - { - case ID_ANY: - hd->isaiid_idtype = aftoinfo(addrtypeof(&end->host_addr))->id_addr; - tl->len = addrbytesptr(&end->host_addr, - (const unsigned char **)&tl->ptr); /* sets tl->ptr too */ - break; - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - case ID_FQDN: - case ID_USER_FQDN: - case ID_DER_ASN1_DN: - case ID_KEY_ID: - *tl = id->get_encoding(id); - break; - default: - bad_case(id->get_type(id)); - } -} - -/* State Transition Functions. - * - * The definition of state_microcode_table in demux.c is a good - * overview of these routines. - * - * - Called from process_packet; result handled by complete_state_transition - * - struct state_microcode member "processor" points to these - * - these routine definitionss are in state order - * - these routines must be restartable from any point of error return: - * beware of memory allocated before any error. - * - output HDR is usually emitted by process_packet (if state_microcode - * member first_out_payload isn't ISAKMP_NEXT_NONE). - * - * The transition functions' functions include: - * - process and judge payloads - * - update st_iv (result of decryption is in st_new_iv) - * - build reply packet - */ - -/* Handle a Main Mode Oakley first packet (responder side). - * HDR;SA --> HDR;SA - */ -stf_status main_inI1_outR1(struct msg_digest *md) -{ - struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; - struct state *st; - connection_t *c; - struct isakmp_proposal proposal; - pb_stream proposal_pbs; - pb_stream r_sa_pbs; - u_int32_t ipsecdoisit; - lset_t policy = LEMPTY; - int vids_to_send = 0; - - /* We preparse the peer's proposal in order to determine - * the requested authentication policy (RSA or PSK) - */ - RETURN_STF_FAILURE(preparse_isakmp_sa_body(&sa_pd->payload.sa - , &sa_pd->pbs, &ipsecdoisit, &proposal_pbs, &proposal)); - - backup_pbs(&proposal_pbs); - RETURN_STF_FAILURE(parse_isakmp_policy(&proposal_pbs - , proposal.isap_notrans, &policy)); - restore_pbs(&proposal_pbs); - - /* We are only considering candidate connections that match - * the requested authentication policy (RSA or PSK) - */ - c = find_host_connection(&md->iface->addr, pluto_port - , &md->sender, md->sender_port, policy); - - if (c == NULL && md->iface->ike_float) - { - c = find_host_connection(&md->iface->addr, NAT_T_IKE_FLOAT_PORT - , &md->sender, md->sender_port, policy); - } - - if (c == NULL) - { - /* See if a wildcarded connection can be found. - * We cannot pick the right connection, so we're making a guess. - * All Road Warrior connections are fair game: - * we pick the first we come across (if any). - * If we don't find any, we pick the first opportunistic - * with the smallest subnet that includes the peer. - * There is, of course, no necessary relationship between - * an Initiator's address and that of its client, - * but Food Groups kind of assumes one. - */ - { - connection_t *d; - - d = find_host_connection(&md->iface->addr - , pluto_port, (ip_address*)NULL, md->sender_port, policy); - - for (; d != NULL; d = d->hp_next) - { - if (d->kind == CK_GROUP) - { - /* ignore */ - } - else - { - if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO)) - { - /* must be Road Warrior: we have a winner */ - c = d; - break; - } - - /* Opportunistic or Shunt: pick tightest match */ - if (addrinsubnet(&md->sender, &d->spd.that.client) - && (c == NULL || !subnetinsubnet(&c->spd.that.client, &d->spd.that.client))) - c = d; - } - } - } - - if (c == NULL) - { - loglog(RC_LOG_SERIOUS, "initial Main Mode message received on %s:%u" - " but no connection has been authorized%s%s" - , ip_str(&md->iface->addr), ntohs(portof(&md->iface->addr)) - , (policy != LEMPTY) ? " with policy=" : "" - , (policy != LEMPTY) ? bitnamesof(sa_policy_bit_names, policy) : ""); - /* XXX notification is in order! */ - return STF_IGNORE; - } - else if (c->kind != CK_TEMPLATE) - { - loglog(RC_LOG_SERIOUS, "initial Main Mode message received on %s:%u" - " but \"%s\" forbids connection" - , ip_str(&md->iface->addr), pluto_port, c->name); - /* XXX notification is in order! */ - return STF_IGNORE; - } - else - { - /* Create a temporary connection that is a copy of this one. - * His ID isn't declared yet. - */ - c = rw_instantiate(c, &md->sender, md->sender_port, NULL, NULL); - } - } - else if (c->kind == CK_TEMPLATE) - { - /* Create an instance - * This is a rare case: wildcard peer ID but static peer IP address - */ - c = rw_instantiate(c, &md->sender, md->sender_port, NULL, c->spd.that.id); - } - - /* Set up state */ - md->st = st = new_state(); - st->st_connection = c; - set_cur_state(st); /* (caller will reset cur_state) */ - st->st_try = 0; /* not our job to try again from start */ - st->st_policy = c->policy & ~POLICY_IPSEC_MASK; /* only as accurate as connection */ - - memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE); - get_cookie(FALSE, st->st_rcookie, COOKIE_SIZE, &md->sender); - - insert_state(st); /* needs cookies, connection, and msgid (0) */ - - st->st_doi = ISAKMP_DOI_IPSEC; - st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */ - - if ((c->kind == CK_INSTANCE) && (c->spd.that.host_port != pluto_port)) - { - plog("responding to Main Mode from unknown peer %s:%u" - , ip_str(&c->spd.that.host_addr), c->spd.that.host_port); - } - else if (c->kind == CK_INSTANCE) - { - plog("responding to Main Mode from unknown peer %s" - , ip_str(&c->spd.that.host_addr)); - } - else - { - plog("responding to Main Mode"); - } - - /* parse_isakmp_sa also spits out a winning SA into our reply, - * so we have to build our md->reply and emit HDR before calling it. - */ - - /* determine how many Vendor ID payloads we will be sending */ - if (SEND_PLUTO_VID) - { - vids_to_send++; - } - if (SEND_CISCO_UNITY_VID) - { - vids_to_send++; - } - if (md->openpgp) - { - vids_to_send++; - } - if (SEND_XAUTH_VID) - { - vids_to_send++; - } - /* always send DPD Vendor ID */ - vids_to_send++; - if (md->nat_traversal_vid && nat_traversal_enabled) - { - vids_to_send++; - } - - /* HDR out. - * We can't leave this to comm_handle() because we must - * fill in the cookie. - */ - { - struct isakmp_hdr r_hdr = md->hdr; - - r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT; /* we won't ever turn on this bit */ - memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - r_hdr.isa_np = ISAKMP_NEXT_SA; - if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody)) - return STF_INTERNAL_ERROR; - } - - /* start of SA out */ - { - struct isakmp_sa r_sa = sa_pd->payload.sa; - - r_sa.isasa_np = vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; - - if (!out_struct(&r_sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs)) - return STF_INTERNAL_ERROR; - } - - /* SA body in and out */ - RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit, &proposal_pbs - ,&proposal, &r_sa_pbs, st, FALSE)); - - /* if enabled send Pluto Vendor ID */ - if (SEND_PLUTO_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_STRONGSWAN)) - { - return STF_INTERNAL_ERROR; - } - } - - /* if enabled send Cisco Unity Vendor ID */ - if (SEND_CISCO_UNITY_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_CISCO_UNITY)) - { - return STF_INTERNAL_ERROR; - } - } - - /* - * if the peer sent an OpenPGP Vendor ID we offer the same capability - */ - if (md->openpgp) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_OPENPGP)) - { - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do eXtended AUTHentication to the peer */ - if (SEND_XAUTH_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_MISC_XAUTH)) - { - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do Dead Peer Detection to the peer */ - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_MISC_DPD)) - { - return STF_INTERNAL_ERROR; - } - - if (md->nat_traversal_vid && nat_traversal_enabled) - { - /* reply if NAT-Traversal draft is supported */ - st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid); - - if (st->nat_traversal - && !out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, md->nat_traversal_vid)) - { - return STF_INTERNAL_ERROR; - } - } - - close_message(&md->rbody); - - /* save initiator SA for HASH */ - free(st->st_p1isa.ptr); - st->st_p1isa = chunk_create(sa_pd->pbs.start, pbs_room(&sa_pd->pbs)); - st->st_p1isa = chunk_clone(st->st_p1isa); - - return STF_OK; -} - -/* STATE_MAIN_I1: HDR, SA --> auth dependent - * PSK_AUTH, DS_AUTH: --> HDR, KE, Ni - * - * The following are not yet implemented: - * PKE_AUTH: --> HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r - * RPKE_AUTH: --> HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i, - * <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i] - * - * We must verify that the proposal received matches one we sent. - */ -stf_status main_inR1_outI2(struct msg_digest *md) -{ - struct state *const st = md->st; - - u_int8_t np = ISAKMP_NEXT_NONE; - - /* verify echoed SA */ - { - u_int32_t ipsecdoisit; - pb_stream proposal_pbs; - struct isakmp_proposal proposal; - struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; - - RETURN_STF_FAILURE(preparse_isakmp_sa_body(&sapd->payload.sa - ,&sapd->pbs, &ipsecdoisit, &proposal_pbs, &proposal)); - if (proposal.isap_notrans != 1) - { - loglog(RC_LOG_SERIOUS, "a single Transform is required in a selecting Oakley Proposal; found %u" - , (unsigned)proposal.isap_notrans); - RETURN_STF_FAILURE(ISAKMP_BAD_PROPOSAL_SYNTAX); - } - RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit - , &proposal_pbs, &proposal, NULL, st, TRUE)); - } - - if (nat_traversal_enabled && md->nat_traversal_vid) - { - st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid); - plog("enabling possible NAT-traversal with method %s" - , bitnamesof(natt_type_bitnames, st->nat_traversal)); - } - if (st->nat_traversal & NAT_T_WITH_NATD) - { - np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ? - ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS; - } - - /**************** build output packet HDR;KE;Ni ****************/ - - /* HDR out. - * We can't leave this to comm_handle() because the isa_np - * depends on the type of Auth (eventually). - */ - echo_hdr(md, FALSE, ISAKMP_NEXT_KE); - - /* KE out */ - if (!build_and_ship_KE(st, &st->st_gi, st->st_oakley.group - , &md->rbody, ISAKMP_NEXT_NONCE)) - { - return STF_INTERNAL_ERROR; - } - -#ifdef DEBUG - /* Ni out */ - if (!build_and_ship_nonce(&st->st_ni, &md->rbody - , (cur_debugging & IMPAIR_BUST_MI2)? ISAKMP_NEXT_VID : np, "Ni")) - { - return STF_INTERNAL_ERROR; - } - if (cur_debugging & IMPAIR_BUST_MI2) - { - /* generate a pointless large VID payload to push message over MTU */ - pb_stream vid_pbs; - - if (!out_generic(np, &isakmp_vendor_id_desc, &md->rbody, &vid_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&vid_pbs); - } -#else - /* Ni out */ - if (!build_and_ship_nonce(&st->st_ni, &md->rbody, np, "Ni")) - { - return STF_INTERNAL_ERROR; - } -#endif - - if (st->nat_traversal & NAT_T_WITH_NATD) - { - if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md)) - { - return STF_INTERNAL_ERROR; - } - } - - /* finish message */ - close_message(&md->rbody); - - /* Reinsert the state, using the responder cookie we just received */ - unhash_state(st); - memcpy(st->st_rcookie, md->hdr.isa_rcookie, COOKIE_SIZE); - insert_state(st); /* needs cookies, connection, and msgid (0) */ - - return STF_OK; -} - -/* STATE_MAIN_R1: - * PSK_AUTH, DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr - * - * The following are not yet implemented: - * PKE_AUTH: HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r - * --> HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i - * RPKE_AUTH: - * HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i, <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i] - * --> HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r - */ -stf_status main_inI2_outR2(struct msg_digest *md) -{ - struct state *const st = md->st; - pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs; - - /* send CR if auth is RSA or ECDSA and no preloaded public key exists*/ - bool pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); - bool send_cr = !no_cr_send && pubkey_auth && !has_preloaded_public_key(st); - - u_int8_t np = ISAKMP_NEXT_NONE; - - /* KE in */ - RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs)); - - /* Ni in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); - - if (st->nat_traversal & NAT_T_WITH_NATD) - { - nat_traversal_natd_lookup(md); - - np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ? - ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS; - } - if (st->nat_traversal) - { - nat_traversal_show_result(st->nat_traversal, md->sender_port); - } - if (st->nat_traversal & NAT_T_WITH_KA) - { - nat_traversal_new_ka_event(); - } - - /* decode certificate requests */ - st->st_connection->got_certrequest = FALSE; - decode_cr(md, st->st_connection); - - /**************** build output packet HDR;KE;Nr ****************/ - - /* HDR out done */ - - /* KE out */ - if (!build_and_ship_KE(st, &st->st_gr, st->st_oakley.group - , &md->rbody, ISAKMP_NEXT_NONCE)) - { - return STF_INTERNAL_ERROR; - } - -#ifdef DEBUG - /* Nr out */ - if (!build_and_ship_nonce(&st->st_nr, &md->rbody, - (cur_debugging & IMPAIR_BUST_MR2)? ISAKMP_NEXT_VID - : (send_cr? ISAKMP_NEXT_CR : np), "Nr")) - { - return STF_INTERNAL_ERROR; - } - if (cur_debugging & IMPAIR_BUST_MR2) - { - /* generate a pointless large VID payload to push message over MTU */ - pb_stream vid_pbs; - - if (!out_generic((send_cr)? ISAKMP_NEXT_CR : np, - &isakmp_vendor_id_desc, &md->rbody, &vid_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&vid_pbs); - } -#else - /* Nr out */ - if (!build_and_ship_nonce(&st->st_nr, &md->rbody, - (send_cr)? ISAKMP_NEXT_CR : np, "Nr")) - return STF_INTERNAL_ERROR; -#endif - - /* CR out */ - if (send_cr) - { - if (st->st_connection->kind == CK_PERMANENT) - { - identification_t *ca = st->st_connection->spd.that.ca; - chunk_t cr = (ca) ? ca->get_encoding(ca) : chunk_empty; - - if (!build_and_ship_CR(CERT_X509_SIGNATURE, cr, &md->rbody, np)) - { - return STF_INTERNAL_ERROR; - } - } - else - { - linked_list_t *list = collect_rw_ca_candidates(md); - int count = list->get_count(list); - bool error = FALSE; - - if (count) - { - enumerator_t *enumerator; - identification_t *ca; - - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &ca)) - { - if (!build_and_ship_CR(CERT_X509_SIGNATURE, - ca->get_encoding(ca), &md->rbody, - --count ? ISAKMP_NEXT_CR : np)) - { - error = TRUE; - break; - } - } - enumerator->destroy(enumerator); - } - else - { - if (!build_and_ship_CR(CERT_X509_SIGNATURE, chunk_empty, - &md->rbody, np)) - { - error = TRUE; - } - } - list->destroy_offset(list, offsetof(identification_t, destroy)); - if (error) - { - return STF_INTERNAL_ERROR; - } - } - } - - if (st->nat_traversal & NAT_T_WITH_NATD) - { - if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md)) - { - return STF_INTERNAL_ERROR; - } - } - - /* finish message */ - close_message(&md->rbody); - - /* next message will be encrypted, but not this one. - * We could defer this calculation. - */ - compute_dh_shared(st, st->st_gi); - if (!generate_skeyids_iv(st)) - { - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - update_iv(st); - - return STF_OK; -} - -/* STATE_MAIN_I2: - * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I - * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I - * - * The following are not yet implemented. - * SMF_PKE_AUTH: HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i - * --> HDR*, HASH_I - * SMF_RPKE_AUTH: HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r - * --> HDR*, HASH_I - */ -stf_status main_inR2_outI3(struct msg_digest *md) -{ - struct state *const st = md->st; - pb_stream *const keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs; - pb_stream id_pbs; /* ID Payload; also used for hash calculation */ - - connection_t *c = st->st_connection; - certpolicy_t cert_policy = c->spd.this.sendcert; - cert_t *mycert = c->spd.this.cert; - bool requested, send_cert, send_cr; - bool pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); - - int auth_payload = pubkey_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH; - - /* KE in */ - RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, keyex_pbs)); - - /* Nr in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr")); - - /* decode certificate requests */ - c->got_certrequest = FALSE; - decode_cr(md, c); - - /* free collected certificate requests since as initiator - * we don't heed them anyway - */ - if (c->requested_ca) - { - c->requested_ca->destroy_offset(c->requested_ca, - offsetof(identification_t, destroy)); - c->requested_ca = NULL; - } - - /* send certificate if auth is RSA, we have one and we want - * or are requested to send it - */ - requested = cert_policy == CERT_SEND_IF_ASKED && c->got_certrequest; - send_cert = pubkey_auth && mycert && - mycert->cert->get_type(mycert->cert) == CERT_X509 && - (cert_policy == CERT_ALWAYS_SEND || requested); - - /* send certificate request if we don't have a preloaded RSA public key */ - send_cr = !no_cr_send && send_cert && !has_preloaded_public_key(st); - - /* done parsing; initialize crypto */ - compute_dh_shared(st, st->st_gr); - if (!generate_skeyids_iv(st)) - { - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - if (st->nat_traversal & NAT_T_WITH_NATD) - { - nat_traversal_natd_lookup(md); - } - if (st->nat_traversal) - { - nat_traversal_show_result(st->nat_traversal, md->sender_port); - } - if (st->nat_traversal & NAT_T_WITH_KA) - { - nat_traversal_new_ka_event(); - } - - /*************** build output packet HDR*;IDii;HASH/SIG_I ***************/ - /* ??? NOTE: this is almost the same as main_inI3_outR3's code */ - - /* HDR* out done */ - - /* IDii out */ - { - struct isakmp_ipsec_id id_hd; - chunk_t id_b; - - build_id_payload(&id_hd, &id_b, &c->spd.this); - id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : auth_payload; - if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &id_pbs) - || !out_chunk(id_b, &id_pbs, "my identity")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&id_pbs); - } - - /* CERT out */ - if (pubkey_auth) - { - DBG(DBG_CONTROL, - DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) - ) - if (mycert && mycert->cert->get_type(mycert->cert) == CERT_X509) - { - const char *request_text = ""; - - if (cert_policy == CERT_SEND_IF_ASKED) - { - request_text = (send_cert)? "upon request":"without request"; - } - plog("we have a cert %s sending it %s" - , send_cert? "and are":"but are not", request_text); - } - else - { - plog("we don't have a cert"); - } - } - if (send_cert) - { - bool success = FALSE; - chunk_t cert_encoding; - pb_stream cert_pbs; - - struct isakmp_cert cert_hd; - cert_hd.isacert_np = (send_cr)? ISAKMP_NEXT_CR : ISAKMP_NEXT_SIG; - cert_hd.isacert_type = CERT_X509_SIGNATURE; - - if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (mycert->cert->get_encoding(mycert->cert, CERT_ASN1_DER, - &cert_encoding)) - { - success = out_chunk(cert_encoding, &cert_pbs, "CERT"); - free(cert_encoding.ptr); - } - if (!success) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&cert_pbs); - } - - /* CR out */ - if (send_cr) - { - identification_t *ca = st->st_connection->spd.that.ca; - chunk_t cr = (ca) ? ca->get_encoding(ca) : chunk_empty; - - if (!build_and_ship_CR(CERT_X509_SIGNATURE, cr, &md->rbody, ISAKMP_NEXT_SIG)) - { - return STF_INTERNAL_ERROR; - } - } - - /* HASH_I or SIG_I out */ - { - chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); - - main_mode_hash(st, &hash, TRUE, &id_pbs); - - if (auth_payload == ISAKMP_NEXT_HASH) - { - /* HASH_I out */ - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody, - hash.ptr, hash.len, "HASH_I")) - { - return STF_INTERNAL_ERROR; - } - } - else - { - /* SIG_I out */ - u_char sig_val[RSA_MAX_OCTETS]; - signature_scheme_t scheme; - size_t sig_len; - - scheme = oakley_to_signature_scheme(st->st_oakley.auth); - - sig_len = sign_hash(scheme, c, sig_val, hash); - if (sig_len == 0) - { - loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature"); - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc - , &md->rbody, sig_val, sig_len, "SIG_I")) - { - return STF_INTERNAL_ERROR; - } - } - } - - /* encrypt message, except for fixed part of header */ - - /* st_new_iv was computed by generate_skeyids_iv */ - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - return STF_OK; -} - -/* Shared logic for asynchronous lookup of DNS KEY records. - * Used for STATE_MAIN_R2 and STATE_MAIN_I3. - */ - -enum key_oppo_step { - kos_null, - kos_his_txt -#ifdef USE_KEYRR - , kos_his_key -#endif -}; - -struct key_continuation { - struct adns_continuation ac; /* common prefix */ - struct msg_digest *md; - enum key_oppo_step step; - bool failure_ok; - err_t last_ugh; -}; - -typedef stf_status (key_tail_fn)(struct msg_digest *md - , struct key_continuation *kc); - -static void report_key_dns_failure(identification_t *id, err_t ugh) -{ - loglog(RC_LOG_SERIOUS, "no RSA public key known for '%Y'" - "; DNS search for KEY failed (%s)", id, ugh); -} - - -/* Processs the Main Mode ID Payload and the Authenticator - * (Hash or Signature Payload). - * If a DNS query is still needed to get the other host's public key, - * the query is initiated and STF_SUSPEND is returned. - * Note: parameter kc is a continuation containing the results from - * the previous DNS query, or NULL indicating no query has been issued. - */ -static stf_status -main_id_and_auth(struct msg_digest *md - , bool initiator /* are we the Initiator? */ - , cont_fn_t cont_fn /* continuation function */ - , const struct key_continuation *kc /* current state, can be NULL */ -) -{ - chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); - struct state *st = md->st; - identification_t *peer; - stf_status r = STF_OK; - - /* ID Payload in */ - if (!decode_peer_id(md, &peer)) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* Hash the ID Payload. - * main_mode_hash requires idpl->cur to be at end of payload - * so we temporarily set if so. - */ - { - pb_stream *idpl = &md->chain[ISAKMP_NEXT_ID]->pbs; - u_int8_t *old_cur = idpl->cur; - - idpl->cur = idpl->roof; - main_mode_hash(st, &hash, !initiator, idpl); - idpl->cur = old_cur; - } - - switch (st->st_oakley.auth) - { - case OAKLEY_PRESHARED_KEY: - case XAUTHInitPreShared: - case XAUTHRespPreShared: - { - pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; - - if (pbs_left(hash_pbs) != hash.len - || memcmp(hash_pbs->cur, hash.ptr, hash.len) != 0) - { - DBG_cond_dump(DBG_CRYPT, "received HASH:" - , hash_pbs->cur, pbs_left(hash_pbs)); - loglog(RC_LOG_SERIOUS, "received Hash Payload does not match computed value"); - /* XXX Could send notification back */ - r = STF_FAIL + ISAKMP_INVALID_HASH_INFORMATION; - } - } - break; - - case OAKLEY_RSA_SIG: - case XAUTHInitRSA: - case XAUTHRespRSA: - r = check_signature(KEY_RSA, peer, st, hash, - &md->chain[ISAKMP_NEXT_SIG]->pbs, -#ifdef USE_KEYRR - kc == NULL ? NULL : kc->ac.keys_from_dns, -#endif /* USE_KEYRR */ - kc == NULL ? NULL : kc->ac.gateways_from_dns - ); - - if (r == STF_SUSPEND) - { - err_t ugh = NULL; -#ifdef ADNS - /* initiate/resume asynchronous DNS lookup for key */ - struct key_continuation *nkc = malloc_thing(struct key_continuation); - enum key_oppo_step step_done = kc == NULL? kos_null : kc->step; - - /* Record that state is used by a suspended md */ - passert(st->st_suspended_md == NULL); - st->st_suspended_md = md; - - nkc->failure_ok = FALSE; - nkc->md = md; - - switch (step_done) - { - case kos_null: - /* first try: look for the TXT records */ - nkc->step = kos_his_txt; -#ifdef USE_KEYRR - nkc->failure_ok = TRUE; -#endif - ugh = start_adns_query(peer, peer, T_TXT, cont_fn, &nkc->ac); - break; - -#ifdef USE_KEYRR - case kos_his_txt: - /* second try: look for the KEY records */ - nkc->step = kos_his_key; - ugh = start_adns_query(peer, NULL, T_KEY, cont_fn, &nkc->ac); - break; -#endif /* USE_KEYRR */ - - default: - bad_case(step_done); - } -#else /* ADNS */ - ugh = "adns not supported"; -#endif /* ADNS */ - if (ugh != NULL) - { - report_key_dns_failure(peer, ugh); - st->st_suspended_md = NULL; - r = STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; - } - } - break; - - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - r = check_signature(KEY_ECDSA, peer, st, hash, - &md->chain[ISAKMP_NEXT_SIG]->pbs, -#ifdef USE_KEYRR - NULL, -#endif /* USE_KEYRR */ - NULL); - break; - - default: - bad_case(st->st_oakley.auth); - } - if (r != STF_OK) - { - peer->destroy(peer); - return r; - } - DBG(DBG_CRYPT, DBG_log("authentication succeeded")); - - /* - * With the peer ID known, let's see if we need to switch connections. - */ - if (!switch_connection(md, peer, initiator)) - { - r = STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - peer->destroy(peer); - return r; -} - -/* This continuation is called as part of either - * the main_inI3_outR3 state or main_inR3 state. - * - * The "tail" function is the corresponding tail - * function main_inI3_outR3_tail | main_inR3_tail, - * either directly when the state is started, or via - * adns continuation. - * - * Basically, we go around in a circle: - * main_in?3* -> key_continue - * ^ \ - * / V - * adns main_in?3*_tail - * ^ | - * \ V - * main_id_and_auth - * - * until such time as main_id_and_auth is able - * to find authentication, or we run out of things - * to try. - */ -static void key_continue(struct adns_continuation *cr, err_t ugh, - key_tail_fn *tail) -{ - struct key_continuation *kc = (void *)cr; - struct state *st = kc->md->st; - - passert(cur_state == NULL); - - /* if st == NULL, our state has been deleted -- just clean up */ - if (st != NULL) - { - stf_status r; - - passert(st->st_suspended_md == kc->md); - st->st_suspended_md = NULL; /* no longer connected or suspended */ - cur_state = st; - - if (!kc->failure_ok && ugh != NULL) - { - report_key_dns_failure(st->st_connection->spd.that.id, ugh); - r = STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; - } - else - { - -#ifdef USE_KEYRR - passert(kc->step == kos_his_txt || kc->step == kos_his_key); -#else - passert(kc->step == kos_his_txt); -#endif - kc->last_ugh = ugh; /* record previous error in case we need it */ - r = (*tail)(kc->md, kc); - } - complete_state_transition(&kc->md, r); - } - if (kc->md != NULL) - { - release_md(kc->md); - } - cur_state = NULL; -} - -/* STATE_MAIN_R2: - * PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R - * DS_AUTH: HDR*, IDi1, [ CERT, ] SIG_I --> HDR*, IDr1, [ CERT, ] SIG_R - * PKE_AUTH, RPKE_AUTH: HDR*, HASH_I --> HDR*, HASH_R - * - * Broken into parts to allow asynchronous DNS lookup. - * - * - main_inI3_outR3 to start - * - main_inI3_outR3_tail to finish or suspend for DNS lookup - * - main_inI3_outR3_continue to start main_inI3_outR3_tail again - */ -static key_tail_fn main_inI3_outR3_tail; /* forward */ - -stf_status main_inI3_outR3(struct msg_digest *md) -{ - return main_inI3_outR3_tail(md, NULL); -} - -static void main_inI3_outR3_continue(struct adns_continuation *cr, err_t ugh) -{ - key_continue(cr, ugh, main_inI3_outR3_tail); -} - -static stf_status -main_inI3_outR3_tail(struct msg_digest *md -, struct key_continuation *kc) -{ - struct state *const st = md->st; - u_int8_t auth_payload; - pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */ - certpolicy_t cert_policy; - cert_t *mycert; - bool pubkey_auth, send_cert, requested; - - /* ID and HASH_I or SIG_I in - * Note: this may switch the connection being used! - */ - { - stf_status r = main_id_and_auth(md, FALSE - , main_inI3_outR3_continue - , kc); - - if (r != STF_OK) - { - return r; - } - } - - /* send certificate if pubkey authentication is used, we have one - * and we want or are requested to send it - */ - cert_policy = st->st_connection->spd.this.sendcert; - mycert = st->st_connection->spd.this.cert; - requested = cert_policy == CERT_SEND_IF_ASKED - && st->st_connection->got_certrequest; - pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); - send_cert = pubkey_auth && mycert && - mycert->cert->get_type(mycert->cert) == CERT_X509 && - (cert_policy == CERT_ALWAYS_SEND || requested); - - /*************** build output packet HDR*;IDir;HASH/SIG_R ***************/ - /* proccess_packet() would automatically generate the HDR* - * payload if smc->first_out_payload is not ISAKMP_NEXT_NONE. - * We don't do this because we wish there to be no partially - * built output packet if we need to suspend for asynch DNS. - */ - /* ??? NOTE: this is almost the same as main_inR2_outI3's code */ - - /* HDR* out - * If auth were PKE_AUTH or RPKE_AUTH, ISAKMP_NEXT_HASH would - * be first payload. - */ - echo_hdr(md, TRUE, ISAKMP_NEXT_ID); - - auth_payload = pubkey_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH; - - /* IDir out */ - { - /* id_hd should be struct isakmp_id, but struct isakmp_ipsec_id - * allows build_id_payload() to work for both phases. - */ - struct isakmp_ipsec_id id_hd; - chunk_t id_b; - - build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this); - id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : auth_payload; - if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &r_id_pbs) - || !out_chunk(id_b, &r_id_pbs, "my identity")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&r_id_pbs); - } - - /* CERT out */ - if (pubkey_auth) - { - DBG(DBG_CONTROL, - DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) - ) - if (mycert && mycert->cert->get_type(mycert->cert) == CERT_X509) - { - const char *request_text = ""; - - if (cert_policy == CERT_SEND_IF_ASKED) - { - request_text = (send_cert)? "upon request":"without request"; - } - plog("we have a cert %s sending it %s" - , send_cert? "and are":"but are not", request_text); - } - else - { - plog("we don't have a cert"); - } - } - if (send_cert) - { - bool success = FALSE; - chunk_t cert_encoding; - pb_stream cert_pbs; - struct isakmp_cert cert_hd; - - cert_hd.isacert_np = ISAKMP_NEXT_SIG; - cert_hd.isacert_type = CERT_X509_SIGNATURE; - - if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (mycert->cert->get_encoding(mycert->cert, CERT_ASN1_DER, - &cert_encoding)) - { - success = out_chunk(cert_encoding, &cert_pbs, "CERT"); - free(cert_encoding.ptr); - } - if (!success) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&cert_pbs); - } - - /* HASH_R or SIG_R out */ - { - chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); - - main_mode_hash(st, &hash, FALSE, &r_id_pbs); - - if (auth_payload == ISAKMP_NEXT_HASH) - { - /* HASH_R out */ - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody, - hash.ptr, hash.len, "HASH_R")) - { - return STF_INTERNAL_ERROR; - } - } - else - { - /* SIG_R out */ - u_char sig_val[RSA_MAX_OCTETS]; - signature_scheme_t scheme; - size_t sig_len; - - scheme = oakley_to_signature_scheme(st->st_oakley.auth); - - sig_len = sign_hash(scheme, st->st_connection, sig_val, hash); - if (sig_len == 0) - { - loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature"); - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc - , &md->rbody, sig_val, sig_len, "SIG_R")) - { - return STF_INTERNAL_ERROR; - } - } - } - - /* encrypt message, sans fixed part of header */ - - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - - /* Last block of Phase 1 (R3), kept for Phase 2 IV generation */ - DBG_cond_dump(DBG_CRYPT, "last encrypted block of Phase 1:" - , st->st_new_iv, st->st_new_iv_len); - - ISAKMP_SA_established(st->st_connection, st->st_serialno); - - /* Save Phase 1 IV */ - st->st_ph1_iv_len = st->st_new_iv_len; - set_ph1_iv(st, st->st_new_iv); - - return STF_OK; -} - -/* STATE_MAIN_I3: - * Handle HDR*;IDir;HASH/SIG_R from responder. - * - * Broken into parts to allow asynchronous DNS for KEY records. - * - * - main_inR3 to start - * - main_inR3_tail to finish or suspend for DNS lookup - * - main_inR3_continue to start main_inR3_tail again - */ - -static key_tail_fn main_inR3_tail; /* forward */ - -stf_status main_inR3(struct msg_digest *md) -{ - return main_inR3_tail(md, NULL); -} - -static void main_inR3_continue(struct adns_continuation *cr, err_t ugh) -{ - key_continue(cr, ugh, main_inR3_tail); -} - -static stf_status main_inR3_tail(struct msg_digest *md, - struct key_continuation *kc) -{ - struct state *const st = md->st; - - /* ID and HASH_R or SIG_R in - * Note: this may switch the connection being used! - */ - { - stf_status r = main_id_and_auth(md, TRUE, main_inR3_continue, kc); - - if (r != STF_OK) - { - return r; - } - } - - /**************** done input ****************/ - - ISAKMP_SA_established(st->st_connection, st->st_serialno); - - /* Save Phase 1 IV */ - st->st_ph1_iv_len = st->st_new_iv_len; - set_ph1_iv(st, st->st_new_iv); - - - update_iv(st); /* finalize our Phase 1 IV */ - - return STF_OK; -} - -/* Handle first message of Phase 2 -- Quick Mode. - * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] - * (see RFC 2409 "IKE" 5.5) - * Installs inbound IPsec SAs. - * Although this seems early, we know enough to do so, and - * this way we know that it is soon enough to catch all - * packets that other side could send using this IPsec SA. - * - * Broken into parts to allow asynchronous DNS for TXT records: - * - * - quick_inI1_outR1 starts the ball rolling. - * It checks and parses enough to learn the Phase 2 IDs - * - * - quick_inI1_outR1_tail does the rest of the job - * unless DNS must be consulted. In that case, - * it starts a DNS query, salts away what is needed - * to continue, and suspends. Calls - * + quick_inI1_outR1_start_query - * + quick_inI1_outR1_process_answer - * - * - quick_inI1_outR1_continue will restart quick_inI1_outR1_tail - * when DNS comes back with an answer. - * - * A big chunk of quick_inI1_outR1_tail is executed twice. - * This is necessary because the set of connections - * might change while we are awaiting DNS. - * When first called, gateways_from_dns == NULL. If DNS is - * consulted asynchronously, gateways_from_dns != NULL the second time. - * Remember that our state object might disappear too! - * - * - * If the connection is opportunistic, we must verify delegation. - * - * 1. Check that we are authorized to be SG for - * our client. We look for the TXT record that - * delegates us. We also check that the public - * key (if present) matches the private key we used. - * Eventually, we should probably require DNSsec - * authentication for our side. - * - * 2. If our client TXT record did not include a - * public key, check the KEY record indicated - * by the identity in the TXT record. - * - * 3. If the peer's client is the peer itself, we - * consider it authenticated. Otherwise, we check - * the TXT record for the client to see that - * the identity of the SG matches the peer and - * that some public key (if present in the TXT) - * matches. We need not check the public key if - * it isn't in the TXT record. - * - * Since p isn't yet instantiated, we need to look - * in c for description of peer. - * - * We cannot afford to block waiting for a DNS query. - * The code here is structured as two halves: - * - process the result of just completed - * DNS query (if any) - * - if another query is needed, initiate the next - * DNS query and suspend - */ - -enum verify_oppo_step { - vos_fail, - vos_start, - vos_our_client, - vos_our_txt, -#ifdef USE_KEYRR - vos_our_key, -#endif /* USE_KEYRR */ - vos_his_client, - vos_done -}; - -static const char *const verify_step_name[] = { - "vos_fail", - "vos_start", - "vos_our_client", - "vos_our_txt", -#ifdef USE_KEYRR - "vos_our_key", -#endif /* USE_KEYRR */ - "vos_his_client", - "vos_done" -}; - -/* hold anything we can handle of a Phase 2 ID */ -struct p2id { - ip_subnet net; - u_int8_t proto; - u_int16_t port; -}; - -struct verify_oppo_bundle { - enum verify_oppo_step step; - bool failure_ok; /* if true, quick_inI1_outR1_continue will try - * other things on DNS failure */ - struct msg_digest *md; - struct p2id my, his; - unsigned int new_iv_len; /* p1st's might change */ - u_char new_iv[MAX_DIGEST_LEN]; - /* int whackfd; */ /* not needed because we are Responder */ -}; - -struct verify_oppo_continuation { - struct adns_continuation ac; /* common prefix */ - struct verify_oppo_bundle b; -}; - -static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b - , struct adns_continuation *ac); - -stf_status quick_inI1_outR1(struct msg_digest *md) -{ - const struct state *const p1st = md->st; - connection_t *c = p1st->st_connection; - struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; - struct verify_oppo_bundle b; - - /* HASH(1) in */ - CHECK_QUICK_HASH(md - , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof - , p1st, &md->hdr.isa_msgid, FALSE) - , "HASH(1)", "Quick I1"); - - /* [ IDci, IDcr ] in - * We do this now (probably out of physical order) because - * we wish to select the correct connection before we consult - * it for policy. - */ - - if (id_pd != NULL) - { - /* ??? we are assuming IPSEC_DOI */ - - /* IDci (initiator is peer) */ - - if (!decode_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs - , &b.his.net, "peer client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* Hack for MS 818043 NAT-T Update */ - - if (id_pd->payload.ipsec_id.isaiid_idtype == ID_FQDN) - { - happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net)); - } - - /* End Hack for MS 818043 NAT-T Update */ - - b.his.proto = id_pd->payload.ipsec_id.isaiid_protoid; - b.his.port = id_pd->payload.ipsec_id.isaiid_port; - b.his.net.addr.u.v4.sin_port = htons(b.his.port); - - /* IDcr (we are responder) */ - - if (!decode_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs - , &b.my.net, "our client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - b.my.proto = id_pd->next->payload.ipsec_id.isaiid_protoid; - b.my.port = id_pd->next->payload.ipsec_id.isaiid_port; - b.my.net.addr.u.v4.sin_port = htons(b.my.port); - } - else - { - /* implicit IDci and IDcr: peer and self */ - if (!sameaddrtype(&c->spd.this.host_addr, &c->spd.that.host_addr)) - { - return STF_FAIL; - } - happy(addrtosubnet(&c->spd.this.host_addr, &b.my.net)); - happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net)); - b.his.proto = b.my.proto = 0; - b.his.port = b.my.port = 0; - } - b.step = vos_start; - b.md = md; - b.new_iv_len = p1st->st_new_iv_len; - memcpy(b.new_iv, p1st->st_new_iv, p1st->st_new_iv_len); - return quick_inI1_outR1_tail(&b, NULL); -} - -#ifdef ADNS - -static void -report_verify_failure(struct verify_oppo_bundle *b, err_t ugh) -{ - struct state *st = b->md->st; - char fgwb[ADDRTOT_BUF] - , cb[ADDRTOT_BUF]; - ip_address client; - err_t which = NULL; - - switch (b->step) - { - case vos_our_client: - case vos_our_txt: -#ifdef USE_KEYRR - case vos_our_key: -#endif /* USE_KEYRR */ - which = "our"; - networkof(&b->my.net, &client); - break; - - case vos_his_client: - which = "his"; - networkof(&b->his.net, &client); - break; - - case vos_start: - case vos_done: - case vos_fail: - default: - bad_case(b->step); - } - - addrtot(&st->st_connection->spd.that.host_addr, 0, fgwb, sizeof(fgwb)); - addrtot(&client, 0, cb, sizeof(cb)); - loglog(RC_OPPOFAILURE - , "gateway %s wants connection with %s as %s client, but DNS fails to confirm delegation: %s" - , fgwb, cb, which, ugh); -} - -static void quick_inI1_outR1_continue(struct adns_continuation *cr, err_t ugh) -{ - stf_status r; - struct verify_oppo_continuation *vc = (void *)cr; - struct verify_oppo_bundle *b = &vc->b; - struct state *st = b->md->st; - - passert(cur_state == NULL); - /* if st == NULL, our state has been deleted -- just clean up */ - if (st != NULL) - { - passert(st->st_suspended_md == b->md); - st->st_suspended_md = NULL; /* no longer connected or suspended */ - cur_state = st; - if (!b->failure_ok && ugh != NULL) - { - report_verify_failure(b, ugh); - r = STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - else - { - r = quick_inI1_outR1_tail(b, cr); - } - complete_state_transition(&b->md, r); - } - if (b->md != NULL) - { - release_md(b->md); - } - cur_state = NULL; -} - -static stf_status quick_inI1_outR1_start_query(struct verify_oppo_bundle *b, - enum verify_oppo_step next_step) -{ - struct msg_digest *md = b->md; - struct state *p1st = md->st; - connection_t *c = p1st->st_connection; - struct verify_oppo_continuation *vc = malloc_thing(struct verify_oppo_continuation); - identification_t *id; /* subject of query */ - identification_t *our_id; /* needed for myid playing */ - identification_t *our_id_space; /* ephemeral: no need for unshare_id_content */ - ip_address client; - err_t ugh = NULL; - - /* Record that state is used by a suspended md */ - b->step = next_step; /* not just vc->b.step */ - vc->b = *b; - passert(p1st->st_suspended_md == NULL); - p1st->st_suspended_md = b->md; - - DBG(DBG_CONTROL, - { - char ours[SUBNETTOT_BUF]; - char his[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, ours, sizeof(ours)); - subnettot(&c->spd.that.client, 0, his, sizeof(his)); - - DBG_log("responding with DNS query - from %s to %s new state: %s" - , ours, his, verify_step_name[b->step]); - }); - - /* Resolve %myid in a cheesy way. - * We have to do the resolution because start_adns_query - * et al have insufficient information to do so. - * If %myid is already known, we'll use that value - * (XXX this may be a mistake: it could be stale). - * If %myid is unknown, we should check to see if - * there are credentials for the IP address or the FQDN. - * Instead, we'll just assume the IP address since we are - * acting as the responder and only the IP address would - * have gotten it to us. - * We don't even try to do this for the other side: - * %myid makes no sense for the other side (but it is syntactically - * legal). - */ - our_id = resolve_myid(c->spd.this.id); - if (our_id->get_type(our_id) == ID_ANY) - { - our_id_space = identification_create_from_sockaddr((sockaddr_t*)&c->spd.this.host_addr); - our_id = our_id_space; - } - - switch (next_step) - { - case vos_our_client: - networkof(&b->my.net, &client); - id = identification_create_from_sockaddr((sockaddr_t*)&client); - vc->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(id - , our_id - , T_TXT - , quick_inI1_outR1_continue - , &vc->ac); - break; - - case vos_our_txt: - vc->b.failure_ok = b->failure_ok = TRUE; - ugh = start_adns_query(our_id - , our_id /* self as SG */ - , T_TXT - , quick_inI1_outR1_continue - , &vc->ac); - break; - -#ifdef USE_KEYRR - case vos_our_key: - vc->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(our_id - , NULL - , T_KEY - , quick_inI1_outR1_continue - , &vc->ac); - break; -#endif - - case vos_his_client: - networkof(&b->his.net, &client); - id = identification_create_from_sockaddr((sockaddr_t*)&client); - vc->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(id - , c->spd.that.id - , T_TXT - , quick_inI1_outR1_continue - , &vc->ac); - break; - - default: - bad_case(next_step); - } - - if (ugh != NULL) - { - /* note: we'd like to use vc->b but vc has been freed - * so we have to use b. This is why we plunked next_state - * into b, not just vc->b. - */ - report_verify_failure(b, ugh); - p1st->st_suspended_md = NULL; - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - else - { - return STF_SUSPEND; - } -} - -static enum verify_oppo_step quick_inI1_outR1_process_answer( - struct verify_oppo_bundle *b, - struct adns_continuation *ac, - struct state *p1st) -{ - connection_t *c = p1st->st_connection; - enum verify_oppo_step next_step = vos_our_client; - err_t ugh = NULL; - - DBG(DBG_CONTROL, - { - char ours[SUBNETTOT_BUF]; - char his[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, ours, sizeof(ours)); - subnettot(&c->spd.that.client, 0, his, sizeof(his)); - DBG_log("responding on demand from %s to %s state: %s" - , ours, his, verify_step_name[b->step]); - }); - - /* process just completed DNS query (if any) */ - switch (b->step) - { - case vos_start: - /* no query to digest */ - next_step = vos_our_client; - break; - - case vos_our_client: - next_step = vos_his_client; - { - private_key_t *private = get_private_key(c); - struct gw_info *gwp; - - if (private == NULL) - { - ugh = "we don't know our own key"; - break; - } - ugh = "our client does not delegate us as its Security Gateway"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "our client delegates us as its Security Gateway but with the wrong public key"; - /* If there is no key in the TXT record, - * we count it as a win, but we will have - * to separately fetch and check the KEY record. - * If there is a key from the TXT record, - * we count it as a win if we match the key. - */ - if (!gwp->gw_key_present) - { - next_step = vos_our_txt; - ugh = NULL; /* good! */ - break; - } - else if (private->belongs_to(private, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - break; - - case vos_our_txt: - next_step = vos_his_client; - { - private_key_t *private = get_private_key(c); - - if (private == NULL) - { - ugh = "we don't know our own key"; - break; - } - { - struct gw_info *gwp; - - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { -#ifdef USE_KEYRR - /* not an error yet, because we have to check KEY RR as well */ - ugh = NULL; -#else - ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key"; -#endif - if (gwp->gw_key_present - && private->belongs_to(private, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } -#ifdef USE_KEYRR - next_step = vos_our_key; -#endif - } - } - } - break; - -#ifdef USE_KEYRR - case vos_our_key: - next_step = vos_his_client; - { - private_key_t *private = get_private_key(c); - - if (private == NULL) - { - ugh = "we don't know our own key"; - break; - } - { - pubkey_list_t *kp; - - ugh = "our client delegation depends on our missing " RRNAME " record"; - for (kp = ac->keys_from_dns; kp != NULL; kp = kp->next) - { - ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key"; - if (private->belongs_to(private, kp->key->public_key)) - { - /* do this only once a day */ - if (!logged_txt_warning) - { - loglog(RC_LOG_SERIOUS, "found KEY RR but not TXT RR. See http://www.freeswan.org/err/txt-change.html."); - logged_txt_warning = TRUE; - } - ugh = NULL; /* good! */ - break; - } - } - } - } - break; -#endif /* USE_KEYRR */ - - case vos_his_client: - next_step = vos_done; - { - public_key_t *pub_key; - struct gw_info *gwp; - - /* check that the public key that authenticated - * the ISAKMP SA (p1st) will do for this gateway. - */ - pub_key = p1st->st_peer_pubkey->public_key; - - ugh = "peer's client does not delegate to peer"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "peer and its client disagree about public key"; - /* If there is a key from the TXT record, - * we count it as a win if we match the key. - * If there was no key, we claim a match since - * it implies fetching a KEY from the same - * place we must have gotten it. - */ - if (!gwp->gw_key_present || - pub_key->equals(pub_key, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - break; - - default: - bad_case(b->step); - } - - if (ugh != NULL) - { - report_verify_failure(b, ugh); - next_step = vos_fail; - } - return next_step; -} - -#endif /* ADNS */ - -static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, - struct adns_continuation *ac) -{ - struct msg_digest *md = b->md; - struct state *const p1st = md->st; - connection_t *c = p1st->st_connection; - struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; - ip_subnet *our_net = &b->my.net - , *his_net = &b->his.net; - - u_char /* set by START_HASH_PAYLOAD: */ - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* from where to start hashing */ - - /* Now that we have identities of client subnets, we must look for - * a suitable connection (our current one only matches for hosts). - */ - { - connection_t *p = find_client_connection(c - , our_net, his_net, b->my.proto, b->my.port, b->his.proto, b->his.port); - - if (p == NULL) - { - /* This message occurs in very puzzling circumstances - * so we must add as much information and beauty as we can. - */ - struct end - me = c->spd.this, - he = c->spd.that; - char buf[2*SUBNETTOT_BUF + 2*ADDRTOT_BUF + 2*BUF_LEN + 2*ADDRTOT_BUF + 12]; /* + 12 for separating */ - size_t l; - - me.client = *our_net; - me.has_client = !subnetisaddr(our_net, &me.host_addr); - me.protocol = b->my.proto; - me.port = b->my.port; - - he.client = *his_net; - he.has_client = !subnetisaddr(his_net, &he.host_addr); - he.protocol = b->his.proto; - he.port = b->his.port; - - l = format_end(buf, sizeof(buf), &me, NULL, TRUE, LEMPTY); - l += snprintf(buf + l, sizeof(buf) - l, "..."); - (void)format_end(buf + l, sizeof(buf) - l, &he, NULL, FALSE, LEMPTY); - plog("cannot respond to IPsec SA request" - " because no connection is known for %s" - , buf); - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - else if (p != c) - { - /* We've got a better connection: it can support the - * specified clients. But it may need instantiation. - */ - if (p->kind == CK_TEMPLATE) - { - /* Yup, it needs instantiation. How much? - * Is it a Road Warrior connection (simple) - * or is it an Opportunistic connection (needing gw validation)? - */ - if (p->policy & POLICY_OPPO) - { -#ifdef ADNS - /* Opportunistic case: delegation must be verified. - * Here be dragons. - */ - enum verify_oppo_step next_step; - ip_address our_client, his_client; - - passert(subnetishost(our_net) && subnetishost(his_net)); - networkof(our_net, &our_client); - networkof(his_net, &his_client); - - next_step = quick_inI1_outR1_process_answer(b, ac, p1st); - if (next_step == vos_fail) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* short circuit: if peer's client is self, - * accept that we've verified delegation in Phase 1 - */ - if (next_step == vos_his_client - && sameaddr(&c->spd.that.host_addr, &his_client)) - { - next_step = vos_done; - } - - /* the second chunk: initiate the next DNS query (if any) */ - DBG(DBG_CONTROL, - { - char ours[SUBNETTOT_BUF]; - char his[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, ours, sizeof(ours)); - subnettot(&c->spd.that.client, 0, his, sizeof(his)); - - DBG_log("responding on demand from %s to %s new state: %s" - , ours, his, verify_step_name[next_step]); - }); - - /* start next DNS query and suspend (if necessary) */ - if (next_step != vos_done) - { - return quick_inI1_outR1_start_query(b, next_step); - } - - /* Instantiate inbound Opportunistic connection, - * carrying over authenticated peer ID - * and filling in a few more details. - * We used to include gateways_from_dns, but that - * seems pointless at this stage of negotiation. - * We should record DNS sec use, if any -- belongs in - * state during perhaps. - */ - p = oppo_instantiate(p, &c->spd.that.host_addr, c->spd.that.id - , NULL, &our_client, &his_client); -#else /* ADNS */ - plog("opportunistic connections not supported because" - " adns is not available"); - return STF_INTERNAL_ERROR; -#endif /* ADNS */ - } - else - { - /* Plain Road Warrior: - * instantiate, carrying over authenticated peer ID - */ - host_t *vip = c->spd.that.host_srcip; - - p = rw_instantiate(p, &c->spd.that.host_addr, md->sender_port - , his_net, c->spd.that.id); - - /* inherit any virtual IP assigned by a Mode Config exchange */ - if (p->spd.that.modecfg && c->spd.that.modecfg && - subnetisaddr(his_net, (ip_address*)vip->get_sockaddr(vip))) - { - DBG(DBG_CONTROL, - DBG_log("inheriting virtual IP source address %H from ModeCfg", vip) - ) - p->spd.that.host_srcip->destroy(p->spd.that.host_srcip); - p->spd.that.host_srcip = vip->clone(vip); - p->spd.that.client = c->spd.that.client; - p->spd.that.has_client = TRUE; - } - - if (c->policy & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK) && - c->xauth_identity && !p->xauth_identity) - { - DBG(DBG_CONTROL, - DBG_log("inheriting XAUTH identity %Y", c->xauth_identity) - ) - p->xauth_identity = c->xauth_identity->clone(c->xauth_identity); - } - } - } -#ifdef DEBUG - /* temporarily bump up cur_debugging to get "using..." message - * printed if we'd want it with new connection. - */ - { - lset_t old_cur_debugging = cur_debugging; - - cur_debugging |= p->extra_debugging; - DBG(DBG_CONTROL, DBG_log("using connection \"%s\"", p->name)); - cur_debugging = old_cur_debugging; - } -#endif - c = p; - } - /* fill in the client's true ip address/subnet */ - if (p->spd.that.has_client_wildcard) - { - p->spd.that.client = *his_net; - p->spd.that.has_client_wildcard = FALSE; - } - else if (is_virtual_connection(c)) - { - c->spd.that.client = *his_net; - c->spd.that.virt = NULL; - if (subnetishost(his_net) && addrinsubnet(&c->spd.that.host_addr, his_net)) - { - c->spd.that.has_client = FALSE; - } - } - - /* fill in the client's true port */ - if (p->spd.that.has_port_wildcard) - { - int port = htons(b->his.port); - - setportof(port, &p->spd.that.host_addr); - setportof(port, &p->spd.that.client.addr); - - p->spd.that.port = b->his.port; - p->spd.that.has_port_wildcard = FALSE; - } - } - - /* now that we are sure of our connection, create our new state */ - { - enum endpoint ep = EP_LOCAL; - struct state *const st = duplicate_state(p1st); - - /* first: fill in missing bits of our new state object - * note: we don't copy over st_peer_pubkey, the public key - * that authenticated the ISAKMP SA. We only need it in this - * routine, so we can "reach back" to p1st to get it. - */ - - if (st->st_connection != c) - { - connection_t *t = st->st_connection; - - st->st_connection = c; - set_cur_connection(c); - connection_discard(t); - } - - st->st_try = 0; /* not our job to try again from start */ - - st->st_msgid = md->hdr.isa_msgid; - - st->st_new_iv_len = b->new_iv_len; - memcpy(st->st_new_iv, b->new_iv, b->new_iv_len); - - set_cur_state(st); /* (caller will reset) */ - md->st = st; /* feed back new state */ - - st->st_peeruserprotoid = b->his.proto; - st->st_peeruserport = b->his.port; - st->st_myuserprotoid = b->my.proto; - st->st_myuserport = b->my.port; - - insert_state(st); /* needs cookies, connection, and msgid */ - - /* copy the connection's - * IPSEC policy into our state. The ISAKMP policy is water under - * the bridge, I think. It will reflect the ISAKMP SA that we - * are using. - */ - st->st_policy = (p1st->st_policy & POLICY_ISAKMP_MASK) - | (c->policy & ~POLICY_ISAKMP_MASK); - - if (p1st->nat_traversal & NAT_T_DETECTED) - { - st->nat_traversal = p1st->nat_traversal; - nat_traversal_change_port_lookup(md, md->st); - } - else - { - st->nat_traversal = 0; - } - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->nat_traversal & NAT_T_WITH_NATOA)) - { - nat_traversal_natoa_lookup(md); - } - - /* Start the output packet. - * - * proccess_packet() would automatically generate the HDR* - * payload if smc->first_out_payload is not ISAKMP_NEXT_NONE. - * We don't do this because we wish there to be no partially - * built output packet if we need to suspend for asynch DNS. - * - * We build the reply packet as we parse the message since - * the parse_ipsec_sa_body emits the reply SA - */ - - /* HDR* out */ - echo_hdr(md, TRUE, ISAKMP_NEXT_HASH); - - /* HASH(2) out -- first pass */ - START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_SA); - - /* process SA (in and out) */ - { - struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; - pb_stream r_sa_pbs; - struct isakmp_sa sa = sapd->payload.sa; - - /* sa header is unchanged -- except for np */ - sa.isasa_np = ISAKMP_NEXT_NONCE; - if (!out_struct(&sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs)) - { - return STF_INTERNAL_ERROR; - } - - /* parse and accept body */ - st->st_pfs_group = &unset_group; - RETURN_STF_FAILURE(parse_ipsec_sa_body(&sapd->pbs - , &sapd->payload.sa, &r_sa_pbs, FALSE, st)); - } - - passert(st->st_pfs_group != &unset_group); - - if ((st->st_policy & POLICY_PFS) && st->st_pfs_group == NULL) - { - loglog(RC_LOG_SERIOUS, "we require PFS but Quick I1 SA specifies no GROUP_DESCRIPTION"); - return STF_FAIL + ISAKMP_NO_PROPOSAL_CHOSEN; - } - - /* Ni in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); - - /* [ KE ] in (for PFS) */ - RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gi, "Gi", "Quick Mode I1")); - - plog("responding to Quick Mode"); - - /**** finish reply packet: Nr [, KE ] [, IDci, IDcr ] ****/ - - /* Nr out */ - if (!build_and_ship_nonce(&st->st_nr, &md->rbody - , st->st_pfs_group != NULL? ISAKMP_NEXT_KE : id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE - , "Nr")) - { - return STF_INTERNAL_ERROR; - } - - /* [ KE ] out (for PFS) */ - - if (st->st_pfs_group != NULL) - { - if (!build_and_ship_KE(st, &st->st_gr, st->st_pfs_group - , &md->rbody, id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE)) - { - return STF_INTERNAL_ERROR; - } - - /* MPZ-Operations might be done after sending the packet... */ - compute_dh_shared(st, st->st_gi); - } - - /* [ IDci, IDcr ] out */ - if (id_pd != NULL) - { - struct isakmp_ipsec_id *p = (void *)md->rbody.cur; /* UGH! */ - - if (!out_raw(id_pd->pbs.start, pbs_room(&id_pd->pbs), &md->rbody, "IDci")) - { - return STF_INTERNAL_ERROR; - } - p->isaiid_np = ISAKMP_NEXT_ID; - - p = (void *)md->rbody.cur; /* UGH! */ - - if (!out_raw(id_pd->next->pbs.start, pbs_room(&id_pd->next->pbs), &md->rbody, "IDcr")) - { - return STF_INTERNAL_ERROR; - } - p->isaiid_np = ISAKMP_NEXT_NONE; - } - - if ((st->nat_traversal & NAT_T_WITH_NATOA) - && (st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) - && (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT)) - { - /** Send NAT-OA if our address is NATed and if we use Transport Mode */ - if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &md->rbody, md->st)) - { - return STF_INTERNAL_ERROR; - } - } - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT) - && (c->spd.that.has_client)) - { - /** Remove client **/ - addrtosubnet(&c->spd.that.host_addr, &c->spd.that.client); - c->spd.that.has_client = FALSE; - } - - /* Compute reply HASH(2) and insert in output */ - (void)quick_mode_hash12(r_hashval, r_hash_start, md->rbody.cur - , st, &st->st_msgid, TRUE); - - /* Derive new keying material */ - compute_keymats(st, ep); - - /* Tell the kernel to establish the new inbound SA - * (unless the commit bit is set -- which we don't support). - * We do this before any state updating so that - * failure won't look like success. - */ - if (!install_inbound_ipsec_sa(st)) - { - wipe_keymats(st, ep); - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - wipe_keymats(st, ep); - - /* encrypt message, except for fixed part of header */ - - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - - return STF_OK; - } -} - -/* - * Initialize RFC 3706 Dead Peer Detection - */ -static void dpd_init(struct state *st) -{ - struct state *p1st = find_state(st->st_icookie, st->st_rcookie - , &st->st_connection->spd.that.host_addr, 0); - - if (p1st == NULL) - { - loglog(RC_LOG_SERIOUS, "could not find phase 1 state for DPD"); - } - else if (p1st->st_dpd) - { - plog("Dead Peer Detection (RFC 3706) enabled"); - /* randomize the first DPD event */ - - event_schedule(EVENT_DPD - , (0.5 + rand()/(RAND_MAX + 1.E0)) * st->st_connection->dpd_delay - , st); - } -} - -/* Handle (the single) message from Responder in Quick Mode. - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(3) - * (see RFC 2409 "IKE" 5.5) - * Installs inbound and outbound IPsec SAs, routing, etc. - */ -stf_status quick_inR1_outI2(struct msg_digest *md) -{ - enum endpoint ep = EP_LOCAL | EP_REMOTE; - struct state *const st = md->st; - const connection_t *c = st->st_connection; - - /* HASH(2) in */ - CHECK_QUICK_HASH(md - , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof - , st, &st->st_msgid, TRUE) - , "HASH(2)", "Quick R1"); - - /* SA in */ - { - struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; - - RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs - , &sa_pd->payload.sa, NULL, TRUE, st)); - } - - /* Nr in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr")); - - /* [ KE ] in (for PFS) */ - RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1")); - - if (st->st_pfs_group != NULL) - { - compute_dh_shared(st, st->st_gr); - } - - /* [ IDci, IDcr ] in; these must match what we sent */ - - { - struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; - - if (id_pd != NULL) - { - /* ??? we are assuming IPSEC_DOI */ - - /* IDci (we are initiator) */ - - if (!check_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs - , &st->st_myuserprotoid, &st->st_myuserport - , &st->st_connection->spd.this.client - , "our client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* IDcr (responder is peer) */ - - if (!check_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs - , &st->st_peeruserprotoid, &st->st_peeruserport - , &st->st_connection->spd.that.client - , "peer client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - } - else - { - /* no IDci, IDcr: we must check that the defaults match our proposal */ - if (!subnetisaddr(&c->spd.this.client, &c->spd.this.host_addr) - || !subnetisaddr(&c->spd.that.client, &c->spd.that.host_addr)) - { - loglog(RC_LOG_SERIOUS, "IDci, IDcr payloads missing in message" - " but default does not match proposal"); - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - } - } - - /* check the peer's group attributes */ - { - identification_t *peer_ca = NULL; - ietf_attributes_t *peer_attributes = NULL; - bool match; - - get_peer_ca_and_groups(st->st_connection, &peer_ca, &peer_attributes); - match = match_group_membership(peer_attributes, - st->st_connection->name, - st->st_connection->spd.that.groups); - DESTROY_IF(peer_attributes); - - if (!match) - { - ietf_attributes_t *groups = st->st_connection->spd.that.groups; - - loglog(RC_LOG_SERIOUS, - "peer with attributes '%s' is not a member of the groups '%s'", - peer_attributes->get_string(peer_attributes), - groups->get_string(groups)); - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - } - - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->nat_traversal & NAT_T_WITH_NATOA)) - { - nat_traversal_natoa_lookup(md); - } - - /* ??? We used to copy the accepted proposal into the state, but it was - * never used. From sa_pd->pbs.start, length pbs_room(&sa_pd->pbs). - */ - - /**************** build reply packet HDR*, HASH(3) ****************/ - - /* HDR* out done */ - - /* HASH(3) out -- since this is the only content, no passes needed */ - { - u_char /* set by START_HASH_PAYLOAD: */ - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - - START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_NONE); - (void)quick_mode_hash3(r_hashval, st); - } - - /* Derive new keying material */ - compute_keymats(st, ep); - - /* Tell the kernel to establish the inbound, outbound, and routing part - * of the new SA (unless the commit bit is set -- which we don't support). - * We do this before any state updating so that - * failure won't look like success. - */ - if (!install_ipsec_sa(st, TRUE)) - { - wipe_keymats(st, ep); - return STF_INTERNAL_ERROR; - } - wipe_keymats(st, ep); - - /* encrypt message, except for fixed part of header */ - - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - DBG(DBG_CONTROLMORE, - DBG_log("inR1_outI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)" - , st->st_connection->name - , st->st_connection->instance_serial - , st->st_serialno - , st->st_connection->newest_ipsec_sa - , st->st_connection->spd.eroute_owner) - ) - st->st_connection->newest_ipsec_sa = st->st_serialno; - - /* note (presumed) success */ - if (c->gw_info != NULL) - { - c->gw_info->key->last_worked_time = now(); - } - - /* If we want DPD on this connection then initialize it */ - if (st->st_connection->dpd_action != DPD_ACTION_NONE) - { - dpd_init(st); - } - return STF_OK; -} - -/* Handle last message of Quick Mode. - * HDR*, HASH(3) -> done - * (see RFC 2409 "IKE" 5.5) - * Installs outbound IPsec SAs, routing, etc. - */ -stf_status quick_inI2(struct msg_digest *md) -{ - enum endpoint ep = EP_REMOTE; - struct state *const st = md->st; - - /* HASH(3) in */ - CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st) - , "HASH(3)", "Quick I2"); - - /* Derive keying material */ - compute_keymats(st, ep); - - /* Tell the kernel to establish the outbound and routing part of the new SA - * (the previous state established inbound) - * (unless the commit bit is set -- which we don't support). - * We do this before any state updating so that - * failure won't look like success. - */ - if (!install_ipsec_sa(st, FALSE)) - { - wipe_keymats(st, ep); - return STF_INTERNAL_ERROR; - } - wipe_keymats(st, ep); - - DBG(DBG_CONTROLMORE, - DBG_log("inI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)" - , st->st_connection->name - , st->st_connection->instance_serial - , st->st_serialno - , st->st_connection->newest_ipsec_sa - , st->st_connection->spd.eroute_owner) - ) - st->st_connection->newest_ipsec_sa = st->st_serialno; - - update_iv(st); /* not actually used, but tidy */ - - /* note (presumed) success */ - { - struct gw_info *gw = st->st_connection->gw_info; - - if (gw != NULL) - { - gw->key->last_worked_time = now(); - } - } - - /* If we want DPD on this connection then initialize it */ - if (st->st_connection->dpd_action != DPD_ACTION_NONE) - { - dpd_init(st); - } - return STF_OK; -} - -static stf_status send_isakmp_notification(struct state *st, u_int16_t type, - const void *data, size_t len) -{ - msgid_t msgid; - pb_stream reply; - pb_stream rbody; - u_char - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - - msgid = generate_msgid(st); - - init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "ISAKMP notify"); - - /* HDR* */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_INFO; - hdr.isa_msgid = msgid; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) - { - impossible(); - } - } - /* HASH -- create and note space to be filled later */ - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_N); - - /* NOTIFY */ - { - pb_stream notify_pbs; - struct isakmp_notification isan; - - isan.isan_np = ISAKMP_NEXT_NONE; - isan.isan_doi = ISAKMP_DOI_IPSEC; - isan.isan_protoid = PROTO_ISAKMP; - isan.isan_spisize = COOKIE_SIZE * 2; - isan.isan_type = type; - if (!out_struct(&isan, &isakmp_notification_desc, &rbody, ¬ify_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (!out_raw(st->st_icookie, COOKIE_SIZE, ¬ify_pbs, "notify icookie")) - { - return STF_INTERNAL_ERROR; - } - if (!out_raw(st->st_rcookie, COOKIE_SIZE, ¬ify_pbs, "notify rcookie")) - { - return STF_INTERNAL_ERROR; - } - if (data != NULL && len > 0) - { - if (!out_raw(data, len, ¬ify_pbs, "notify data")) - { - return STF_INTERNAL_ERROR; - } - } - close_output_pbs(¬ify_pbs); - } - - { - /* finish computing HASH */ - chunk_t msgid_chunk = chunk_from_thing(msgid); - chunk_t msg_chunk = { r_hash_start, rbody.cur-r_hash_start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, r_hashval); - - DBG(DBG_CRYPT, - DBG_log("HASH computed:"); - DBG_dump("", r_hashval, prf->get_block_size(prf)); - ) - prf->destroy(prf); - } - - /* Encrypt message (preserve st_iv and st_new_iv) */ - { - u_char old_iv[MAX_DIGEST_LEN]; - u_char new_iv[MAX_DIGEST_LEN]; - - u_int old_iv_len = st->st_iv_len; - u_int new_iv_len = st->st_new_iv_len; - - if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN) - return STF_INTERNAL_ERROR; - - memcpy(old_iv, st->st_iv, old_iv_len); - memcpy(new_iv, st->st_new_iv, new_iv_len); - - init_phase2_iv(st, &msgid); - if (!encrypt_message(&rbody, st)) - { - return STF_INTERNAL_ERROR; - } - - /* restore preserved st_iv and st_new_iv */ - memcpy(st->st_iv, old_iv, old_iv_len); - memcpy(st->st_new_iv, new_iv, new_iv_len); - st->st_iv_len = old_iv_len; - st->st_new_iv_len = new_iv_len; - } - - /* Send packet (preserve st_tpacket) */ - { - chunk_t saved_tpacket = st->st_tpacket; - - st->st_tpacket = chunk_create(reply.start, pbs_offset(&reply)); - send_packet(st, "ISAKMP notify"); - st->st_tpacket = saved_tpacket; - } - - return STF_IGNORE; -} - -/* - * DPD Out Initiator - */ -void dpd_outI(struct state *p2st) -{ - struct state *st; - u_int32_t seqno; - time_t tm; - time_t idle_time; - time_t delay = p2st->st_connection->dpd_delay; - time_t timeout = p2st->st_connection->dpd_timeout; - - /* find the newest related Phase 1 state */ - st = find_phase1_state(p2st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); - - if (st == NULL) - { - loglog(RC_LOG_SERIOUS, "DPD: Could not find newest phase 1 state"); - return; - } - - /* If no DPD, then get out of here */ - if (!st->st_dpd) - { - return; - } - - /* schedule the next periodic DPD event */ - event_schedule(EVENT_DPD, delay, p2st); - - /* Current time */ - tm = now(); - - /* Make sure we really need to invoke DPD */ - if (!was_eroute_idle(p2st, delay, &idle_time)) - { - DBG(DBG_CONTROL, - DBG_log("recent eroute activity %u seconds ago, " - "no need to send DPD notification" - , (int)idle_time) - ) - st->st_last_dpd = tm; - delete_dpd_event(st); - return; - } - - /* If an R_U_THERE has been sent or received recently, or if a - * companion Phase 2 SA has shown eroute activity, - * then we don't need to invoke DPD. - */ - if (tm < st->st_last_dpd + delay) - { - DBG(DBG_CONTROL, - DBG_log("recent DPD activity %u seconds ago, " - "no need to send DPD notification" - , (int)(tm - st->st_last_dpd)) - ) - return; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - return; - - if (!st->st_dpd_seqno) - { - rng_t *rng; - - /* Get a non-zero random value that has room to grow */ - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->get_bytes(rng, sizeof(st->st_dpd_seqno), (u_char *)&st->st_dpd_seqno); - rng->destroy(rng); - st->st_dpd_seqno &= 0x7fff; - st->st_dpd_seqno++; - } - seqno = htonl(st->st_dpd_seqno); - - if (send_isakmp_notification(st, R_U_THERE, &seqno, sizeof(seqno)) != STF_IGNORE) - { - loglog(RC_LOG_SERIOUS, "DPD: Could not send R_U_THERE"); - return; - } - DBG(DBG_CONTROL, - DBG_log("sent DPD notification R_U_THERE with seqno = %u", st->st_dpd_seqno) - ) - st->st_dpd_expectseqno = st->st_dpd_seqno++; - st->st_last_dpd = tm; - /* Only schedule a new timeout if there isn't one currently, - * or if it would be sooner than the current timeout. */ - if (st->st_dpd_event == NULL - || st->st_dpd_event->ev_time > tm + timeout) - { - delete_dpd_event(st); - event_schedule(EVENT_DPD_TIMEOUT, timeout, st); - } -} - -/* - * DPD in Initiator, out Responder - */ -stf_status -dpd_inI_outR(struct state *st, struct isakmp_notification *const n, pb_stream *pbs) -{ - time_t tm = now(); - u_int32_t seqno; - - if (st == NULL || !IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "DPD: Received R_U_THERE for unestablished ISAKMP SA"); - return STF_IGNORE; - } - if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2) - { - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid SPI length (%d)", n->isan_spisize); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) - { -#ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ -#else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid icookie (broken Cisco?)"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; -#endif - } - pbs->cur += COOKIE_SIZE; - - if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0) - { - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid rcookie (broken Cisco?)"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; - } - pbs->cur += COOKIE_SIZE; - - if (pbs_left(pbs) != sizeof(seqno)) - { - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid data length (%d)" - , (int) pbs_left(pbs)); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - seqno = ntohl(*(u_int32_t *)pbs->cur); - DBG(DBG_CONTROL, - DBG_log("received DPD notification R_U_THERE with seqno = %u", seqno) - ) - - if (st->st_dpd_peerseqno && seqno <= st->st_dpd_peerseqno) { - loglog(RC_LOG_SERIOUS, "DPD: Received old or duplicate R_U_THERE"); - return STF_IGNORE; - } - - st->st_dpd_peerseqno = seqno; - delete_dpd_event(st); - - if (send_isakmp_notification(st, R_U_THERE_ACK, pbs->cur, pbs_left(pbs)) != STF_IGNORE) - { - loglog(RC_LOG_SERIOUS, "DPD Info: could not send R_U_THERE_ACK"); - return STF_IGNORE; - } - DBG(DBG_CONTROL, - DBG_log("sent DPD notification R_U_THERE_ACK with seqno = %u", seqno) - ) - - st->st_last_dpd = tm; - return STF_IGNORE; -} - -/* - * DPD out Responder - */ -stf_status dpd_inR(struct state *st, struct isakmp_notification *const n, - pb_stream *pbs) -{ - u_int32_t seqno; - - if (st == NULL || !IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS - , "DPD: Received R_U_THERE_ACK for unestablished ISAKMP SA"); - return STF_FAIL; - } - - if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2) - { - loglog(RC_LOG_SERIOUS - , "DPD: R_U_THERE_ACK has invalid SPI length (%d)" - , n->isan_spisize); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) - { -#ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ -#else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid icookie"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; -#endif - } - pbs->cur += COOKIE_SIZE; - - if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0) - { -#ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ -#else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid rcookie"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; -#endif - } - pbs->cur += COOKIE_SIZE; - - if (pbs_left(pbs) != sizeof(seqno)) - { - loglog(RC_LOG_SERIOUS - , " DPD: R_U_THERE_ACK has invalid data length (%d)" - , (int) pbs_left(pbs)); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - seqno = ntohl(*(u_int32_t *)pbs->cur); - DBG(DBG_CONTROL, - DBG_log("received DPD notification R_U_THERE_ACK with seqno = %u" - , seqno) - ) - - if (!st->st_dpd_expectseqno && seqno != st->st_dpd_expectseqno) - { - loglog(RC_LOG_SERIOUS - , "DPD: R_U_THERE_ACK has unexpected sequence number %u (expected %u)" - , seqno, st->st_dpd_expectseqno); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - st->st_dpd_expectseqno = 0; - delete_dpd_event(st); - return STF_IGNORE; -} - -/* - * DPD Timeout Function - * - * This function is called when a timeout DPD_EVENT occurs. We set clear/trap - * both the SA and the eroutes, depending on what the connection definition - * tells us (either 'hold' or 'clear') - */ -void -dpd_timeout(struct state *st) -{ - struct state *newest_phase1_st; - connection_t *c = st->st_connection; - int action = st->st_connection->dpd_action; - char cname[BUF_LEN]; - - passert(action == DPD_ACTION_HOLD - || action == DPD_ACTION_CLEAR - || DPD_ACTION_RESTART); - - /* is there a newer phase1_state? */ - newest_phase1_st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); - if (newest_phase1_st != NULL && newest_phase1_st != st) - { - plog("DPD: Phase1 state #%ld has been superseded by #%ld" - " - timeout ignored" - , st->st_serialno, newest_phase1_st->st_serialno); - return; - } - - loglog(RC_LOG_SERIOUS, "DPD: No response from peer - declaring peer dead"); - - /* delete the state, which is probably in phase 2 */ - set_cur_connection(c); - plog("DPD: Terminating all SAs using this connection"); - delete_states_by_connection(c, TRUE); - reset_cur_connection(); - - switch (action) - { - case DPD_ACTION_HOLD: - /* dpdaction=hold - Wipe the SA's but %trap the eroute so we don't - * leak traffic. Also, being in %trap means new packets will - * force an initiation of the conn again. - */ - loglog(RC_LOG_SERIOUS, "DPD: Putting connection \"%s\" into %%trap", c->name); - if (c->kind == CK_INSTANCE) - { - delete_connection(c, TRUE); - } - break; - case DPD_ACTION_CLEAR: - /* dpdaction=clear - Wipe the SA & eroute - everything */ - loglog(RC_LOG_SERIOUS, "DPD: Clearing connection \"%s\"", c->name); - unroute_connection(c); - if (c->kind == CK_INSTANCE) - { - delete_connection(c, TRUE); - } - break; - case DPD_ACTION_RESTART: - /* dpdaction=restart - Restart connection, - * except if roadwarrior connection - */ - loglog(RC_LOG_SERIOUS, "DPD: Restarting connection \"%s\"", c->name); - unroute_connection(c); - - /* caching the connection name before deletion */ - strncpy(cname, c->name, BUF_LEN); - cname[BUF_LEN-1] = '\0'; - - if (c->kind == CK_INSTANCE) - { - delete_connection(c, TRUE); - } - initiate_connection(cname, NULL_FD); - break; - default: - loglog(RC_LOG_SERIOUS, "DPD: unknown action"); - } -} - diff --git a/src/pluto/ipsec_doi.h b/src/pluto/ipsec_doi.h deleted file mode 100644 index c11edaa94..000000000 --- a/src/pluto/ipsec_doi.h +++ /dev/null @@ -1,108 +0,0 @@ -/* IPsec DOI and Oakley resolution routines - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _IPSEC_DOI_H -#define _IPSEC_DOI_H - -#include "defs.h" - -extern void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np); - -extern void ipsecdoi_initiate(int whack_sock, struct connection *c - , lset_t policy, unsigned long try, so_serial_t replacing); - -extern void ipsecdoi_replace(struct state *st, unsigned long try); - -extern void init_phase2_iv(struct state *st, const msgid_t *msgid); - -extern stf_status quick_outI1(int whack_sock - , struct state *isakmp_sa - , struct connection *c - , lset_t policy - , unsigned long try - , so_serial_t replacing); - -extern state_transition_fn - main_inI1_outR1, - main_inR1_outI2, - main_inI2_outR2, - main_inR2_outI3, - main_inI3_outR3, - main_inR3, - quick_inI1_outR1, - quick_inR1_outI2, - quick_inI2; - -extern void send_delete(struct state *st); -extern void accept_delete(struct state *st, struct msg_digest *md - , struct payload_digest *p); -extern void close_message(pb_stream *pbs); -extern bool encrypt_message(pb_stream *pbs, struct state *st); - - -extern void send_notification_from_state(struct state *st, - enum state_kind state, u_int16_t type); -extern void send_notification_from_md(struct msg_digest *md, u_int16_t type); - -extern const char *init_pluto_vendorid(void); - -extern void dpd_outI(struct state *st); -extern stf_status dpd_inI_outR(struct state *st - , struct isakmp_notification *const n, pb_stream *n_pbs); -extern stf_status dpd_inR(struct state *st - , struct isakmp_notification *const n, pb_stream *n_pbs); -extern void dpd_timeout(struct state *st); - -/* START_HASH_PAYLOAD - * - * Emit a to-be-filled-in hash payload, noting the field start (r_hashval) - * and the start of the part of the message to be hashed (r_hash_start). - * This macro is magic. - * - it can cause the caller to return - * - it references variables local to the caller (r_hashval, r_hash_start, st) - */ -#define START_HASH_PAYLOAD(rbody, np) { \ - pb_stream hash_pbs; \ - if (!out_generic(np, &isakmp_hash_desc, &(rbody), &hash_pbs)) \ - return STF_INTERNAL_ERROR; \ - r_hashval = hash_pbs.cur; /* remember where to plant value */ \ - if (!out_zero(st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH")) \ - return STF_INTERNAL_ERROR; \ - close_output_pbs(&hash_pbs); \ - r_hash_start = (rbody).cur; /* hash from after HASH payload */ \ -} - -/* CHECK_QUICK_HASH - * - * This macro is magic -- it cannot be expressed as a function. - * - it causes the caller to return! - * - it declares local variables and expects the "do_hash" argument - * expression to reference them (hash_val, hash_pbs) - */ -#define CHECK_QUICK_HASH(md, do_hash, hash_name, msg_name) { \ - pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; \ - u_char hash_val[MAX_DIGEST_LEN]; \ - size_t hash_len = do_hash; \ - if (pbs_left(hash_pbs) != hash_len \ - || memcmp(hash_pbs->cur, hash_val, hash_len) != 0) \ - { \ - DBG_cond_dump(DBG_CRYPT, "received " hash_name ":", hash_pbs->cur, pbs_left(hash_pbs)); \ - loglog(RC_LOG_SERIOUS, "received " hash_name " does not match computed value in " msg_name); \ - /* XXX Could send notification back */ \ - return STF_FAIL + ISAKMP_INVALID_HASH_INFORMATION; \ - } \ - } - -#endif /* _IPSEC_DOI_H */ - diff --git a/src/pluto/kameipsec.h b/src/pluto/kameipsec.h deleted file mode 100644 index 5e9d8ce99..000000000 --- a/src/pluto/kameipsec.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef __IPSEC_H -#define __IPSEC_H 1 - -/* The definitions, required to talk to KAME racoon IKE. */ - -#define IPSEC_PORT_ANY 0 -#define IPSEC_ULPROTO_ANY 255 -#define IPSEC_PROTO_ANY 255 - -enum { - IPSEC_MODE_ANY = 0, /* We do not support this for SA */ - IPSEC_MODE_TRANSPORT = 1, - IPSEC_MODE_TUNNEL = 2 -}; - -enum { - IPSEC_DIR_ANY = 0, - IPSEC_DIR_INBOUND = 1, - IPSEC_DIR_OUTBOUND = 2, - IPSEC_DIR_FWD = 3, /* It is our own */ - IPSEC_DIR_MAX = 4, - IPSEC_DIR_INVALID = 5 -}; - -enum { - IPSEC_POLICY_DISCARD = 0, - IPSEC_POLICY_NONE = 1, - IPSEC_POLICY_IPSEC = 2, - IPSEC_POLICY_ENTRUST = 3, - IPSEC_POLICY_BYPASS = 4 -}; - -enum { - IPSEC_LEVEL_DEFAULT = 0, - IPSEC_LEVEL_USE = 1, - IPSEC_LEVEL_REQUIRE = 2, - IPSEC_LEVEL_UNIQUE = 3 -}; - -#define IPSEC_MANUAL_REQID_MAX 0x3fff - -#define IPSEC_REPLAYWSIZE 32 - -#define IP_IPSEC_POLICY 16 -#define IPV6_IPSEC_POLICY 34 - -#endif /* __IPSEC_H */ diff --git a/src/pluto/kernel.c b/src/pluto/kernel.c deleted file mode 100644 index e4729ef08..000000000 --- a/src/pluto/kernel.c +++ /dev/null @@ -1,2114 +0,0 @@ -/* routines that interface with the kernel's IPsec mechanism - * - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * Copyright (C) 1998-2002 D. Hugh Redelmeier - * Copyright (C) 1997 Angelos D. Keromytis - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stddef.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/queue.h> -#include <sys/wait.h> - -#include <sys/stat.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <freeswan.h> - -#include <library.h> -#include <hydra.h> -#include <crypto/rngs/rng.h> -#include <kernel/kernel_listener.h> - -#include <signal.h> -#include <sys/time.h> /* for select(2) */ -#include <sys/types.h> /* for select(2) */ -#include <pfkeyv2.h> -#include <pfkey.h> -#include "kameipsec.h" - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "state.h" -#include "timer.h" -#include "kernel.h" -#include "kernel_pfkey.h" -#include "log.h" -#include "ca.h" -#include "server.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "keys.h" -#include "crypto.h" -#include "nat_traversal.h" -#include "alg_info.h" -#include "kernel_alg.h" -#include "pluto.h" - - -bool can_do_IPcomp = TRUE; /* can system actually perform IPCOMP? */ - -/* test if the routes required for two different connections agree - * It is assumed that the destination subnets agree; we are only - * testing that the interfaces and nexthops match. - */ -#define routes_agree(c, d) ((c)->interface == (d)->interface \ - && sameaddr(&(c)->spd.this.host_nexthop, &(d)->spd.this.host_nexthop)) - -/* forward declaration */ -static bool shunt_eroute(connection_t *c, struct spd_route *sr, - enum routing_t rt_kind, unsigned int op, - const char *opname); - -static void set_text_said(char *text_said, const ip_address *dst, - ipsec_spi_t spi, int proto); - -/** - * Default IPsec SA config (e.g. to install trap policies). - */ -static ipsec_sa_cfg_t null_ipsec_sa = { - .mode = MODE_TRANSPORT, - .esp = { - .use = TRUE, - }, -}; - -/** - * Helper function that converts an ip_subnet to a traffic_selector_t. - */ -static traffic_selector_t *traffic_selector_from_subnet(const ip_subnet *client, - const u_int8_t proto) -{ - traffic_selector_t *ts; - host_t *net; - net = host_create_from_sockaddr((sockaddr_t*)&client->addr); - ts = traffic_selector_create_from_subnet(net, client->maskbits, proto, - net->get_port(net)); - return ts; -} - -/** - * Helper function that converts a traffic_selector_t to an ip_subnet. - */ -static ip_subnet subnet_from_traffic_selector(traffic_selector_t *ts) -{ - ip_subnet subnet; - host_t *net; - u_int8_t mask; - ts->to_subnet(ts, &net, &mask); - subnet.addr = *(ip_address*)net->get_sockaddr(net); - subnet.maskbits = mask; - net->destroy(net); - return subnet; -} - - -void record_and_initiate_opportunistic(const ip_subnet *ours, - const ip_subnet *his, - int transport_proto, const char *why) -{ - ip_address src, dst; - passert(samesubnettype(ours, his)); - - /* actually initiate opportunism */ - networkof(ours, &src); - networkof(his, &dst); - initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD); -} - -/* Generate Unique SPI numbers. - * - * The returned SPI is in network byte order. - */ -ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, - bool tunnel) -{ - host_t *host_src, *host_dst; - u_int32_t spi; - - host_src = host_create_from_sockaddr((sockaddr_t*)&sr->that.host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&sr->this.host_addr); - - if (hydra->kernel_interface->get_spi(hydra->kernel_interface, host_src, - host_dst, proto, sr->reqid, &spi) != SUCCESS) - { - spi = 0; - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - - return spi; -} - -/* Generate Unique CPI numbers. - * The result is returned as an SPI (4 bytes) in network order! - * The real bits are in the nework-low-order 2 bytes. - */ -ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel) -{ - host_t *host_src, *host_dst; - u_int16_t cpi; - - host_src = host_create_from_sockaddr((sockaddr_t*)&sr->that.host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&sr->this.host_addr); - - if (hydra->kernel_interface->get_cpi(hydra->kernel_interface, host_src, - host_dst, sr->reqid, &cpi) != SUCCESS) - - { - cpi = 0; - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - - return htonl((u_int32_t)ntohs(cpi)); -} - -/* Replace the shell metacharacters ', \, ", `, and $ in a character string - * by escape sequences consisting of their octal values - */ -static void escape_metachar(const char *src, char *dst, size_t dstlen) -{ - while (*src != '\0' && dstlen > 4) - { - switch (*src) - { - case '\'': - case '\\': - case '"': - case '`': - case '$': - sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src); - dst += 4; - dstlen -= 4; - break; - default: - *dst++ = *src; - dstlen--; - } - src++; - } - *dst = '\0'; -} - -/* invoke the updown script to do the routing and firewall commands required - * - * The user-specified updown script is run. Parameters are fed to it in - * the form of environment variables. All such environment variables - * have names starting with "PLUTO_". - * - * The operation to be performed is specified by PLUTO_VERB. This - * verb has a suffix "-host" if the client on this end is just the - * host; otherwise the suffix is "-client". If the address family - * of the host is IPv6, an extra suffix of "-v6" is added. - * - * "prepare-host" and "prepare-client" are used to delete a route - * that may exist (due to forces outside of Pluto). It is used to - * prepare for pluto creating a route. - * - * "route-host" and "route-client" are used to install a route. - * Since routing is based only on destination, the PLUTO_MY_CLIENT_* - * values are probably of no use (using them may signify a bug). - * - * "unroute-host" and "unroute-client" are used to delete a route. - * Since routing is based only on destination, the PLUTO_MY_CLIENT_* - * values are probably of no use (using them may signify a bug). - * - * "up-host" and "up-client" are run when an eroute is added (not replaced). - * They are useful for adjusting a firewall: usually for adding a rule - * to let processed packets flow between clients. Note that only - * one eroute may exist for a pair of client subnets but inbound - * IPsec SAs may persist without an eroute. - * - * "down-host" and "down-client" are run when an eroute is deleted. - * They are useful for adjusting a firewall. - */ - -#ifndef DEFAULT_UPDOWN -# define DEFAULT_UPDOWN "ipsec _updown" -#endif - -static bool do_command(connection_t *c, struct spd_route *sr, struct state *st, - const char *verb) -{ - char cmd[1536]; /* arbitrary limit on shell command length */ - const char *verb_suffix; - - /* figure out which verb suffix applies */ - { - const char *hs, *cs; - - switch (addrtypeof(&sr->this.host_addr)) - { - case AF_INET: - hs = "-host"; - cs = "-client"; - break; - case AF_INET6: - hs = "-host-v6"; - cs = "-client-v6"; - break; - default: - loglog(RC_LOG_SERIOUS, "unknown address family"); - return FALSE; - } - verb_suffix = subnetisaddr(&sr->this.client, &sr->this.host_addr) - ? hs : cs; - } - - /* form the command string */ - { - char - nexthop_str[sizeof("PLUTO_NEXT_HOP='' ") +ADDRTOT_BUF] = "", - srcip_str[sizeof("PLUTO_MY_SOURCEIP='' ")+ADDRTOT_BUF] = "", - me_str[ADDRTOT_BUF], - myid_str[BUF_LEN], - myclient_str[SUBNETTOT_BUF], - myclientnet_str[ADDRTOT_BUF], - myclientmask_str[ADDRTOT_BUF], - peer_str[ADDRTOT_BUF], - peerid_str[BUF_LEN], - peerclient_str[SUBNETTOT_BUF], - peerclientnet_str[ADDRTOT_BUF], - peerclientmask_str[ADDRTOT_BUF], - peerca_str[BUF_LEN], - mark_in[BUF_LEN] = "", - mark_out[BUF_LEN] = "", - udp_encap[BUF_LEN] = "", - xauth_id_str[BUF_LEN] = "", - secure_myid_str[BUF_LEN] = "", - secure_peerid_str[BUF_LEN] = "", - secure_peerca_str[BUF_LEN] = "", - secure_xauth_id_str[BUF_LEN] = ""; - ip_address ta; - pubkey_list_t *p; - - if (addrbytesptr(&sr->this.host_nexthop, NULL) - && !isanyaddr(&sr->this.host_nexthop)) - { - char *n; - - strcpy(nexthop_str, "PLUTO_NEXT_HOP='"); - n = nexthop_str + strlen(nexthop_str); - - addrtot(&sr->this.host_nexthop, 0 - ,n , sizeof(nexthop_str)-strlen(nexthop_str)); - strncat(nexthop_str, "' ", sizeof(nexthop_str)); - } - - if (!sr->this.host_srcip->is_anyaddr(sr->this.host_srcip)) - { - char *n; - - strcpy(srcip_str, "PLUTO_MY_SOURCEIP='"); - n = srcip_str + strlen(srcip_str); - snprintf(n, sizeof(srcip_str)-strlen(srcip_str), "%H", - sr->this.host_srcip); - strncat(srcip_str, "' ", sizeof(srcip_str)); - } - - if (sr->mark_in.value) - { - snprintf(mark_in, sizeof(mark_in), "PLUTO_MARK_IN='%u/0x%08x' ", - sr->mark_in.value, sr->mark_in.mask); - } - - if (sr->mark_out.value) - { - snprintf(mark_out, sizeof(mark_out), "PLUTO_MARK_OUT='%u/0x%08x' ", - sr->mark_out.value, sr->mark_out.mask); - } - - if (st && (st->nat_traversal & NAT_T_DETECTED)) - { - snprintf(udp_encap, sizeof(udp_encap), "PLUTO_UDP_ENC='%u' ", - sr->that.host_port); - } - - addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str)); - snprintf(myid_str, sizeof(myid_str), "%Y", sr->this.id); - escape_metachar(myid_str, secure_myid_str, sizeof(secure_myid_str)); - subnettot(&sr->this.client, 0, myclient_str, sizeof(myclientnet_str)); - networkof(&sr->this.client, &ta); - addrtot(&ta, 0, myclientnet_str, sizeof(myclientnet_str)); - maskof(&sr->this.client, &ta); - addrtot(&ta, 0, myclientmask_str, sizeof(myclientmask_str)); - - if (c->xauth_identity && - c->xauth_identity->get_type(c->xauth_identity) != ID_ANY) - { - snprintf(xauth_id_str, sizeof(xauth_id_str), "%Y", c->xauth_identity); - escape_metachar(xauth_id_str, secure_xauth_id_str, - sizeof(secure_xauth_id_str)); - snprintf(xauth_id_str, sizeof(xauth_id_str), "PLUTO_XAUTH_ID='%s' ", - secure_xauth_id_str); - } - - addrtot(&sr->that.host_addr, 0, peer_str, sizeof(peer_str)); - snprintf(peerid_str, sizeof(peerid_str), "%Y", sr->that.id); - escape_metachar(peerid_str, secure_peerid_str, sizeof(secure_peerid_str)); - subnettot(&sr->that.client, 0, peerclient_str, sizeof(peerclientnet_str)); - networkof(&sr->that.client, &ta); - addrtot(&ta, 0, peerclientnet_str, sizeof(peerclientnet_str)); - maskof(&sr->that.client, &ta); - addrtot(&ta, 0, peerclientmask_str, sizeof(peerclientmask_str)); - - for (p = pubkeys; p != NULL; p = p->next) - { - pubkey_t *key = p->key; - key_type_t type = key->public_key->get_type(key->public_key); - int pathlen; - - if (type == KEY_RSA && - sr->that.id->equals(sr->that.id, key->id) && - trusted_ca(key->issuer, sr->that.ca, &pathlen)) - { - if (key->issuer) - { - snprintf(peerca_str, BUF_LEN, "%Y", key->issuer); - escape_metachar(peerca_str, secure_peerca_str, BUF_LEN); - } - else - { - secure_peerca_str[0] = '\0'; - } - break; - } - } - - if (-1 == snprintf(cmd, sizeof(cmd) - , "2>&1 " /* capture stderr along with stdout */ - "PLUTO_VERSION='1.1' " /* change VERSION when interface spec changes */ - "PLUTO_VERB='%s%s' " - "PLUTO_CONNECTION='%s' " - "%s" /* optional PLUTO_NEXT_HOP */ - "PLUTO_INTERFACE='%s' " - "%s" /* optional PLUTO_HOST_ACCESS */ - "PLUTO_REQID='%u' " - "PLUTO_ME='%s' " - "PLUTO_MY_ID='%s' " - "PLUTO_MY_CLIENT='%s' " - "PLUTO_MY_CLIENT_NET='%s' " - "PLUTO_MY_CLIENT_MASK='%s' " - "PLUTO_MY_PORT='%u' " - "PLUTO_MY_PROTOCOL='%u' " - "PLUTO_PEER='%s' " - "PLUTO_PEER_ID='%s' " - "PLUTO_PEER_CLIENT='%s' " - "PLUTO_PEER_CLIENT_NET='%s' " - "PLUTO_PEER_CLIENT_MASK='%s' " - "PLUTO_PEER_PORT='%u' " - "PLUTO_PEER_PROTOCOL='%u' " - "PLUTO_PEER_CA='%s' " - "%s" /* optional PLUTO_MY_SRCIP */ - "%s" /* optional PLUTO_XAUTH_ID */ - "%s" /* optional PLUTO_MARK_IN */ - "%s" /* optional PLUTO_MARK_OUT */ - "%s" /* optional PLUTO_UDP_ENC */ - "%s" /* actual script */ - , verb, verb_suffix - , c->name - , nexthop_str - , c->interface->vname - , sr->this.hostaccess? "PLUTO_HOST_ACCESS='1' " : "" - , sr->reqid - , me_str - , secure_myid_str - , myclient_str - , myclientnet_str - , myclientmask_str - , sr->this.port - , sr->this.protocol - , peer_str - , secure_peerid_str - , peerclient_str - , peerclientnet_str - , peerclientmask_str - , sr->that.port - , sr->that.protocol - , secure_peerca_str - , srcip_str - , xauth_id_str - , mark_in - , mark_out - , udp_encap - , sr->this.updown == NULL? DEFAULT_UPDOWN : sr->this.updown)) - { - loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, verb_suffix); - return FALSE; - } - } - - DBG(DBG_CONTROL, DBG_log("executing %s%s: %s" - , verb, verb_suffix, cmd)); - - /* invoke the script, catching stderr and stdout - * It may be of concern that some file descriptors will - * be inherited. For the ones under our control, we - * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this. - * Any used by library routines (perhaps the resolver or syslog) - * will remain. - */ - FILE *f = popen(cmd, "r"); - - if (f == NULL) - { - loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix); - return FALSE; - } - - /* log any output */ - for (;;) - { - /* if response doesn't fit in this buffer, it will be folded */ - char resp[256]; - - if (fgets(resp, sizeof(resp), f) == NULL) - { - if (ferror(f)) - { - log_errno((e, "fgets failed on output of %s%s command" - , verb, verb_suffix)); - return FALSE; - } - else - { - passert(feof(f)); - break; - } - } - else - { - char *e = resp + strlen(resp); - - if (e > resp && e[-1] == '\n') - e[-1] = '\0'; /* trim trailing '\n' */ - plog("%s%s output: %s", verb, verb_suffix, resp); - } - } - - /* report on and react to return code */ - { - int r = pclose(f); - - if (r == -1) - { - log_errno((e, "pclose failed for %s%s command" - , verb, verb_suffix)); - return FALSE; - } - else if (WIFEXITED(r)) - { - if (WEXITSTATUS(r) != 0) - { - loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d" - , verb, verb_suffix, WEXITSTATUS(r)); - return FALSE; - } - } - else if (WIFSIGNALED(r)) - { - loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d" - , verb, verb_suffix, WTERMSIG(r)); - return FALSE; - } - else - { - loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d" - , verb, verb_suffix, r); - return FALSE; - } - } - return TRUE; -} - -/* Check that we can route (and eroute). Diagnose if we cannot. */ - -enum routability { - route_impossible = 0, - route_easy = 1, - route_nearconflict = 2, - route_farconflict = 3 -}; - -static enum routability could_route(connection_t *c) -{ - struct spd_route *esr, *rosr; - connection_t *ero /* who, if anyone, owns our eroute? */ - , *ro = route_owner(c, &rosr, &ero, &esr); /* who owns our route? */ - - /* it makes no sense to route a connection that is ISAKMP-only */ - if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy)) - { - loglog(RC_ROUTE, "cannot route an ISAKMP-only connection"); - return route_impossible; - } - - /* if this is a Road Warrior template, we cannot route. - * Opportunistic template is OK. - */ - if (c->kind == CK_TEMPLATE && !(c->policy & POLICY_OPPO)) - { - loglog(RC_ROUTE, "cannot route Road Warrior template"); - return route_impossible; - } - - /* if we don't know nexthop, we cannot route */ - if (isanyaddr(&c->spd.this.host_nexthop)) - { - loglog(RC_ROUTE, "cannot route connection without knowing our nexthop"); - return route_impossible; - } - - /* if routing would affect IKE messages, reject */ - if (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT - && c->spd.this.host_port != IKE_UDP_PORT - && addrinsubnet(&c->spd.that.host_addr, &c->spd.that.client)) - { - loglog(RC_LOG_SERIOUS, "cannot install route: peer is within its client"); - return route_impossible; - } - - /* If there is already a route for peer's client subnet - * and it disagrees about interface or nexthop, we cannot steal it. - * Note: if this connection is already routed (perhaps for another - * state object), the route will agree. - * This is as it should be -- it will arise during rekeying. - */ - if (ro != NULL && !routes_agree(ro, c)) - { - loglog(RC_LOG_SERIOUS, "cannot route -- route already in use for \"%s\"" - , ro->name); - return route_impossible; /* another connection already - using the eroute */ - } - - /* if there is an eroute for another connection, there is a problem */ - if (ero != NULL && ero != c) - { - connection_t *ero2, *ero_top; - connection_t *inside, *outside; - - /* - * note, wavesec (PERMANENT) goes *outside* and - * OE goes *inside* (TEMPLATE) - */ - inside = NULL; - outside= NULL; - if (ero->kind == CK_PERMANENT - && c->kind == CK_TEMPLATE) - { - outside = ero; - inside = c; - } - else if (c->kind == CK_PERMANENT - && ero->kind == CK_TEMPLATE) - { - outside = c; - inside = ero; - } - - /* okay, check again, with correct order */ - if (outside && outside->kind == CK_PERMANENT - && inside && inside->kind == CK_TEMPLATE) - { - char inst[CONN_INST_BUF]; - - /* this is a co-terminal attempt of the "near" kind. */ - /* when chaining, we chain from inside to outside */ - - /* XXX permit multiple deep connections? */ - passert(inside->policy_next == NULL); - - inside->policy_next = outside; - - /* since we are going to steal the eroute from the secondary - * policy, we need to make sure that it no longer thinks that - * it owns the eroute. - */ - outside->spd.eroute_owner = SOS_NOBODY; - outside->spd.routing = RT_UNROUTED_KEYED; - - /* set the priority of the new eroute owner to be higher - * than that of the current eroute owner - */ - inside->prio = outside->prio + 1; - - fmt_conn_instance(inside, inst); - - loglog(RC_LOG_SERIOUS - , "conflict on eroute (%s), switching eroute to %s and linking %s" - , inst, inside->name, outside->name); - - return route_nearconflict; - } - - /* look along the chain of policies for one with the same name */ - ero_top = ero; - - for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next) - { - if (ero2->kind == CK_TEMPLATE - && streq(ero2->name, c->name)) - break; - } - - /* If we fell of the end of the list, then we found no TEMPLATE - * so there must be a conflict that we can't resolve. - * As the names are not equal, then we aren't replacing/rekeying. - */ - if (ero2 == NULL) - { - char inst[CONN_INST_BUF]; - - fmt_conn_instance(ero, inst); - - loglog(RC_LOG_SERIOUS - , "cannot install eroute -- it is in use for \"%s\"%s #%lu" - , ero->name, inst, esr->eroute_owner); - return route_impossible; - } - } - return route_easy; -} - -bool trap_connection(connection_t *c) -{ - switch (could_route(c)) - { - case route_impossible: - return FALSE; - - case route_nearconflict: - case route_easy: - /* RT_ROUTED_TUNNEL is treated specially: we don't override - * because we don't want to lose track of the IPSEC_SAs etc. - */ - if (c->spd.routing < RT_ROUTED_TUNNEL) - { - return route_and_eroute(c, &c->spd, NULL); - } - return TRUE; - - case route_farconflict: - return FALSE; - } - - return FALSE; -} - -/** - * Delete any eroute for a connection and unroute it if route isn't shared - */ -void unroute_connection(connection_t *c) -{ - struct spd_route *sr; - enum routing_t cr; - - for (sr = &c->spd; sr; sr = sr->next) - { - cr = sr->routing; - - if (erouted(cr)) - { - /* cannot handle a live one */ - passert(sr->routing != RT_ROUTED_TUNNEL); - shunt_eroute(c, sr, RT_UNROUTED, ERO_DELETE, "delete"); - } - - sr->routing = RT_UNROUTED; /* do now so route_owner won't find us */ - - /* only unroute if no other connection shares it */ - if (routed(cr) && route_owner(c, NULL, NULL, NULL) == NULL) - { - (void) do_command(c, sr, NULL, "unroute"); - } - } -} - - -static void set_text_said(char *text_said, const ip_address *dst, - ipsec_spi_t spi, int proto) -{ - ip_said said; - - initsaid(dst, spi, proto, &said); - satot(&said, 0, text_said, SATOT_BUF); -} - - -/** - * Setup an IPsec route entry. - * op is one of the ERO_* operators. - */ -static bool raw_eroute(const ip_address *this_host, - const ip_subnet *this_client, - const ip_address *that_host, - const ip_subnet *that_client, - mark_t mark, - ipsec_spi_t spi, - unsigned int proto, - unsigned int satype, - unsigned int transport_proto, - ipsec_sa_cfg_t *sa, - unsigned int op, - const char *opname USED_BY_DEBUG) -{ - traffic_selector_t *ts_src, *ts_dst; - host_t *host_src, *host_dst; - policy_type_t type = POLICY_IPSEC; - policy_dir_t dir = POLICY_OUT; - policy_priority_t priority = POLICY_PRIORITY_DEFAULT; - char text_said[SATOT_BUF]; - bool ok = TRUE, - deleting = (op & ERO_MASK) == ERO_DELETE, - replacing = op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT); - - set_text_said(text_said, that_host, spi, proto); - - DBG(DBG_CONTROL | DBG_KERNEL, - { - int sport = ntohs(portof(&this_client->addr)); - int dport = ntohs(portof(&that_client->addr)); - char mybuf[SUBNETTOT_BUF]; - char peerbuf[SUBNETTOT_BUF]; - - subnettot(this_client, 0, mybuf, sizeof(mybuf)); - subnettot(that_client, 0, peerbuf, sizeof(peerbuf)); - DBG_log("%s eroute %s:%d -> %s:%d => %s:%d" - , opname, mybuf, sport, peerbuf, dport - , text_said, transport_proto); - }); - - if (satype == SADB_X_SATYPE_INT) - { - switch (ntohl(spi)) - { - case SPI_PASS: - type = POLICY_PASS; - break; - case SPI_DROP: - case SPI_REJECT: - type = POLICY_DROP; - break; - case SPI_TRAP: - case SPI_TRAPSUBNET: - case SPI_HOLD: - if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) - { - return TRUE; - } - priority = POLICY_PRIORITY_ROUTED; - break; - } - } - - if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) - { - dir = POLICY_IN; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)this_host); - host_dst = host_create_from_sockaddr((sockaddr_t*)that_host); - ts_src = traffic_selector_from_subnet(this_client, transport_proto); - ts_dst = traffic_selector_from_subnet(that_client, transport_proto); - - if (deleting || replacing) - { - hydra->kernel_interface->del_policy(hydra->kernel_interface, - ts_src, ts_dst, dir, sa->reqid, mark, priority); - } - - if (!deleting) - { - ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, - host_src, host_dst, ts_src, ts_dst, dir, type, sa, - mark, priority) == SUCCESS; - } - - if (dir == POLICY_IN) - { /* handle forward policy */ - dir = POLICY_FWD; - if (deleting || replacing) - { - hydra->kernel_interface->del_policy(hydra->kernel_interface, - ts_src, ts_dst, dir, sa->reqid, mark, priority); - } - - if (!deleting && ok && - (sa->mode == MODE_TUNNEL || satype == SADB_X_SATYPE_INT)) - { - ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, - host_src, host_dst, ts_src, ts_dst, dir, type, sa, - mark, priority) == SUCCESS; - } - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - ts_src->destroy(ts_src); - ts_dst->destroy(ts_dst); - - return ok; -} - -static bool eroute_connection(struct spd_route *sr, ipsec_spi_t spi, - unsigned int proto, unsigned int satype, - ipsec_sa_cfg_t *sa, unsigned int op, - const char *opname) -{ - const ip_address *peer = &sr->that.host_addr; - char buf2[256]; - bool ok; - - snprintf(buf2, sizeof(buf2) - , "eroute_connection %s", opname); - - if (proto == SA_INT) - { - peer = aftoinfo(addrtypeof(peer))->any; - } - ok = raw_eroute(peer, &sr->that.client, - &sr->this.host_addr, &sr->this.client, sr->mark_in, - spi, proto, satype, sr->this.protocol, - sa, op | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT), buf2); - return raw_eroute(&sr->this.host_addr, &sr->this.client, peer, - &sr->that.client, sr->mark_out, spi, proto, satype, - sr->this.protocol, sa, op, buf2) && ok; -} - -/* assign a bare hold to a connection */ - -bool assign_hold(connection_t *c USED_BY_DEBUG, struct spd_route *sr, - int transport_proto, - const ip_address *src, - const ip_address *dst) -{ - /* either the automatically installed %hold eroute is broad enough - * or we try to add a broader one and delete the automatic one. - * Beware: this %hold might be already handled, but still squeak - * through because of a race. - */ - enum routing_t ro = sr->routing /* routing, old */ - , rn = ro; /* routing, new */ - - passert(LHAS(LELEM(CK_PERMANENT) | LELEM(CK_INSTANCE), c->kind)); - /* figure out what routing should become */ - switch (ro) - { - case RT_UNROUTED: - rn = RT_UNROUTED_HOLD; - break; - case RT_ROUTED_PROSPECTIVE: - rn = RT_ROUTED_HOLD; - break; - default: - /* no change: this %hold is old news and should just be deleted */ - break; - } - - /* We need a broad %hold - * First we ensure that there is a broad %hold. - * There may already be one (race condition): no need to create one. - * There may already be a %trap: replace it. - * There may not be any broad eroute: add %hold. - */ - if (rn != ro) - { - if (erouted(ro) - ? !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT, - &null_ipsec_sa, ERO_REPLACE, - "replace %trap with broad %hold") - : !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT, - &null_ipsec_sa, ERO_ADD, "add broad %hold")) - { - return FALSE; - } - } - sr->routing = rn; - return TRUE; -} - -/* install or remove eroute for SA Group */ -static bool sag_eroute(struct state *st, struct spd_route *sr, - unsigned op, const char *opname) -{ - u_int inner_proto, inner_satype; - ipsec_spi_t inner_spi = 0; - ipsec_sa_cfg_t sa = { - .mode = MODE_TRANSPORT, - }; - bool tunnel = FALSE; - - if (st->st_ah.present) - { - inner_spi = st->st_ah.attrs.spi; - inner_proto = SA_AH; - inner_satype = SADB_SATYPE_AH; - sa.ah.use = TRUE; - sa.ah.spi = inner_spi; - tunnel |= st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; - } - - if (st->st_esp.present) - { - inner_spi = st->st_esp.attrs.spi; - inner_proto = SA_ESP; - inner_satype = SADB_SATYPE_ESP; - sa.esp.use = TRUE; - sa.esp.spi = inner_spi; - tunnel |= st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; - } - - if (st->st_ipcomp.present) - { - inner_spi = st->st_ipcomp.attrs.spi; - inner_proto = SA_COMP; - inner_satype = SADB_X_SATYPE_COMP; - sa.ipcomp.transform = st->st_ipcomp.attrs.transid; - sa.ipcomp.cpi = htons(ntohl(inner_spi)); - tunnel |= st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; - } - - if (!sa.ah.use && !sa.esp.use && !sa.ipcomp.transform) - { - impossible(); /* no transform at all! */ - } - - if (tunnel) - { - inner_spi = st->st_tunnel_out_spi; - inner_proto = SA_IPIP; - inner_satype = SADB_X_SATYPE_IPIP; - sa.mode = MODE_TUNNEL; - } - - sa.reqid = sr->reqid; - - return eroute_connection(sr, inner_spi, inner_proto, inner_satype, - &sa, op, opname); -} - -/* compute a (host-order!) SPI to implement the policy in connection c */ -ipsec_spi_t -shunt_policy_spi(connection_t *c, bool prospective) -{ - /* note: these are in host order :-( */ - static const ipsec_spi_t shunt_spi[] = - { - SPI_TRAP, /* --initiateontraffic */ - SPI_PASS, /* --pass */ - SPI_DROP, /* --drop */ - SPI_REJECT, /* --reject */ - }; - - static const ipsec_spi_t fail_spi[] = - { - 0, /* --none*/ - SPI_PASS, /* --failpass */ - SPI_DROP, /* --faildrop */ - SPI_REJECT, /* --failreject */ - }; - - return prospective - ? shunt_spi[(c->policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT] - : fail_spi[(c->policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT]; -} - -/* Add/replace/delete a shunt eroute. - * Such an eroute determines the fate of packets without the use - * of any SAs. These are defaults, in effect. - * If a negotiation has not been attempted, use %trap. - * If negotiation has failed, the choice between %trap/%pass/%drop/%reject - * is specified in the policy of connection c. - */ -static bool shunt_eroute(connection_t *c, struct spd_route *sr, - enum routing_t rt_kind, - unsigned int op, const char *opname) -{ - /* We are constructing a special SAID for the eroute. - * The destination doesn't seem to matter, but the family does. - * The protocol is SA_INT -- mark this as shunt. - * The satype has no meaning, but is required for PF_KEY header! - * The SPI signifies the kind of shunt. - */ - ipsec_spi_t spi = shunt_policy_spi(c, rt_kind == RT_ROUTED_PROSPECTIVE); - - if (spi == 0) - { - /* we're supposed to end up with no eroute: rejig op and opname */ - switch (op) - { - case ERO_REPLACE: - /* replace with nothing == delete */ - op = ERO_DELETE; - opname = "delete"; - break; - case ERO_ADD: - /* add nothing == do nothing */ - return TRUE; - case ERO_DELETE: - /* delete remains delete */ - break; - default: - bad_case(op); - } - } - if (sr->routing == RT_ROUTED_ECLIPSED && c->kind == CK_TEMPLATE) - { - /* We think that we have an eroute, but we don't. - * Adjust the request and account for eclipses. - */ - passert(eclipsable(sr)); - switch (op) - { - case ERO_REPLACE: - /* really an add */ - op = ERO_ADD; - opname = "replace eclipsed"; - eclipse_count--; - break; - case ERO_DELETE: - /* delete unnecessary: we don't actually have an eroute */ - eclipse_count--; - return TRUE; - case ERO_ADD: - default: - bad_case(op); - } - } - else if (eclipse_count > 0 && op == ERO_DELETE && eclipsable(sr)) - { - /* maybe we are uneclipsing something */ - struct spd_route *esr; - connection_t *ue = eclipsed(c, &esr); - - if (ue != NULL) - { - esr->routing = RT_ROUTED_PROSPECTIVE; - return shunt_eroute(ue, esr - , RT_ROUTED_PROSPECTIVE, ERO_REPLACE, "restoring eclipsed"); - } - } - - return eroute_connection(sr, htonl(spi), SA_INT, SADB_X_SATYPE_INT, - &null_ipsec_sa, op, opname); -} - -static bool setup_half_ipsec_sa(struct state *st, bool inbound) -{ - host_t *host_src, *host_dst; - connection_t *c = st->st_connection; - struct end *src, *dst; - ipsec_mode_t mode = MODE_TRANSPORT; - ipsec_sa_cfg_t sa = { .mode = 0 }; - lifetime_cfg_t lt_none = { .time = { .rekey = 0 } }; - mark_t mark; - bool ok = TRUE; - /* SPIs, saved for undoing, if necessary */ - struct kernel_sa said[EM_MAXRELSPIS], *said_next = said; - if (inbound) - { - src = &c->spd.that; - dst = &c->spd.this; - mark = c->spd.mark_in; - } - else - { - src = &c->spd.this; - dst = &c->spd.that; - mark = c->spd.mark_out; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL - || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL - || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - mode = MODE_TUNNEL; - } - - sa.mode = mode; - sa.reqid = c->spd.reqid; - - memset(said, 0, sizeof(said)); - - /* set up IPCOMP SA, if any */ - - if (st->st_ipcomp.present) - { - ipsec_spi_t ipcomp_spi = inbound ? st->st_ipcomp.our_spi - : st->st_ipcomp.attrs.spi; - - switch (st->st_ipcomp.attrs.transid) - { - case IPCOMP_DEFLATE: - break; - - default: - loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented", - enum_name(&ipcomp_transformid_names, - st->st_ipcomp.attrs.transid)); - goto fail; - } - - sa.ipcomp.cpi = htons(ntohl(ipcomp_spi)); - sa.ipcomp.transform = st->st_ipcomp.attrs.transid; - - said_next->spi = ipcomp_spi; - said_next->proto = IPPROTO_COMP; - - if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, - host_dst, ipcomp_spi, said_next->proto, c->spd.reqid, - mark, 0, <_none, ENCR_UNDEFINED, chunk_empty, - AUTH_UNDEFINED, chunk_empty, mode, - st->st_ipcomp.attrs.transid, 0 /* cpi */, FALSE, FALSE, - inbound, NULL, NULL) != SUCCESS) - { - goto fail; - } - said_next++; - mode = MODE_TRANSPORT; - } - - /* set up ESP SA, if any */ - - if (st->st_esp.present) - { - ipsec_spi_t esp_spi = inbound ? st->st_esp.our_spi - : st->st_esp.attrs.spi; - u_char *esp_dst_keymat = inbound ? st->st_esp.our_keymat - : st->st_esp.peer_keymat; - bool encap = st->nat_traversal & NAT_T_DETECTED; - encryption_algorithm_t enc_alg; - integrity_algorithm_t auth_alg; - const struct esp_info *ei; - chunk_t enc_key, auth_key; - u_int16_t key_len; - - if ((ei = kernel_alg_esp_info(st->st_esp.attrs.transid, - st->st_esp.attrs.auth)) == NULL) - { - loglog(RC_LOG_SERIOUS, "ESP transform %s / auth %s" - " not implemented yet", - enum_name(&esp_transform_names, st->st_esp.attrs.transid), - enum_name(&auth_alg_names, st->st_esp.attrs.auth)); - goto fail; - } - - key_len = st->st_esp.attrs.key_len / 8; - if (key_len) - { - /* XXX: must change to check valid _range_ key_len */ - if (key_len > ei->enckeylen) - { - loglog(RC_LOG_SERIOUS, "ESP transform %s: key_len=%d > %d", - enum_name(&esp_transform_names, st->st_esp.attrs.transid), - (int)key_len, (int)ei->enckeylen); - goto fail; - } - } - else - { - key_len = ei->enckeylen; - } - - switch (ei->transid) - { - case ESP_3DES: - /* 168 bits in kernel, need 192 bits for keymat_len */ - if (key_len == 21) - { - key_len = 24; - } - break; - case ESP_DES: - /* 56 bits in kernel, need 64 bits for keymat_len */ - if (key_len == 7) - { - key_len = 8; - } - break; - case ESP_AES_CCM_8: - case ESP_AES_CCM_12: - case ESP_AES_CCM_16: - key_len += 3; - break; - case ESP_AES_GCM_8: - case ESP_AES_GCM_12: - case ESP_AES_GCM_16: - case ESP_AES_CTR: - case ESP_AES_GMAC: - key_len += 4; - break; - default: - break; - } - - if (encap) - { - host_src->set_port(host_src, src->host_port); - host_dst->set_port(host_dst, dst->host_port); - // st->nat_oa is currently unused - } - - /* divide up keying material */ - enc_alg = encryption_algorithm_from_esp(st->st_esp.attrs.transid); - enc_key.ptr = esp_dst_keymat; - enc_key.len = key_len; - auth_alg = integrity_algorithm_from_esp(st->st_esp.attrs.auth); - auth_alg = auth_alg ? : AUTH_UNDEFINED; - auth_key.ptr = esp_dst_keymat + key_len; - auth_key.len = ei->authkeylen; - - sa.esp.use = TRUE; - sa.esp.spi = esp_spi; - - said_next->spi = esp_spi; - said_next->proto = IPPROTO_ESP; - - if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, - host_dst, esp_spi, said_next->proto, c->spd.reqid, - mark, 0, <_none, enc_alg, enc_key, - auth_alg, auth_key, mode, IPCOMP_NONE, 0 /* cpi */, - encap, FALSE, inbound, NULL, NULL) != SUCCESS) - { - goto fail; - } - said_next++; - mode = MODE_TRANSPORT; - } - - /* set up AH SA, if any */ - - if (st->st_ah.present) - { - ipsec_spi_t ah_spi = inbound ? st->st_ah.our_spi - : st->st_ah.attrs.spi; - u_char *ah_dst_keymat = inbound ? st->st_ah.our_keymat - : st->st_ah.peer_keymat; - integrity_algorithm_t auth_alg; - chunk_t auth_key; - - auth_alg = integrity_algorithm_from_esp(st->st_ah.attrs.auth); - auth_key.ptr = ah_dst_keymat; - auth_key.len = st->st_ah.keymat_len; - - sa.ah.use = TRUE; - sa.ah.spi = ah_spi; - - said_next->spi = ah_spi; - said_next->proto = IPPROTO_AH; - - if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, - host_dst, ah_spi, said_next->proto, c->spd.reqid, - mark, 0, <_none, ENCR_UNDEFINED, chunk_empty, - auth_alg, auth_key, mode, IPCOMP_NONE, 0 /* cpi */, - FALSE, FALSE, inbound, NULL, NULL) != SUCCESS) - { - goto fail; - } - said_next++; - mode = MODE_TRANSPORT; - } - - goto cleanup; - -fail: - /* undo the done SPIs */ - while (said_next-- != said) - { - hydra->kernel_interface->del_sa(hydra->kernel_interface, host_src, - host_dst, said_next->spi, - said_next->proto, 0 /* cpi */, - mark); - } - ok = FALSE; - -cleanup: - host_src->destroy(host_src); - host_dst->destroy(host_dst); - return ok; -} - -static bool teardown_half_ipsec_sa(struct state *st, bool inbound) -{ - connection_t *c = st->st_connection; - const struct end *src, *dst; - host_t *host_src, *host_dst; - ipsec_spi_t spi; - mark_t mark; - bool result = TRUE; - - if (inbound) - { - src = &c->spd.that; - dst = &c->spd.this; - mark = c->spd.mark_in; - } - else - { - src = &c->spd.this; - dst = &c->spd.that; - mark = c->spd.mark_out; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - if (st->st_ah.present) - { - spi = inbound ? st->st_ah.our_spi : st->st_ah.attrs.spi; - result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, - host_src, host_dst, spi, IPPROTO_AH, - 0 /* cpi */, mark) == SUCCESS; - } - - if (st->st_esp.present) - { - spi = inbound ? st->st_esp.our_spi : st->st_esp.attrs.spi; - result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, - host_src, host_dst, spi, IPPROTO_ESP, - 0 /* cpi */, mark) == SUCCESS; - } - - if (st->st_ipcomp.present) - { - spi = inbound ? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi; - result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, - host_src, host_dst, spi, IPPROTO_COMP, - 0 /* cpi */, mark) == SUCCESS; - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - - return result; -} - -/* - * get information about a given sa - */ -bool get_sa_info(struct state *st, bool inbound, u_int *bytes, time_t *use_time) -{ - connection_t *c = st->st_connection; - traffic_selector_t *ts_src = NULL, *ts_dst = NULL; - host_t *host_src = NULL, *host_dst = NULL; - const struct end *src, *dst; - ipsec_spi_t spi; - mark_t mark; - u_int64_t bytes_kernel = 0; - bool result = FALSE; - - *use_time = UNDEFINED_TIME; - - if (!st->st_esp.present) - { - goto failed; - } - - if (inbound) - { - src = &c->spd.that; - dst = &c->spd.this; - mark = c->spd.mark_in; - spi = st->st_esp.our_spi; - } - else - { - src = &c->spd.this; - dst = &c->spd.that; - mark = c->spd.mark_out; - spi = st->st_esp.attrs.spi; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - switch(hydra->kernel_interface->query_sa(hydra->kernel_interface, host_src, - host_dst, spi, IPPROTO_ESP, - mark, &bytes_kernel)) - { - case FAILED: - goto failed; - case SUCCESS: - *bytes = bytes_kernel; - break; - case NOT_SUPPORTED: - default: - break; - } - - if (st->st_serialno == c->spd.eroute_owner) - { - u_int32_t time_kernel; - - ts_src = traffic_selector_from_subnet(&src->client, src->protocol); - ts_dst = traffic_selector_from_subnet(&dst->client, dst->protocol); - - if (hydra->kernel_interface->query_policy(hydra->kernel_interface, - ts_src, ts_dst, inbound ? POLICY_IN : POLICY_OUT, - mark, &time_kernel) != SUCCESS) - { - goto failed; - } - *use_time = time_kernel; - - if (inbound && - st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - if (hydra->kernel_interface->query_policy(hydra->kernel_interface, - ts_src, ts_dst, POLICY_FWD, mark, - &time_kernel) != SUCCESS) - { - goto failed; - } - *use_time = max(*use_time, time_kernel); - } - } - - result = TRUE; - -failed: - DESTROY_IF(host_src); - DESTROY_IF(host_dst); - DESTROY_IF(ts_src); - DESTROY_IF(ts_dst); - return result; -} - -/** - * Handler for kernel events (called by thread-pool thread) - */ -kernel_listener_t *kernel_handler; - -/** - * Data for acquire events - */ -typedef struct { - /** Subnets */ - ip_subnet src, dst; - /** Transport protocol */ - int proto; -} acquire_data_t; - -/** - * Callback for acquire events (called by main thread) - */ -void handle_acquire(acquire_data_t *this) -{ - record_and_initiate_opportunistic(&this->src, &this->dst, this->proto, - "%acquire"); -} - -METHOD(kernel_listener_t, acquire, bool, - kernel_listener_t *this, u_int32_t reqid, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts) -{ - if (src_ts && dst_ts) - { - acquire_data_t *data; - DBG(DBG_CONTROL, - DBG_log("creating acquire event for policy %R === %R " - "with reqid {%u}", src_ts, dst_ts, reqid)); - INIT(data, - .src = subnet_from_traffic_selector(src_ts), - .dst = subnet_from_traffic_selector(dst_ts), - .proto = src_ts->get_protocol(src_ts), - ); - pluto->events->queue(pluto->events, (void*)handle_acquire, data, free); - } - else - { - DBG(DBG_CONTROL, - DBG_log("ignoring acquire without traffic selectors for policy " - "with reqid {%u}", reqid)); - } - DESTROY_IF(src_ts); - DESTROY_IF(dst_ts); - return TRUE; -} - -/** - * Data for mapping events - */ -typedef struct { - /** reqid, spi of affected SA */ - u_int32_t reqid, spi; - /** new endpont */ - ip_address new_end; -} mapping_data_t; - -/** - * Callback for mapping events (called by main thread) - */ -void handle_mapping(mapping_data_t *this) -{ - process_nat_t_new_mapping(this->reqid, this->spi, &this->new_end); -} - - -METHOD(kernel_listener_t, mapping, bool, - kernel_listener_t *this, u_int32_t reqid, u_int32_t spi, host_t *remote) -{ - mapping_data_t *data; - DBG(DBG_CONTROL, - DBG_log("creating mapping event for SA with SPI %.8x and reqid {%u}", - spi, reqid)); - INIT(data, - .reqid = reqid, - .spi = spi, - .new_end = *(ip_address*)remote->get_sockaddr(remote), - ); - pluto->events->queue(pluto->events, (void*)handle_mapping, data, free); - return TRUE; -} - -void init_kernel(void) -{ - /* register SA types that we can negotiate */ - can_do_IPcomp = FALSE; /* until we get a response from the kernel */ - pfkey_register(); - - INIT(kernel_handler, - .acquire = _acquire, - .mapping = _mapping, - ); - hydra->kernel_interface->add_listener(hydra->kernel_interface, - kernel_handler); -} - -void kernel_finalize() -{ - hydra->kernel_interface->remove_listener(hydra->kernel_interface, - kernel_handler); - free(kernel_handler); -} - -/* Note: install_inbound_ipsec_sa is only used by the Responder. - * The Responder will subsequently use install_ipsec_sa for the outbound. - * The Initiator uses install_ipsec_sa to install both at once. - */ -bool install_inbound_ipsec_sa(struct state *st) -{ - connection_t *const c = st->st_connection; - - /* If our peer has a fixed-address client, check if we already - * have a route for that client that conflicts. We will take this - * as proof that that route and the connections using it are - * obsolete and should be eliminated. Interestingly, this is - * the only case in which we can tell that a connection is obsolete. - */ - passert(c->kind == CK_PERMANENT || c->kind == CK_INSTANCE); - if (c->spd.that.has_client) - { - for (;;) - { - struct spd_route *esr; - connection_t *o = route_owner(c, &esr, NULL, NULL); - - if (o == NULL) - { - break; /* nobody has a route */ - } - - /* note: we ignore the client addresses at this end */ - if (sameaddr(&o->spd.that.host_addr, &c->spd.that.host_addr) && - o->interface == c->interface) - { - break; /* existing route is compatible */ - } - - if (o->kind == CK_TEMPLATE && streq(o->name, c->name)) - { - break; /* ??? is this good enough?? */ - } - - loglog(RC_LOG_SERIOUS, "route to peer's client conflicts with \"%s\" %s; releasing old connection to free the route" - , o->name, ip_str(&o->spd.that.host_addr)); - release_connection(o, FALSE); - } - } - - DBG(DBG_CONTROL, DBG_log("install_inbound_ipsec_sa() checking if we can route")); - /* check that we will be able to route and eroute */ - switch (could_route(c)) - { - case route_easy: - case route_nearconflict: - break; - default: - return FALSE; - } - - /* (attempt to) actually set up the SAs */ - return setup_half_ipsec_sa(st, TRUE); -} - -/* Install a route and then a prospective shunt eroute or an SA group eroute. - * Assumption: could_route gave a go-ahead. - * Any SA Group must have already been created. - * On failure, steps will be unwound. - */ -bool route_and_eroute(connection_t *c, struct spd_route *sr, struct state *st) -{ - struct spd_route *esr; - struct spd_route *rosr; - connection_t *ero /* who, if anyone, owns our eroute? */ - , *ro = route_owner(c, &rosr, &ero, &esr); - bool eroute_installed = FALSE - , firewall_notified = FALSE - , route_installed = FALSE; - - connection_t *ero_top; - - DBG(DBG_CONTROLMORE, - DBG_log("route_and_eroute with c: %s (next: %s) ero:%s esr:{%p} ro:%s rosr:{%p} and state: %lu" - , c->name - , (c->policy_next ? c->policy_next->name : "none") - , ero ? ero->name : "null" - , esr - , ro ? ro->name : "null" - , rosr - , st ? st->st_serialno : 0)); - - /* look along the chain of policies for one with the same name */ - ero_top = ero; - -#if 0 - /* XXX - mcr this made sense before, and likely will make sense - * again, so I'l leaving this to remind me what is up */ - if (ero!= NULL && ero->routing == RT_UNROUTED_KEYED) - ero = NULL; - - for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next) - if ((ero2->kind == CK_TEMPLATE || ero2->kind==CK_SECONDARY) - && streq(ero2->name, c->name)) - break; -#endif - - /* install the eroute */ - - if (ero != NULL) - { - /* We're replacing an eroute */ - - /* if no state provided, then install a shunt for later */ - if (st == NULL) - { - eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE - , ERO_REPLACE, "replace"); - } - else - { - eroute_installed = sag_eroute(st, sr, ERO_REPLACE, "replace"); - } -#if 0 - /* XXX - MCR. I previously felt that this was a bogus check */ - if (ero != NULL && ero != c && esr != sr) - { - /* By elimination, we must be eclipsing ero. Check. */ - passert(ero->kind == CK_TEMPLATE && streq(ero->name, c->name)); - passert(LHAS(LELEM(RT_ROUTED_PROSPECTIVE) | LELEM(RT_ROUTED_ECLIPSED) - , esr->routing)); - passert(samesubnet(&esr->this.client, &sr->this.client) - && samesubnet(&esr->that.client, &sr->that.client)); - } -#endif - } - else - { - /* we're adding an eroute */ - - /* if no state provided, then install a shunt for later */ - if (st == NULL) - { - eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE - , ERO_ADD, "add"); - } - else - { - eroute_installed = sag_eroute(st, sr, ERO_ADD, "add"); - } - } - - /* notify the firewall of a new tunnel */ - - if (eroute_installed) - { - /* do we have to notify the firewall? Yes, if we are installing - * a tunnel eroute and the firewall wasn't notified - * for a previous tunnel with the same clients. Any Previous - * tunnel would have to be for our connection, so the actual - * test is simple. - */ - firewall_notified = st == NULL /* not a tunnel eroute */ - || sr->eroute_owner != SOS_NOBODY /* already notified */ - || do_command(c, sr, st, "up"); /* go ahead and notify */ - } - - /* install the route */ - - DBG(DBG_CONTROL, - DBG_log("route_and_eroute: firewall_notified: %s" - , firewall_notified ? "true" : "false")); - if (!firewall_notified) - { - /* we're in trouble -- don't do routing */ - } - else if (ro == NULL) - { - /* a new route: no deletion required, but preparation is */ - (void) do_command(c, sr, st, "prepare"); /* just in case; ignore failure */ - route_installed = do_command(c, sr, st, "route"); - } - else if (routed(sr->routing) || routes_agree(ro, c)) - { - route_installed = TRUE; /* nothing to be done */ - } - else - { - /* Some other connection must own the route - * and the route must disagree. But since could_route - * must have allowed our stealing it, we'll do so. - * - * A feature of LINUX allows us to install the new route - * before deleting the old if the nexthops differ. - * This reduces the "window of vulnerability" when packets - * might flow in the clear. - */ - if (sameaddr(&sr->this.host_nexthop, &esr->this.host_nexthop)) - { - (void) do_command(ro, sr, st, "unroute"); - route_installed = do_command(c, sr, st, "route"); - } - else - { - route_installed = do_command(c, sr, st, "route"); - (void) do_command(ro, sr, st, "unroute"); - } - - /* record unrouting */ - if (route_installed) - { - do { - passert(!erouted(rosr->routing)); - rosr->routing = RT_UNROUTED; - - /* no need to keep old value */ - ro = route_owner(c, &rosr, NULL, NULL); - } while (ro != NULL); - } - } - - /* all done -- clean up */ - if (route_installed) - { - /* Success! */ - - if (ero != NULL && ero != c) - { - /* check if ero is an ancestor of c. */ - connection_t *ero2; - - for (ero2 = c; ero2 != NULL && ero2 != c; ero2 = ero2->policy_next) - ; - - if (ero2 == NULL) - { - /* By elimination, we must be eclipsing ero. Checked above. */ - if (ero->spd.routing != RT_ROUTED_ECLIPSED) - { - ero->spd.routing = RT_ROUTED_ECLIPSED; - eclipse_count++; - } - } - } - - if (st == NULL) - { - passert(sr->eroute_owner == SOS_NOBODY); - sr->routing = RT_ROUTED_PROSPECTIVE; - } - else - { - char cib[CONN_INST_BUF]; - sr->routing = RT_ROUTED_TUNNEL; - - DBG(DBG_CONTROL, - DBG_log("route_and_eroute: instance \"%s\"%s, setting eroute_owner {spd=%p,sr=%p} to #%ld (was #%ld) (newest_ipsec_sa=#%ld)" - , st->st_connection->name - , (fmt_conn_instance(st->st_connection, cib), cib) - , &st->st_connection->spd, sr - , st->st_serialno - , sr->eroute_owner - , st->st_connection->newest_ipsec_sa)); - sr->eroute_owner = st->st_serialno; - } - - return TRUE; - } - else - { - /* Failure! Unwind our work. */ - if (firewall_notified && sr->eroute_owner == SOS_NOBODY) - (void) do_command(c, sr, st, "down"); - - if (eroute_installed) - { - /* Restore original eroute, if we can. - * Since there is nothing much to be done if the restoration - * fails, ignore success or failure. - */ - if (ero != NULL) - { - /* restore ero's former glory */ - if (esr->eroute_owner == SOS_NOBODY) - { - /* note: normal or eclipse case */ - (void) shunt_eroute(ero, esr - , esr->routing, ERO_REPLACE, "restore"); - } - else - { - /* Try to find state that owned eroute. - * Don't do anything if it cannot be found. - * This case isn't likely since we don't run - * the updown script when replacing a SA group - * with its successor (for the same conn). - */ - struct state *ost = state_with_serialno(esr->eroute_owner); - - if (ost != NULL) - (void) sag_eroute(ost, esr, ERO_REPLACE, "restore"); - } - } - else - { - /* there was no previous eroute: delete whatever we installed */ - if (st == NULL) - { - (void) shunt_eroute(c, sr, sr->routing, ERO_DELETE, "delete"); - } - else - { - (void) sag_eroute(st, sr, ERO_DELETE, "delete"); - } - } - } - - return FALSE; - } -} - -bool install_ipsec_sa(struct state *st, bool inbound_also) -{ - struct spd_route *sr; - - DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() for #%ld: %s" - , st->st_serialno - , inbound_also? - "inbound and outbound" : "outbound only")); - - switch (could_route(st->st_connection)) - { - case route_easy: - case route_nearconflict: - break; - default: - return FALSE; - } - - /* (attempt to) actually set up the SA group */ - if ((inbound_also && !setup_half_ipsec_sa(st, TRUE)) || - !setup_half_ipsec_sa(st, FALSE)) - { - return FALSE; - } - - for (sr = &st->st_connection->spd; sr != NULL; sr = sr->next) - { - DBG(DBG_CONTROL, DBG_log("sr for #%ld: %s" - , st->st_serialno - , enum_name(&routing_story, sr->routing))); - - /* - * if the eroute owner is not us, then make it us. - * See test co-terminal-02, pluto-rekey-01, pluto-unit-02/oppo-twice - */ - pexpect(sr->eroute_owner == SOS_NOBODY - || sr->routing >= RT_ROUTED_TUNNEL); - - if (sr->eroute_owner != st->st_serialno - && sr->routing != RT_UNROUTED_KEYED) - { - if (!route_and_eroute(st->st_connection, sr, st)) - { - delete_ipsec_sa(st, FALSE); - /* XXX go and unroute any SRs that were successfully - * routed already. - */ - return FALSE; - } - } - } - - return TRUE; -} - -/* delete an IPSEC SA. - * we may not succeed, but we bull ahead anyway because - * we cannot do anything better by recognizing failure - */ -void delete_ipsec_sa(struct state *st, bool inbound_only) -{ - if (!inbound_only) - { - /* If the state is the eroute owner, we must adjust - * the routing for the connection. - */ - connection_t *c = st->st_connection; - struct spd_route *sr; - - passert(st->st_connection); - - for (sr = &c->spd; sr; sr = sr->next) - { - if (sr->eroute_owner == st->st_serialno - && sr->routing == RT_ROUTED_TUNNEL) - { - sr->eroute_owner = SOS_NOBODY; - - /* Routing should become RT_ROUTED_FAILURE, - * but if POLICY_FAIL_NONE, then we just go - * right back to RT_ROUTED_PROSPECTIVE as if no - * failure happened. - */ - sr->routing = (c->policy & POLICY_FAIL_MASK) == POLICY_FAIL_NONE - ? RT_ROUTED_PROSPECTIVE : RT_ROUTED_FAILURE; - - (void) do_command(c, sr, st, "down"); - if ((c->policy & POLICY_DONT_REKEY) && c->kind == CK_INSTANCE) - { - /* in this special case, even if the connection - * is still alive (due to an ISAKMP SA), - * we get rid of routing. - * Even though there is still an eroute, the c->routing - * setting will convince unroute_connection to delete it. - * unroute_connection would be upset if c->routing == RT_ROUTED_TUNNEL - */ - unroute_connection(c); - } - else - { - (void) shunt_eroute(c, sr, sr->routing, ERO_REPLACE, "replace with shunt"); - } - } - } - (void) teardown_half_ipsec_sa(st, FALSE); - } - (void) teardown_half_ipsec_sa(st, TRUE); -} - -static bool update_nat_t_ipsec_esp_sa (struct state *st, bool inbound) -{ - connection_t *c = st->st_connection; - host_t *host_src, *host_dst, *new_src, *new_dst; - ipsec_spi_t spi = inbound ? st->st_esp.our_spi : st->st_esp.attrs.spi; - struct end *src = inbound ? &c->spd.that : &c->spd.this, - *dst = inbound ? &c->spd.this : &c->spd.that; - mark_t mark = inbound ? c->spd.mark_in : c->spd.mark_out; - bool result; - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - new_src = host_src->clone(host_src); - new_dst = host_dst->clone(host_dst); - new_src->set_port(new_src, src->host_port); - new_dst->set_port(new_dst, dst->host_port); - - result = hydra->kernel_interface->update_sa(hydra->kernel_interface, - spi, IPPROTO_ESP, 0 /* cpi */, host_src, host_dst, - new_src, new_dst, TRUE /* encap */, TRUE /* new_encap */, - mark) == SUCCESS; - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - new_src->destroy(new_src); - new_dst->destroy(new_dst); - - return result; -} - -bool update_ipsec_sa (struct state *st) -{ - if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - if (st->st_esp.present && ( - (!update_nat_t_ipsec_esp_sa (st, TRUE)) || - (!update_nat_t_ipsec_esp_sa (st, FALSE)))) - { - return FALSE; - } - } - else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) - { - if (st->st_esp.present && !update_nat_t_ipsec_esp_sa (st, FALSE)) - { - return FALSE; - } - } - else - { - DBG_log("assert failed at %s:%d st_state=%d", __FILE__, __LINE__, st->st_state); - return FALSE; - } - return TRUE; -} - -/* Check if there was traffic on given SA during the last idle_max - * seconds. If TRUE, the SA was idle and DPD exchange should be performed. - * If FALSE, DPD is not necessary. We also return TRUE for errors, as they - * could mean that the SA is broken and needs to be replace anyway. - */ -bool was_eroute_idle(struct state *st, time_t idle_max, time_t *idle_time) -{ - time_t use_time; - u_int bytes; - int ret = TRUE; - - passert(st != NULL); - - if (get_sa_info(st, TRUE, &bytes, &use_time) && use_time != UNDEFINED_TIME) - { - *idle_time = time_monotonic(NULL) - use_time; - ret = *idle_time >= idle_max; - } - - return ret; -} diff --git a/src/pluto/kernel.h b/src/pluto/kernel.h deleted file mode 100644 index 1fa11c50e..000000000 --- a/src/pluto/kernel.h +++ /dev/null @@ -1,118 +0,0 @@ -/* declarations of routines that interface with the kernel's IPsec mechanism - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "connections.h" - -extern bool can_do_IPcomp; /* can system actually perform IPCOMP? */ - -/* Declare eroute things early enough for uses. - * - * Flags are encoded above the low-order byte of verbs. - * "real" eroutes are only outbound. Inbound eroutes don't exist, - * but an addflow with an INBOUND flag allows IPIP tunnels to be - * limited to appropriate source and destination addresses. - */ - -#define ERO_MASK 0xFF -#define ERO_FLAG_SHIFT 8 - -#define ERO_DELETE SADB_X_DELFLOW -#define ERO_ADD SADB_X_ADDFLOW -#define ERO_REPLACE (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT)) - -struct pfkey_proto_info { - int proto; - int encapsulation; - unsigned reqid; -}; -struct sadb_msg; - -struct kernel_sa { - const ip_address *src; - const ip_address *dst; - - const ip_subnet *src_client; - const ip_subnet *dst_client; - - ipsec_spi_t spi; - unsigned proto; - unsigned satype; - unsigned transport_proto; - unsigned replay_window; - unsigned reqid; - - unsigned authalg; - unsigned authkeylen; - char *authkey; - - unsigned encalg; - unsigned enckeylen; - char *enckey; - - unsigned compalg; - - int encapsulation; - - u_int16_t natt_sport, natt_dport; - u_int8_t transid, natt_type; - ip_address *natt_oa; - - const char *text_said; -}; - -/* A netlink header defines EM_MAXRELSPIS, the max number of SAs in a group. - * Is there a PF_KEY equivalent? - */ -#ifndef EM_MAXRELSPIS -# define EM_MAXRELSPIS 4 /* AH ESP IPCOMP IPIP */ -#endif - -extern void record_and_initiate_opportunistic(const ip_subnet * - , const ip_subnet * - , int transport_proto - , const char *why); - -extern void init_kernel(void); -extern void kernel_finalize(void); - -extern bool trap_connection(struct connection *c); -extern void unroute_connection(struct connection *c); - -extern bool assign_hold(struct connection *c - , struct spd_route *sr - , int transport_proto - , const ip_address *src, const ip_address *dst); - -extern ipsec_spi_t shunt_policy_spi(struct connection *c, bool prospective); - - -struct state; /* forward declaration of tag */ -extern ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid - , int proto - , struct spd_route *sr - , bool tunnel_mode); -extern ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel_mode); - -extern bool install_inbound_ipsec_sa(struct state *st); -extern bool install_ipsec_sa(struct state *st, bool inbound_also); -extern void delete_ipsec_sa(struct state *st, bool inbound_only); -extern bool route_and_eroute(struct connection *c - , struct spd_route *sr - , struct state *st); -extern bool was_eroute_idle(struct state *st, time_t idle_max - , time_t *idle_time); -extern bool get_sa_info(struct state *st, bool inbound, u_int *bytes - , time_t *use_time); - -extern bool update_ipsec_sa(struct state *st); diff --git a/src/pluto/kernel_alg.c b/src/pluto/kernel_alg.c deleted file mode 100644 index b4b18fd80..000000000 --- a/src/pluto/kernel_alg.c +++ /dev/null @@ -1,663 +0,0 @@ -/* Kernel runtime algorithm handling interface - * Copyright (C) JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <unistd.h> -#include <sys/queue.h> - -#include <pfkeyv2.h> -#include <pfkey.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "state.h" -#include "packet.h" -#include "spdb.h" -#include "kernel.h" -#include "kernel_alg.h" -#include "alg_info.h" -#include "log.h" -#include "whack.h" -#include "db_ops.h" - -/* ALG storage */ -static struct sadb_alg esp_aalg[SADB_AALG_MAX+1]; -static struct sadb_alg esp_ealg[SADB_EALG_MAX+1]; -static int esp_ealg_num = 0; -static int esp_aalg_num = 0; - -#define ESP_EALG_PRESENT(algo) (((algo)<=SADB_EALG_MAX)&&(esp_ealg[(algo)].sadb_alg_id==(algo))) -#define ESP_EALG_FOR_EACH_UPDOWN(algo) \ - for (algo=SADB_EALG_MAX; algo >0 ; algo--) \ - if (ESP_EALG_PRESENT(algo)) -#define ESP_AALG_PRESENT(algo) ((algo<=SADB_AALG_MAX)&&(esp_aalg[(algo)].sadb_alg_id==(algo))) -#define ESP_AALG_FOR_EACH_UPDOWN(algo) \ - for (algo=SADB_AALG_MAX; algo >0 ; algo--) \ - if (ESP_AALG_PRESENT(algo)) - -static struct sadb_alg* sadb_alg_ptr (int satype, int exttype, int alg_id, - int rw) -{ - struct sadb_alg *alg_p = NULL; - - switch (exttype) - { - case SADB_EXT_SUPPORTED_AUTH: - if (alg_id > SADB_AALG_MAX) - return NULL; - break; - case SADB_EXT_SUPPORTED_ENCRYPT: - if (alg_id > SADB_EALG_MAX) - return NULL; - break; - default: - return NULL; - } - - switch (satype) - { - case SADB_SATYPE_ESP: - alg_p = (exttype == SADB_EXT_SUPPORTED_ENCRYPT)? - &esp_ealg[alg_id] : &esp_aalg[alg_id]; - /* get for write: increment elem count */ - if (rw) - { - (exttype == SADB_EXT_SUPPORTED_ENCRYPT)? - esp_ealg_num++ : esp_aalg_num++; - } - break; - case SADB_SATYPE_AH: - default: - return NULL; - } - - return alg_p; -} - -const struct sadb_alg* kernel_alg_sadb_alg_get(int satype, int exttype, - int alg_id) -{ - return sadb_alg_ptr(satype, exttype, alg_id, 0); -} - -/* - * Forget previous registration - */ -static void kernel_alg_init(void) -{ - DBG(DBG_KERNEL, - DBG_log("alg_init(): memset(%p, 0, %d) memset(%p, 0, %d)", - &esp_aalg, (int)sizeof (esp_aalg), - &esp_ealg, (int)sizeof (esp_ealg)) - ) - memset (&esp_aalg, 0, sizeof (esp_aalg)); - memset (&esp_ealg, 0, sizeof (esp_ealg)); - esp_ealg_num=esp_aalg_num = 0; -} - -static int kernel_alg_add(int satype, int exttype, - const struct sadb_alg *sadb_alg) -{ - struct sadb_alg *alg_p = NULL; - int alg_id = sadb_alg->sadb_alg_id; - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_add(): satype=%d, exttype=%d, alg_id=%d", - satype, exttype, sadb_alg->sadb_alg_id) - ) - if (!(alg_p = sadb_alg_ptr(satype, exttype, alg_id, 1))) - return -1; - - /* This logic "mimics" KLIPS: first algo implementation will be used */ - if (alg_p->sadb_alg_id) - { - DBG(DBG_KERNEL, - DBG_log("kernel_alg_add(): discarding already setup " - "satype=%d, exttype=%d, alg_id=%d", - satype, exttype, sadb_alg->sadb_alg_id) - ) - return 0; - } - *alg_p = *sadb_alg; - return 1; -} - -bool kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len, - struct alg_info_esp *alg_info __attribute__((unused))) -{ - struct sadb_alg *alg_p = NULL; - - /* - * test #1: encrypt algo must be present - */ - int ret = ESP_EALG_PRESENT(alg_id); - if (!ret) goto out; - - alg_p = &esp_ealg[alg_id]; - - /* - * test #2: if key_len specified, it must be in range - */ - if (key_len - && (key_len < alg_p->sadb_alg_minbits || key_len > alg_p->sadb_alg_maxbits)) - { - plog("kernel_alg_db_add() key_len not in range: alg_id=%d, " - "key_len=%d, alg_minbits=%d, alg_maxbits=%d" - , alg_id, key_len - , alg_p->sadb_alg_minbits - , alg_p->sadb_alg_maxbits); - ret = FALSE; - } - -out: - if (ret) - { - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_enc_ok(%d,%d): " - "alg_id=%d, " - "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " - "res=%d, ret=%d" - , alg_id, key_len - , alg_p->sadb_alg_id - , alg_p->sadb_alg_ivlen - , alg_p->sadb_alg_minbits - , alg_p->sadb_alg_maxbits - , alg_p->sadb_alg_reserved - , ret); - ) - } - else - { - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_enc_ok(%d,%d): NO", alg_id, key_len); - ) - } - return ret; -} - -/* - * ML: make F_STRICT logic consider enc,auth algorithms - */ -bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, - struct alg_info_esp *alg_info) -{ - int ealg_insecure; - - /* - * key_len passed comes from esp_attrs read from peer - * For many older algorithms (eg 3DES) this key_len is fixed - * and get passed as 0. - * ... then get default key_len - */ - if (key_len == 0) - key_len = kernel_alg_esp_enc_keylen(ealg) * BITS_PER_BYTE; - - /* - * simple test to toss low key_len, will accept it only - * if specified in "esp" string - */ - ealg_insecure = (key_len < 128) ; - - if (ealg_insecure - || (alg_info && alg_info->alg_info_flags & ALG_INFO_F_STRICT)) - { - int i; - struct esp_info *esp_info; - - if (alg_info) - { - ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) - { - if (esp_info->esp_ealg_id == ealg - && (esp_info->esp_ealg_keylen == 0 || key_len == 0 - || esp_info->esp_ealg_keylen == key_len) - && esp_info->esp_aalg_id == aalg) - { - if (ealg_insecure) - { - loglog(RC_LOG_SERIOUS - , "You should NOT use insecure ESP algorithms [%s (%d)]!" - , enum_name(&esp_transform_names, ealg), key_len); - } - return TRUE; - } - } - } - plog("IPSec Transform [%s (%d), %s] refused due to %s", - enum_name(&esp_transform_names, ealg), key_len, - enum_name(&auth_alg_names, aalg), - ealg_insecure ? "insecure key_len and enc. alg. not listed in \"esp\" string" : "strict flag"); - return FALSE; - } - return TRUE; -} - -/** - * Load kernel_alg arrays pluto's SADB_REGISTER user by pluto/kernel.c - */ -void kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen) -{ - /* Trick: one 'type-mangle-able' pointer to ease offset/assign */ - union { - const struct sadb_msg *msg; - const struct sadb_supported *supported; - const struct sadb_ext *ext; - const struct sadb_alg *alg; - const char *ch; - } sadb; - - int satype; - int msglen; - int i = 0; - - /* Initialize alg arrays */ - kernel_alg_init(); - satype = msg_buf->sadb_msg_satype; - sadb.msg = msg_buf; - msglen = sadb.msg->sadb_msg_len*IPSEC_PFKEYv2_ALIGN; - msglen -= sizeof(struct sadb_msg); - buflen -= sizeof(struct sadb_msg); - passert(buflen > 0); - - sadb.msg++; - - while (msglen) - { - int supp_exttype = sadb.supported->sadb_supported_exttype; - int supp_len = sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN; - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: " - "sadb_msg_len=%d sadb_supported_len=%d" - , satype==SADB_SATYPE_ESP? "ESP" : "AH" - , msg_buf->sadb_msg_len, supp_len) - ) - sadb.supported++; - msglen -= supp_len; - buflen -= supp_len; - passert(buflen >= 0); - - for (supp_len -= sizeof(struct sadb_supported); - supp_len; - supp_len -= sizeof(struct sadb_alg), sadb.alg++,i++) - { - kernel_alg_add(satype, supp_exttype, sadb.alg); - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: " - "alg[%d], exttype=%d, satype=%d, alg_id=%d, " - "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " - "res=%d" - , satype == SADB_SATYPE_ESP? "ESP" : "AH" - , i - , supp_exttype - , satype - , sadb.alg->sadb_alg_id - , sadb.alg->sadb_alg_ivlen - , sadb.alg->sadb_alg_minbits - , sadb.alg->sadb_alg_maxbits - , sadb.alg->sadb_alg_reserved) - ) - /* if AES_CBC is registered then also register AES_CCM and AES_GCM */ - if (satype == SADB_SATYPE_ESP && - supp_exttype == SADB_EXT_SUPPORTED_ENCRYPT && - sadb.alg->sadb_alg_id == SADB_X_EALG_AESCBC) - { - struct sadb_alg alg = *sadb.alg; - int alg_id; - - for (alg_id = SADB_X_EALG_AES_CCM_ICV8; - alg_id <= SADB_X_EALG_AES_GCM_ICV16; alg_id++) - { - if (alg_id != ESP_UNASSIGNED_17) - { - alg.sadb_alg_id = alg_id; - kernel_alg_add(satype, supp_exttype, &alg); - } - } - - /* also register AES_GMAC */ - alg.sadb_alg_id = SADB_X_EALG_NULL_AES_GMAC; - kernel_alg_add(satype, supp_exttype, &alg); - } - /* if SHA2_256 is registered then also register SHA2_256_96 */ - if (satype == SADB_SATYPE_ESP && - supp_exttype == SADB_EXT_SUPPORTED_AUTH && - sadb.alg->sadb_alg_id == SADB_X_AALG_SHA2_256HMAC) - { - struct sadb_alg alg = *sadb.alg; - - alg.sadb_alg_id = SADB_X_AALG_SHA2_256_96HMAC; - kernel_alg_add(satype, supp_exttype, &alg); - } - } - } -} - -u_int kernel_alg_esp_enc_keylen(u_int alg_id) -{ - u_int keylen = 0; - - if (!ESP_EALG_PRESENT(alg_id)) - { - goto none; - } - keylen = esp_ealg[alg_id].sadb_alg_maxbits/BITS_PER_BYTE; - - switch (alg_id) - { - /* - * this is veryUgly[TM] - * Peer should have sent KEY_LENGTH attribute for ESP_AES - * but if not do force it to 128 instead of using sadb_alg_maxbits - * from kernel. - */ - case ESP_AES: - keylen = 128/BITS_PER_BYTE; - break; - } - -none: - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_enc_keylen(): alg_id=%d, keylen=%d", - alg_id, keylen) - ) - return keylen; -} - -struct sadb_alg* kernel_alg_esp_sadb_alg(u_int alg_id) -{ - struct sadb_alg *sadb_alg = (ESP_EALG_PRESENT(alg_id)) - ? &esp_ealg[alg_id] : NULL; - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_sadb_alg(): alg_id=%d, sadb_alg=%p" - , alg_id, sadb_alg) - ) - return sadb_alg; -} - -/** - * Print the name of a kernel algorithm - */ -static void print_alg(char *buf, int *len, enum_names *alg_names, int alg_type) -{ - char alg_name[BUF_LEN]; - int alg_name_len; - - alg_name_len = sprintf(alg_name, " %s", enum_name(alg_names, alg_type)); - if (*len + alg_name_len > CRYPTO_MAX_ALG_LINE) - { - whack_log(RC_COMMENT, "%s", buf); - *len = sprintf(buf, " "); - } - sprintf(buf + *len, "%s", alg_name); - *len += alg_name_len; -} - -void kernel_alg_list(void) -{ - char buf[BUF_LEN]; - int len; - u_int sadb_id; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of registered ESP Algorithms:"); - whack_log(RC_COMMENT, " "); - - len = sprintf(buf, " encryption:"); - for (sadb_id = 1; sadb_id <= SADB_EALG_MAX; sadb_id++) - { - if (ESP_EALG_PRESENT(sadb_id)) - { - print_alg(buf, &len, &esp_transform_names, sadb_id); - } - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " integrity: "); - for (sadb_id = 1; sadb_id <= SADB_AALG_MAX; sadb_id++) - { - if (ESP_AALG_PRESENT(sadb_id)) - { - u_int aaid = alg_info_esp_sadb2aa(sadb_id); - - print_alg(buf, &len, &auth_alg_names, aaid); - } - } - whack_log(RC_COMMENT, "%s", buf); -} - -void kernel_alg_show_connection(connection_t *c, const char *instance) -{ - struct state *st = state_with_serialno(c->newest_ipsec_sa); - - if (st && st->st_esp.present) - { - const char *aalg_name, *pfsgroup_name; - - aalg_name = (c->policy & POLICY_AUTHENTICATE) ? - enum_show(&ah_transform_names, st->st_ah.attrs.transid): - enum_show(&auth_alg_names, st->st_esp.attrs.auth); - - pfsgroup_name = (c->policy & POLICY_PFS) ? - (c->alg_info_esp && c->alg_info_esp->esp_pfsgroup) ? - enum_show(&oakley_group_names, - c->alg_info_esp->esp_pfsgroup) : - "<Phase1>" : "<N/A>"; - - if (st->st_esp.attrs.key_len) - { - whack_log(RC_COMMENT, "\"%s\"%s: ESP%s proposal: %s_%u/%s/%s", - c->name, instance, - (st->st_ah.present) ? "/AH" : "", - enum_show(&esp_transform_names, st->st_esp.attrs.transid), - st->st_esp.attrs.key_len, aalg_name, pfsgroup_name); - } - else - { - whack_log(RC_COMMENT, "\"%s\"%s: ESP%s proposal: %s/%s/%s", - c->name, instance, - (st->st_ah.present) ? "/AH" : "", - enum_show(&esp_transform_names, st->st_esp.attrs.transid), - aalg_name, pfsgroup_name); - } - } -} - -bool kernel_alg_esp_auth_ok(u_int auth, - struct alg_info_esp *alg_info __attribute__((unused))) -{ - return ESP_AALG_PRESENT(alg_info_esp_aa2sadb(auth)); -} - -u_int kernel_alg_esp_auth_keylen(u_int auth) -{ - u_int sadb_aalg = alg_info_esp_aa2sadb(auth); - - u_int a_keylen = (sadb_aalg) - ? esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE - : 0; - - DBG(DBG_CONTROL | DBG_CRYPT | DBG_PARSING, - DBG_log("kernel_alg_esp_auth_keylen(auth=%d, sadb_aalg=%d): " - "a_keylen=%d", auth, sadb_aalg, a_keylen) - ) - return a_keylen; -} - -struct esp_info* kernel_alg_esp_info(int transid, int auth) -{ - int sadb_aalg, sadb_ealg; - static struct esp_info ei_buf; - - sadb_ealg = transid; - sadb_aalg = alg_info_esp_aa2sadb(auth); - - if (!ESP_EALG_PRESENT(sadb_ealg)) - goto none; - if (!ESP_AALG_PRESENT(sadb_aalg)) - goto none; - - memset(&ei_buf, 0, sizeof (ei_buf)); - ei_buf.transid = transid; - ei_buf.auth = auth; - - /* don't return "default" keylen because this value is used from - * setup_half_ipsec_sa() to "validate" keylen - * In effect, enckeylen will be used as "max" value - */ - ei_buf.enckeylen = esp_ealg[sadb_ealg].sadb_alg_maxbits/BITS_PER_BYTE; - ei_buf.authkeylen = esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE; - ei_buf.encryptalg = sadb_ealg; - ei_buf.authalg = sadb_aalg; - - DBG(DBG_PARSING, - DBG_log("kernel_alg_esp_info():" - "transid=%d, auth=%d, ei=%p, " - "enckeylen=%d, authkeylen=%d, encryptalg=%d, authalg=%d", - transid, auth, &ei_buf, - (int)ei_buf.enckeylen, (int)ei_buf.authkeylen, - ei_buf.encryptalg, ei_buf.authalg) - ) - return &ei_buf; - -none: - DBG(DBG_PARSING, - DBG_log("kernel_alg_esp_info():" - "transid=%d, auth=%d, ei=NULL", - transid, auth) - ) - return NULL; -} - -static void kernel_alg_policy_algorithms(struct esp_info *esp_info) -{ - u_int ealg_id = esp_info->esp_ealg_id; - - switch(ealg_id) - { - case 0: - case ESP_DES: - case ESP_3DES: - case ESP_NULL: - case ESP_CAST: - break; - default: - if (!esp_info->esp_ealg_keylen) - { - /* algos that need KEY_LENGTH - * - * Note: this is a very dirty hack ;-) - * Idea: Add a key_length_needed attribute to - * esp_ealg ?? - */ - esp_info->esp_ealg_keylen = esp_ealg[ealg_id].sadb_alg_maxbits; - } - } -} - -static bool kernel_alg_db_add(struct db_context *db_ctx, - struct esp_info *esp_info, lset_t policy) -{ - u_int ealg_id, aalg_id; - - ealg_id = esp_info->esp_ealg_id; - - if (!ESP_EALG_PRESENT(ealg_id)) - { - DBG_log("kernel_alg_db_add() kernel enc ealg_id=%d not present", ealg_id); - return FALSE; - } - - if (!(policy & POLICY_AUTHENTICATE) && /* skip ESP auth attrs for AH */ - esp_info->esp_aalg_id != AUTH_ALGORITHM_NONE) - { - aalg_id = alg_info_esp_aa2sadb(esp_info->esp_aalg_id); - - if (!ESP_AALG_PRESENT(aalg_id)) - { - DBG_log("kernel_alg_db_add() kernel auth aalg_id=%d not present", - aalg_id); - return FALSE; - } - } - - /* do algo policy */ - kernel_alg_policy_algorithms(esp_info); - - /* open new transformation */ - db_trans_add(db_ctx, ealg_id); - - /* add ESP auth attr if not AH or AEAD */ - if (!(policy & POLICY_AUTHENTICATE) && - esp_info->esp_aalg_id != AUTH_ALGORITHM_NONE) - { - db_attr_add_values(db_ctx, AUTH_ALGORITHM, esp_info->esp_aalg_id); - } - - /* add keylength if specified in esp= string */ - if (esp_info->esp_ealg_keylen) - { - db_attr_add_values(db_ctx, KEY_LENGTH, esp_info->esp_ealg_keylen); - } - - return TRUE; -} - -/* - * Create proposal with runtime kernel algos, merging - * with passed proposal if not NULL - * - * for now this function does free() previous returned - * malloced pointer (this quirk allows easier spdb.c change) - */ -struct db_context* kernel_alg_db_new(struct alg_info_esp *alg_info, - lset_t policy) -{ - const struct esp_info *esp_info; - struct esp_info tmp_esp_info; - struct db_context *ctx_new = NULL; - u_int trans_cnt = esp_ealg_num * esp_aalg_num; - - if (!(policy & POLICY_ENCRYPT)) /* not possible, I think */ - { - return NULL; - } - - /* pass aprox. number of transforms and attributes */ - ctx_new = db_prop_new(PROTO_IPSEC_ESP, trans_cnt, trans_cnt * 2); - - if (alg_info) - { - int i; - - ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) - { - tmp_esp_info = *esp_info; - kernel_alg_db_add(ctx_new, &tmp_esp_info, policy); - } - } - return ctx_new; -} - diff --git a/src/pluto/kernel_alg.h b/src/pluto/kernel_alg.h deleted file mode 100644 index 4c757db41..000000000 --- a/src/pluto/kernel_alg.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Kernel runtime algorithm handling interface definitions - * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _KERNEL_ALG_H -#define _KERNEL_ALG_H - -#include "alg_info.h" -#include "spdb.h" - -/* status info */ -extern void kernel_alg_show_status(void); -void kernel_alg_show_connection(struct connection *c, const char *instance); - -/* Registration messages from pluto */ -extern void kernel_alg_register_pfkey(const struct sadb_msg *msg, int buflen); - -/* ESP interface */ -extern struct sadb_alg *kernel_alg_esp_sadb_alg(u_int alg_id); -extern u_int kernel_alg_esp_ivlen(u_int alg_id); -extern bool kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len, struct alg_info_esp *nfo); -extern bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struct alg_info_esp *alg_info); -extern u_int kernel_alg_esp_enc_keylen(u_int alg_id); -extern bool kernel_alg_esp_auth_ok(u_int auth, struct alg_info_esp *nfo); -extern u_int kernel_alg_esp_auth_keylen(u_int auth); -extern void kernel_alg_list(void); - -/* get sadb_alg for passed args */ -extern const struct sadb_alg * kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id); - -extern struct db_context * kernel_alg_db_new(struct alg_info_esp *ai, lset_t policy); -struct esp_info * kernel_alg_esp_info(int esp_id, int auth_id); -#endif /* _KERNEL_ALG_H */ diff --git a/src/pluto/kernel_pfkey.c b/src/pluto/kernel_pfkey.c deleted file mode 100644 index 77fff2f9e..000000000 --- a/src/pluto/kernel_pfkey.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2003 Herbert Xu. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 1997 Angelos D. Keromytis. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <errno.h> -#include <unistd.h> - -#include <sys/select.h> -#include <sys/socket.h> -#include <sys/types.h> - -#include <freeswan.h> -#include <pfkeyv2.h> -#include <pfkey.h> - -#include "constants.h" -#include "kernel.h" -#include "kernel_pfkey.h" -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "kernel_alg.h" - - -static int pfkeyfd = NULL_FD; - -typedef u_int32_t pfkey_seq_t; -static pfkey_seq_t pfkey_seq = 0; /* sequence number for our PF_KEY messages */ - -static pid_t pid; - -#define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */ - -static sparse_names pfkey_type_names = { - NE(SADB_RESERVED), - NE(SADB_GETSPI), - NE(SADB_UPDATE), - NE(SADB_ADD), - NE(SADB_DELETE), - NE(SADB_GET), - NE(SADB_ACQUIRE), - NE(SADB_REGISTER), - NE(SADB_EXPIRE), - NE(SADB_FLUSH), - NE(SADB_DUMP), - NE(SADB_X_PROMISC), - NE(SADB_X_PCHANGE), - NE(SADB_X_GRPSA), - NE(SADB_X_ADDFLOW), - NE(SADB_X_DELFLOW), - NE(SADB_X_DEBUG), - NE(SADB_X_NAT_T_NEW_MAPPING), - NE(SADB_MAX), - { 0, sparse_end } -}; - -#undef NE - -typedef union { - unsigned char bytes[PFKEYv2_MAX_MSGSIZE]; - struct sadb_msg msg; - } pfkey_buf; - -static bool -pfkey_input_ready(void) -{ - int ndes; - fd_set readfds; - struct timeval tm = { .tv_sec = 0 }; /* don't wait, polling */ - - FD_ZERO(&readfds); /* we only care about pfkeyfd */ - FD_SET(pfkeyfd, &readfds); - - do { - ndes = select(pfkeyfd + 1, &readfds, NULL, NULL, &tm); - } while (ndes == -1 && errno == EINTR); - - if (ndes < 0) - { - log_errno((e, "select() failed in pfkey_get()")); - return FALSE; - } - else if (ndes == 0) - { - return FALSE; /* nothing to read */ - } - passert(ndes == 1 && FD_ISSET(pfkeyfd, &readfds)); - return TRUE; -} - -/* get a PF_KEY message from kernel. - * Returns TRUE if message found, FALSE if no message pending, - * and aborts or keeps trying when an error is encountered. - * The only validation of the message is that the message length - * received matches that in the message header, and that the message - * is for this process. - */ -static bool -pfkey_get(pfkey_buf *buf) -{ - for (;;) - { - /* len must be less than PFKEYv2_MAX_MSGSIZE, - * so it should fit in an int. We use this fact when printing it. - */ - ssize_t len; - - if (!pfkey_input_ready()) - { - return FALSE; - } - - len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes)); - - if (len < 0) - { - if (errno == EAGAIN) - { - return FALSE; - } - log_errno((e, "read() failed in pfkey_get()")); - return FALSE; - } - else if ((size_t)len < sizeof(buf->msg)) - { - plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring", - (int)len); - } - else if ((size_t)len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN) - { - plog("pfkey_get read PF_KEY message with length %d that doesn't" - " equal sadb_msg_len %u * %u; ignoring message", (int)len, - (unsigned)buf->msg.sadb_msg_len, (unsigned)IPSEC_PFKEYv2_ALIGN); - } - else if (buf->msg.sadb_msg_pid != (unsigned)pid) - { - /* not for us: ignore */ - DBG(DBG_KERNEL, - DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process" - " %u", sparse_val_show(pfkey_type_names, - buf->msg.sadb_msg_type), - buf->msg.sadb_msg_seq, buf->msg.sadb_msg_pid)); - } - else - { - DBG(DBG_KERNEL, - DBG_log("pfkey_get: %s message %u", - sparse_val_show(pfkey_type_names, - buf->msg.sadb_msg_type), - buf->msg.sadb_msg_seq)); - return TRUE; - } - } -} - -/* get a response to a specific message */ -static bool -pfkey_get_response(pfkey_buf *buf, pfkey_seq_t seq) -{ - while (pfkey_get(buf)) - { - if (buf->msg.sadb_msg_seq == seq) - { - return TRUE; - } - } - return FALSE; -} - -static bool -pfkey_build(int error, const char *description, const char *text_said, - struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - if (error != 0) - { - loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d", description, - text_said, error); - pfkey_extensions_free(extensions); - return FALSE; - } - return TRUE; -} - -/* pfkey_extensions_init + pfkey_build + pfkey_msg_hdr_build */ -static bool -pfkey_msg_start(u_int8_t msg_type, u_int8_t satype, const char *description, - const char *text_said, - struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - pfkey_extensions_init(extensions); - return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type, satype, 0, - ++pfkey_seq, pid), - description, text_said, extensions); -} - -/* Finish (building, sending, accepting response for) PF_KEY message. - * If response isn't NULL, the response from the kernel will be - * placed there (and its errno field will not be examined). - * Returns TRUE iff all appears well. - */ -static bool -finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1], - const char *description, const char *text_said, - pfkey_buf *response) -{ - struct sadb_msg *pfkey_msg; - bool success = TRUE; - int error; - - error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN); - - if (error != 0) - { - loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d", - description, text_said, error); - success = FALSE; - } - else - { - size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN; - - DBG(DBG_KERNEL, - DBG_log("finish_pfkey_msg: %s message %u for %s %s", - sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type), - pfkey_msg->sadb_msg_seq, description, text_said); - DBG_dump(NULL, (void *) pfkey_msg, len)); - - ssize_t r = write(pfkeyfd, pfkey_msg, len); - - if (r != (ssize_t)len) - { - if (r < 0) - { - log_errno((e, "pfkey write() of %s message %u for %s %s" - " failed", sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), pfkey_msg->sadb_msg_seq, - description, text_said)); - } - else - { - loglog(RC_LOG_SERIOUS, "ERROR: pfkey write() of %s message" - " %u for %s %s truncated: %ld instead of %ld", - sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), pfkey_msg->sadb_msg_seq, - description, text_said, (long)r, (long)len); - } - success = FALSE; - - /* if we were compiled with debugging, but we haven't already - * dumped the command, do so. - */ -#ifdef DEBUG - if ((cur_debugging & DBG_KERNEL) == 0) - DBG_dump(NULL, (void *) pfkey_msg, len); -#endif - } - else - { - /* Check response from kernel. - * It ought to be an echo, perhaps with additional info. - * If the caller wants it, response will point to space. - */ - pfkey_buf b; - pfkey_buf *bp = response != NULL? response : &b; - - if (!pfkey_get_response(bp, - ((struct sadb_msg *)extensions[0])->sadb_msg_seq)) - { - loglog(RC_LOG_SERIOUS, "ERROR: no response to our PF_KEY %s" - " message for %s %s", sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), description, text_said); - success = FALSE; - } - else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type) - { - loglog(RC_LOG_SERIOUS, "ERROR: response to our PF_KEY %s" - " message for %s %s was of wrong type (%s)", - sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type), - description, text_said, sparse_val_show(pfkey_type_names, - bp->msg.sadb_msg_type)); - success = FALSE; - } - else if (response == NULL && bp->msg.sadb_msg_errno != 0) - { - /* Kernel is signalling a problem */ - loglog(RC_LOG_SERIOUS, "ERROR: PF_KEY %s response for %s %s" - " included errno %u: %s", - sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), description, text_said, - (unsigned) bp->msg.sadb_msg_errno, - strerror(bp->msg.sadb_msg_errno)); - success = FALSE; - } - } - } - pfkey_extensions_free(extensions); - pfkey_msg_free(&pfkey_msg); - return success; -} - -/* Process a SADB_REGISTER message from the kernel. - * This will be a response to one of ours, but it may be asynchronous - * (if kernel modules are loaded and unloaded). - * Some sanity checking has already been performed. - */ -static void -pfkey_register_response(const struct sadb_msg *msg) -{ - /* Find out what the kernel can support. - */ - switch (msg->sadb_msg_satype) - { - case SADB_SATYPE_ESP: -#ifndef NO_KERNEL_ALG - kernel_alg_register_pfkey(msg, sizeof (pfkey_buf)); -#endif - break; - case SADB_X_SATYPE_IPCOMP: - /* ??? There ought to be an extension to list the - * supported algorithms, but RFC 2367 doesn't - * list one for IPcomp. - */ - can_do_IPcomp = TRUE; - break; - default: - break; - } -} - -/** register SA types that can be negotiated */ -static void -pfkey_register_proto(unsigned satype, const char *satypename) -{ - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - pfkey_buf pfb; - - if (!(pfkey_msg_start(SADB_REGISTER, satype, satypename, NULL, extensions) - && finish_pfkey_msg(extensions, satypename, "", &pfb))) - { - /* ??? should this be loglog */ - plog("no kernel support for %s", satypename); - } - else - { - pfkey_register_response(&pfb.msg); - DBG(DBG_KERNEL, - DBG_log("%s registered with kernel.", satypename)); - } -} - -void -pfkey_register(void) -{ - pid = getpid(); - - pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); - if (pfkeyfd == -1) - { - exit_log_errno((e, "socket() in init_pfkeyfd()")); - } - - pfkey_register_proto(SADB_SATYPE_AH, "AH"); - pfkey_register_proto(SADB_SATYPE_ESP, "ESP"); - pfkey_register_proto(SADB_X_SATYPE_IPCOMP, "IPCOMP"); - - close(pfkeyfd); -} diff --git a/src/pluto/kernel_pfkey.h b/src/pluto/kernel_pfkey.h deleted file mode 100644 index b50ad6c37..000000000 --- a/src/pluto/kernel_pfkey.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * Register our capabilities via PF_KEY, also learn the kernel's capabilities, - * i.e. the supported algorithms. - */ -void pfkey_register(); diff --git a/src/pluto/keys.c b/src/pluto/keys.c deleted file mode 100644 index c5adbfd11..000000000 --- a/src/pluto/keys.c +++ /dev/null @@ -1,1474 +0,0 @@ -/* mechanisms for preshared keys (public, private, and preshared secrets) - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stddef.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <unistd.h> -#include <errno.h> -#include <time.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ -#include <sys/queue.h> - -#ifdef HAVE_GLOB_H -#include <glob.h> -#ifndef GLOB_ABORTED -# define GLOB_ABORTED GLOB_ABEND /* fix for old versions */ -#endif -#endif - -#include <freeswan.h> - -#include <library.h> -#include <asn1/asn1.h> -#include <credentials/certificates/pgp_certificate.h> -#include <credentials/sets/mem_cred.h> -#include <credentials/sets/callback_cred.h> - -#include "constants.h" -#include "defs.h" -#include "x509.h" -#include "certs.h" -#include "smartcard.h" -#include "connections.h" -#include "state.h" -#include "lex.h" -#include "keys.h" -#include "adns.h" /* needs <resolv.h> */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "timer.h" -#include "fetch.h" - -const char *shared_secrets_file = SHARED_SECRETS_FILE; - - -typedef enum secret_kind_t secret_kind_t; - -enum secret_kind_t { - SECRET_PSK, - SECRET_PUBKEY, - SECRET_XAUTH, - SECRET_PIN -}; - -typedef struct secret_t secret_t; - -struct secret_t { - linked_list_t *ids; - secret_kind_t kind; - union { - chunk_t preshared_secret; - private_key_t *private_key; - smartcard_t *smartcard; - } u; - secret_t *next; -}; - -/* - * free a public key struct - */ -static void free_public_key(pubkey_t *pk) -{ - DESTROY_IF(pk->id); - DESTROY_IF(pk->public_key); - DESTROY_IF(pk->issuer); - free(pk->serial.ptr); - free(pk); -} - -secret_t *secrets = NULL; - -/** - * Find the secret associated with the combination of me and the peer. - */ -const secret_t* match_secret(identification_t *my_id, identification_t *his_id, - secret_kind_t kind) -{ - enum { /* bits */ - match_default = 0x01, - match_him = 0x02, - match_me = 0x04 - }; - - unsigned int best_match = 0; - secret_t *s, *best = NULL; - - for (s = secrets; s != NULL; s = s->next) - { - unsigned int match = 0; - - if (s->kind != kind) - { - continue; - } - - if (s->ids->get_count(s->ids) == 0) - { - /* a default (signified by lack of ids): - * accept if no more specific match found - */ - match = match_default; - } - else - { - /* check if both ends match ids */ - enumerator_t *enumerator; - identification_t *id; - - enumerator = s->ids->create_enumerator(s->ids); - while (enumerator->enumerate(enumerator, &id)) - { - if (my_id->equals(my_id, id)) - { - match |= match_me; - } - if (his_id->equals(his_id, id)) - { - match |= match_him; - } - } - enumerator->destroy(enumerator); - - /* If our end matched the only id in the list, - * default to matching any peer. - * A more specific match will trump this. - */ - if (match == match_me && s->ids->get_count(s->ids) == 1) - { - match |= match_default; - } - } - - switch (match) - { - case match_me: - /* if this is an asymmetric (eg. public key) system, - * allow this-side-only match to count, even if - * there are other ids in the list. - */ - if (kind != SECRET_PUBKEY) - { - break; - } - /* FALLTHROUGH */ - case match_default: /* default all */ - case match_me | match_default: /* default peer */ - case match_me | match_him: /* explicit */ - if (match == best_match) - { - /* two good matches are equally good: do they agree? */ - bool same = FALSE; - - switch (kind) - { - case SECRET_PSK: - case SECRET_XAUTH: - same = chunk_equals(s->u.preshared_secret, - best->u.preshared_secret); - break; - case SECRET_PUBKEY: - same = s->u.private_key->equals(s->u.private_key, - best->u.private_key); - break; - default: - bad_case(kind); - } - if (!same) - { - loglog(RC_LOG_SERIOUS, "multiple ipsec.secrets entries with " - "distinct secrets match endpoints: first secret used"); - best = s; /* list is backwards: take latest in list */ - } - } - else if (match > best_match) - { - /* this is the best match so far */ - best_match = match; - best = s; - } - } - } - return best; -} - -/** - * Retrieves an XAUTH secret primarily based on the user ID and - * secondarily based on the server ID - */ -bool get_xauth_secret(identification_t *user, identification_t *server, - chunk_t *secret) -{ - const secret_t *s; - - s = match_secret(user, server, SECRET_XAUTH); - if (s) - { - *secret = chunk_clone(s->u.preshared_secret); - return TRUE; - } - else - { - *secret = chunk_empty; - return FALSE; - } -} - -/** - * We match the ID (if none, the IP address). Failure is indicated by a NULL. - */ -static const secret_t* get_secret(const connection_t *c, secret_kind_t kind) -{ - identification_t *my_id, *his_id; - const secret_t *best; - - my_id = c->spd.this.id; - - if (his_id_was_instantiated(c)) - { - /* roadwarrior: replace him with 0.0.0.0 */ - his_id = identification_create_from_string("%any"); - } - else if (kind == SECRET_PSK && (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK)) && - ((c->kind == CK_TEMPLATE && - c->spd.that.id->get_type(c->spd.that.id) == ID_ANY) || - (c->kind == CK_INSTANCE && id_is_ipaddr(c->spd.that.id)))) - { - /* roadwarrior: replace him with 0.0.0.0 */ - his_id = identification_create_from_string("%any"); - } - else - { - his_id = c->spd.that.id->clone(c->spd.that.id); - } - - best = match_secret(my_id, his_id, kind); - - his_id->destroy(his_id); - return best; -} - -/* find the appropriate preshared key (see get_secret). - * Failure is indicated by a NULL pointer. - * Note: the result is not to be freed by the caller. - */ -const chunk_t* get_preshared_secret(const connection_t *c) -{ - const secret_t *s = get_secret(c, SECRET_PSK); - - DBG(DBG_PRIVATE, - if (s == NULL) - DBG_log("no Preshared Key Found"); - else - DBG_dump_chunk("Preshared Key", s->u.preshared_secret); - ) - return s == NULL? NULL : &s->u.preshared_secret; -} - -/* check the existence of a private key matching a public key contained - * in an X.509 or OpenPGP certificate - */ -bool has_private_key(cert_t *cert) -{ - secret_t *s; - bool has_key = FALSE; - public_key_t *pub_key = cert->cert->get_public_key(cert->cert); - - for (s = secrets; s != NULL; s = s->next) - { - if (s->kind == SECRET_PUBKEY && - s->u.private_key->belongs_to(s->u.private_key, pub_key)) - { - has_key = TRUE; - break; - } - } - pub_key->destroy(pub_key); - return has_key; -} - -/* - * get the matching private key belonging to a given X.509 certificate - */ -private_key_t* get_x509_private_key(const cert_t *cert) -{ - public_key_t *public_key = cert->cert->get_public_key(cert->cert); - private_key_t *private_key = NULL; - secret_t *s; - - for (s = secrets; s != NULL; s = s->next) - { - - if (s->kind == SECRET_PUBKEY && - s->u.private_key->belongs_to(s->u.private_key, public_key)) - { - private_key = s->u.private_key; - break; - } - } - public_key->destroy(public_key); - return private_key; -} - -/* find the appropriate private key (see get_secret). - * Failure is indicated by a NULL pointer. - */ -private_key_t* get_private_key(const connection_t *c) -{ - const secret_t *s, *best = NULL; - - /* is a certificate assigned to this connection? */ - if (c->spd.this.cert) - { - certificate_t *certificate; - public_key_t *pub_key; - - certificate = c->spd.this.cert->cert; - pub_key = certificate->get_public_key(certificate); - - for (s = secrets; s != NULL; s = s->next) - { - if (s->kind == SECRET_PUBKEY && - s->u.private_key->belongs_to(s->u.private_key, pub_key)) - { - best = s; - break; /* found the private key - no sense in searching further */ - } - } - pub_key->destroy(pub_key); - } - else - { - best = get_secret(c, SECRET_PUBKEY); - } - return best ? best->u.private_key : NULL; -} - -/* digest a secrets file - * - * The file is a sequence of records. A record is a maximal sequence of - * tokens such that the first, and only the first, is in the first column - * of a line. - * - * Tokens are generally separated by whitespace and are key words, ids, - * strings, or data suitable for ttodata(3). As a nod to convention, - * a trailing ":" on what would otherwise be a token is taken as a - * separate token. If preceded by whitespace, a "#" is taken as starting - * a comment: it and the rest of the line are ignored. - * - * One kind of record is an include directive. It starts with "include". - * The filename is the only other token in the record. - * If the filename does not start with /, it is taken to - * be relative to the directory containing the current file. - * - * The other kind of record describes a key. It starts with a - * sequence of ids and ends with key information. Each id - * is an IP address, a Fully Qualified Domain Name (which will immediately - * be resolved), or @FQDN which will be left as a name. - * - * The key part can be in several forms. - * - * The old form of the key is still supported: a simple - * quoted strings (with no escapes) is taken as a preshred key. - * - * The new form starts the key part with a ":". - * - * For Preshared Key, use the "PSK" keyword, and follow it by a string - * or a data token suitable for ttodata(3). - * - * For RSA Private Key, use the "RSA" keyword, followed by a - * brace-enclosed list of key field keywords and data values. - * The data values are large integers to be decoded by ttodata(3). - * The fields are a subset of those used by BIND 8.2 and have the - * same names. - */ - -/* parse PSK from file */ -static err_t process_psk_secret(chunk_t *psk) -{ - err_t ugh = NULL; - - if (*tok == '"' || *tok == '\'') - { - chunk_t secret = { tok + 1, flp->cur - tok -2 }; - - *psk = chunk_clone(secret); - (void) shift(); - } - else - { - char buf[BUF_LEN]; /* limit on size of binary representation of key */ - size_t sz; - - ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz - , diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); - if (ugh != NULL) - { - /* ttodata didn't like PSK data */ - ugh = builddiag("PSK data malformed (%s): %s", ugh, tok); - } - else - { - chunk_t secret = { buf, sz }; - *psk = chunk_clone(secret); - (void) shift(); - } - } - return ugh; -} - -typedef enum rsa_private_key_part_t rsa_private_key_part_t; - -enum rsa_private_key_part_t { - RSA_PART_MODULUS = 0, - RSA_PART_PUBLIC_EXPONENT = 1, - RSA_PART_PRIVATE_EXPONENT = 2, - RSA_PART_PRIME1 = 3, - RSA_PART_PRIME2 = 4, - RSA_PART_EXPONENT1 = 5, - RSA_PART_EXPONENT2 = 6, - RSA_PART_COEFFICIENT = 7 -}; - -const char *rsa_private_key_part_names[] = { - "Modulus", - "PublicExponent", - "PrivateExponent", - "Prime1", - "Prime2", - "Exponent1", - "Exponent2", - "Coefficient" -}; - -/** - * Parse fields of an RSA private key in BIND 8.2's representation - * consistiong of a braced list of keyword and value pairs in required order. - */ -static err_t process_rsa_secret(private_key_t **key) -{ - chunk_t rsa_chunk[countof(rsa_private_key_part_names)]; - u_char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */ - rsa_private_key_part_t part, p; - size_t sz; - err_t ugh; - - for (part = RSA_PART_MODULUS; part <= RSA_PART_COEFFICIENT; part++) - { - const char *keyword = rsa_private_key_part_names[part]; - - if (!shift()) - { - ugh = "premature end of RSA key"; - goto end; - } - if (!tokeqword(keyword)) - { - ugh = builddiag("%s keyword not found where expected in RSA key" - , keyword); - goto end; - } - if (!(shift() && (!tokeq(":") || shift()))) /* ignore optional ":" */ - { - ugh = "premature end of RSA key"; - goto end; - } - ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz, - diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); - if (ugh) - { - ugh = builddiag("RSA data malformed (%s): %s", ugh, tok); - goto end; - } - rsa_chunk[part] = chunk_create(buf, sz); - rsa_chunk[part] = chunk_clone(rsa_chunk[part]); - } - - /* We require an (indented) '}' and the end of the record. - * We break down the test so that the diagnostic will be more helpful. - * Some people don't seem to wish to indent the brace! - */ - if (!shift() || !tokeq("}")) - { - ugh = "malformed end of RSA private key -- indented '}' required"; - goto end; - } - if (shift()) - { - ugh = "malformed end of RSA private key -- unexpected token after '}'"; - goto end; - } - - *key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, - BUILD_RSA_MODULUS, rsa_chunk[RSA_PART_MODULUS], - BUILD_RSA_PUB_EXP, rsa_chunk[RSA_PART_PUBLIC_EXPONENT], - BUILD_RSA_PRIV_EXP, rsa_chunk[RSA_PART_PRIVATE_EXPONENT], - BUILD_RSA_PRIME1, rsa_chunk[RSA_PART_PRIME1], - BUILD_RSA_PRIME2, rsa_chunk[RSA_PART_PRIME2], - BUILD_RSA_EXP1, rsa_chunk[RSA_PART_EXPONENT1], - BUILD_RSA_EXP2, rsa_chunk[RSA_PART_EXPONENT2], - BUILD_RSA_COEFF, rsa_chunk[RSA_PART_COEFFICIENT], - BUILD_END); - - if (*key == NULL) - { - ugh = "parsing of RSA private key failed"; - } - -end: - /* clean up and return */ - for (p = RSA_PART_MODULUS ; p < part; p++) - { - chunk_clear(&rsa_chunk[p]); - } - return ugh; -} - -/* struct used to prompt for a secret passphrase - * from a console with file descriptor fd - */ -typedef struct { - char secret[PROMPT_PASS_LEN+1]; - bool prompt; - int fd; - int try; -} prompt_pass_t; - -/** - * Passphrase callback to read from whack fd - */ -static shared_key_t* whack_pass_cb(prompt_pass_t *pass, shared_key_type_t type, - identification_t *me, identification_t *other, - id_match_t *match_me, id_match_t *match_other) -{ - int n; - - if (type != SHARED_ANY && type != SHARED_PRIVATE_KEY_PASS) - { - return NULL; - } - - if (pass->try > MAX_PROMPT_PASS_TRIALS) - { - whack_log(RC_LOG_SERIOUS, "invalid passphrase, too many trials"); - return NULL; - } - if (pass->try == 1) - { - whack_log(RC_ENTERSECRET, "need passphrase for 'private key'"); - } - else - { - whack_log(RC_ENTERSECRET, "invalid passphrase, please try again"); - } - pass->try++; - - n = read(pass->fd, pass->secret, PROMPT_PASS_LEN); - if (n == -1) - { - whack_log(RC_LOG_SERIOUS, "read(whackfd) failed"); - return NULL; - } - pass->secret[n-1] = '\0'; - - if (strlen(pass->secret) == 0) - { - whack_log(RC_LOG_SERIOUS, "no passphrase entered, aborted"); - return NULL; - } - if (match_me) - { - *match_me = ID_MATCH_PERFECT; - } - if (match_other) - { - *match_other = ID_MATCH_NONE; - } - return shared_key_create(SHARED_PRIVATE_KEY_PASS, - chunk_clone(chunk_create(pass->secret, strlen(pass->secret)))); -} - -/** - * Loads a PKCS#1 or PGP private key file - */ -static private_key_t* load_private_key(char* filename, prompt_pass_t *pass, - key_type_t type) -{ - private_key_t *key = NULL; - char *path; - - path = concatenate_paths(PRIVATE_KEY_PATH, filename); - if (pass && pass->prompt && pass->fd != NULL_FD) - { /* use passphrase callback */ - callback_cred_t *cb; - - cb = callback_cred_create_shared((void*)whack_pass_cb, pass); - lib->credmgr->add_local_set(lib->credmgr, &cb->set); - - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, BUILD_END); - lib->credmgr->remove_local_set(lib->credmgr, &cb->set); - cb->destroy(cb); - if (key) - { - whack_log(RC_SUCCESS, "valid passphrase"); - } - } - else if (pass) - { /* use a given passphrase */ - mem_cred_t *mem; - shared_key_t *shared; - - mem = mem_cred_create(); - lib->credmgr->add_local_set(lib->credmgr, &mem->set); - shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, - chunk_clone(chunk_create(pass->secret, strlen(pass->secret)))); - mem->add_shared(mem, shared, NULL); - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, BUILD_END); - lib->credmgr->remove_local_set(lib->credmgr, &mem->set); - mem->destroy(mem); - } - else - { /* no passphrase */ - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, BUILD_END); - - } - if (key) - { - plog(" loaded private key from '%s'", filename); - } - else - { - plog(" syntax error in private key file"); - } - return key; -} - -/** - * process a key file protected with optional passphrase which can either be - * read from ipsec.secrets or prompted for by using whack - */ -static err_t process_keyfile(private_key_t **key, key_type_t type, int whackfd) -{ - char filename[BUF_LEN]; - prompt_pass_t pass; - - memset(filename,'\0', BUF_LEN); - memset(pass.secret,'\0', sizeof(pass.secret)); - pass.prompt = FALSE; - pass.fd = whackfd; - pass.try = 1; - - /* we expect the filename of a PKCS#1 private key file */ - - if (*tok == '"' || *tok == '\'') /* quoted filename */ - memcpy(filename, tok+1, flp->cur - tok - 2); - else - memcpy(filename, tok, flp->cur - tok); - - if (shift()) - { - /* we expect an appended passphrase or passphrase prompt*/ - if (tokeqword("%prompt")) - { - if (pass.fd == NULL_FD) - { - return "Private key file -- enter passphrase using 'ipsec secrets'"; - } - pass.prompt = TRUE; - } - else - { - char *passphrase = tok; - size_t len = flp->cur - passphrase; - - if (*tok == '"' || *tok == '\'') /* quoted passphrase */ - { - passphrase++; - len -= 2; - } - if (len > PROMPT_PASS_LEN) - { - return "Private key file -- passphrase exceeds 64 characters"; - } - memcpy(pass.secret, passphrase, len); - } - if (shift()) - { - return "Private key file -- unexpected token after passphrase"; - } - } - *key = load_private_key(filename, &pass, type); - - return *key ? NULL : "Private key file -- could not be loaded"; -} - -/** - * Process pin read from ipsec.secrets or prompted for it using whack - */ -static err_t process_pin(secret_t *s, int whackfd) -{ - smartcard_t *sc; - const char *pin_status = "no pin"; - - s->kind = SECRET_PIN; - - /* looking for the smartcard keyword */ - if (!shift() || strncmp(tok, SCX_TOKEN, strlen(SCX_TOKEN)) != 0) - return "PIN keyword must be followed by %smartcard<reader>:<id>"; - - sc = scx_add(scx_parse_number_slot_id(tok + strlen(SCX_TOKEN))); - s->u.smartcard = sc; - scx_share(sc); - if (sc->pin.ptr != NULL) - { - scx_release_context(sc); - scx_free_pin(&sc->pin); - } - sc->valid = FALSE; - - if (!shift()) - return "PIN statement must be terminated either by <pin code>, %pinpad or %prompt"; - - if (tokeqword("%prompt")) - { - shift(); - /* if whackfd exists, whack will be used to prompt for a pin */ - if (whackfd != NULL_FD) - pin_status = scx_get_pin(sc, whackfd) ? "valid pin" : "invalid pin"; - else - pin_status = "pin entry via prompt"; - } - else if (tokeqword("%pinpad")) - { - chunk_t empty_pin = { "", 0 }; - - shift(); - - /* pin will be entered via pin pad during verification */ - sc->pin = chunk_clone(empty_pin); - sc->pinpad = TRUE; - sc->valid = TRUE; - pin_status = "pin entry via pad"; - if (pkcs11_keep_state) - { - scx_verify_pin(sc); - } - } - else - { - /* we read the pin directly from ipsec.secrets */ - err_t ugh = process_psk_secret(&sc->pin); - if (ugh != NULL) - return ugh; - /* verify the pin */ - pin_status = scx_verify_pin(sc) ? "valid PIN" : "invalid PIN"; - } -#ifdef SMARTCARD - { - char buf[BUF_LEN]; - - if (sc->any_slot) - snprintf(buf, BUF_LEN, "any slot"); - else - snprintf(buf, BUF_LEN, "slot: %lu", sc->slot); - - plog(" %s for #%d (%s, id: %s)" - , pin_status, sc->number, scx_print_slot(sc, ""), sc->id); - } -#else - plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!"); -#endif - return NULL; -} - -static void log_psk(char *label, secret_t *s) -{ - int n = 0; - char buf[BUF_LEN]; - enumerator_t *enumerator; - identification_t *id; - - if (s->ids->get_count(s->ids) == 0) - { - n = snprintf(buf, BUF_LEN, "%%any"); - } - else - { - enumerator = s->ids->create_enumerator(s->ids); - while(enumerator->enumerate(enumerator, &id)) - { - n += snprintf(buf + n, BUF_LEN - n, "%Y ", id); - if (n >= BUF_LEN) - { - n = BUF_LEN - 1; - break; - } - } - enumerator->destroy(enumerator); - } - plog(" loaded %s secret for %.*s", label, n, buf); -} - -static void process_secret(secret_t *s, int whackfd) -{ - err_t ugh = NULL; - - s->kind = SECRET_PSK; /* default */ - if (tokeqword("psk")) - { - log_psk("PSK", s); - - /* preshared key: quoted string or ttodata format */ - ugh = !shift()? "unexpected end of record in PSK" - : process_psk_secret(&s->u.preshared_secret); - } - else if (tokeqword("xauth")) - { - s->kind = SECRET_XAUTH; - log_psk("XAUTH", s); - - /* xauth secret: quoted string or ttodata format */ - ugh = !shift()? "unexpected end of record in XAUTH" - : process_psk_secret(&s->u.preshared_secret); - } - else if (tokeqword("rsa")) - { - /* RSA key: the fun begins. - * A braced list of keyword and value pairs. - */ - s->kind = SECRET_PUBKEY; - if (!shift()) - { - ugh = "bad RSA key syntax"; - } - else if (tokeq("{")) - { - ugh = process_rsa_secret(&s->u.private_key); - } - else - { - ugh = process_keyfile(&s->u.private_key, KEY_RSA, whackfd); - } - } - else if (tokeqword("ecdsa")) - { - s->kind = SECRET_PUBKEY; - if (!shift()) - { - ugh = "bad ECDSA key syntax"; - } - else - { - ugh = process_keyfile(&s->u.private_key, KEY_ECDSA, whackfd); - } - } - else if (tokeqword("pin")) - { - ugh = process_pin(s, whackfd); - } - else - { - ugh = builddiag("unrecognized key format: %s", tok); - } - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s" - , flp->filename, flp->lino, ugh); - s->ids->destroy_offset(s->ids, offsetof(identification_t, destroy)); - free(s); - } - else if (flushline("expected record boundary in key")) - { - /* gauntlet has been run: install new secret */ - lock_certs_and_keys("process_secret"); - s->next = secrets; - secrets = s; - unlock_certs_and_keys("process_secrets"); - } -} - -static void process_secrets_file(const char *file_pat, int whackfd); /* forward declaration */ - -static void process_secret_records(int whackfd) -{ - /* read records from ipsec.secrets and load them into our table */ - for (;;) - { - (void)flushline(NULL); /* silently ditch leftovers, if any */ - if (flp->bdry == B_file) - { - break; - } - flp->bdry = B_none; /* eat the Record Boundary */ - (void)shift(); /* get real first token */ - - if (tokeqword("include")) - { - /* an include directive */ - char fn[MAX_TOK_LEN]; /* space for filename (I hope) */ - char *p = fn; - char *end_prefix = strrchr(flp->filename, '/'); - - if (!shift()) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end of include directive" - , flp->filename, flp->lino); - continue; /* abandon this record */ - } - - /* if path is relative and including file's pathname has - * a non-empty dirname, prefix this path with that dirname. - */ - if (tok[0] != '/' && end_prefix != NULL) - { - size_t pl = end_prefix - flp->filename + 1; - - /* "clamp" length to prevent problems now; - * will be rediscovered and reported later. - */ - if (pl > sizeof(fn)) - { - pl = sizeof(fn); - } - memcpy(fn, flp->filename, pl); - p += pl; - } - if (flp->cur - tok >= &fn[sizeof(fn)] - p) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: include pathname too long" - , flp->filename, flp->lino); - continue; /* abandon this record */ - } - strcpy(p, tok); - (void) shift(); /* move to Record Boundary, we hope */ - if (flushline("ignoring malformed INCLUDE -- expected Record Boundary after filename")) - { - process_secrets_file(fn, whackfd); - tok = NULL; /* correct, but probably redundant */ - } - } - else - { - /* expecting a list of indices and then the key info */ - secret_t *s = malloc_thing(secret_t); - - zero(s); - s->ids = linked_list_create(); - s->kind = SECRET_PSK; /* default */ - s->u.preshared_secret = chunk_empty; - s->next = NULL; - - for (;;) - { - if (tokeq(":")) - { - /* found key part */ - shift(); /* discard explicit separator */ - process_secret(s, whackfd); - break; - } - else - { - identification_t *id; - - id = identification_create_from_string(tok); - s->ids->insert_last(s->ids, id); - - if (!shift()) - { - /* unexpected Record Boundary or EOF */ - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end" - " of id list", flp->filename, flp->lino); - s->ids->destroy_offset(s->ids, - offsetof(identification_t, destroy)); - free(s); - break; - } - } - } - } - } -} - -static int globugh(const char *epath, int eerrno) -{ - log_errno_routine(eerrno, "problem with secrets file \"%s\"", epath); - return 1; /* stop glob */ -} - -static void process_secrets_file(const char *file_pat, int whackfd) -{ - struct file_lex_position pos; - char **fnp; - - pos.depth = flp == NULL? 0 : flp->depth + 1; - - if (pos.depth > 10) - { - loglog(RC_LOG_SERIOUS, "preshared secrets file \"%s\" nested too deeply", file_pat); - return; - } - -#ifdef HAVE_GLOB_H - /* do globbing */ - { - glob_t globbuf; - int r = glob(file_pat, GLOB_ERR, globugh, &globbuf); - - if (r != 0) - { - switch (r) - { - case GLOB_NOSPACE: - loglog(RC_LOG_SERIOUS, "out of space processing secrets filename \"%s\"", file_pat); - break; - case GLOB_ABORTED: - break; /* already logged */ - case GLOB_NOMATCH: - loglog(RC_LOG_SERIOUS, "no secrets filename matched \"%s\"", file_pat); - break; - default: - loglog(RC_LOG_SERIOUS, "unknown glob error %d", r); - break; - } - globfree(&globbuf); - return; - } - - /* for each file... */ - for (fnp = globbuf.gl_pathv; *fnp != NULL; fnp++) - { - if (lexopen(&pos, *fnp, FALSE)) - { - plog("loading secrets from \"%s\"", *fnp); - flushline("file starts with indentation (continuation notation)"); - process_secret_records(whackfd); - lexclose(); - } - } - - globfree(&globbuf); - } -#else /* HAVE_GLOB_H */ - /* if glob(3) is not available, try to load pattern directly */ - if (lexopen(&pos, file_pat, FALSE)) - { - plog("loading secrets from \"%s\"", file_pat); - flushline("file starts with indentation (continuation notation)"); - process_secret_records(whackfd); - lexclose(); - } -#endif /* HAVE_GLOB_H */ -} - -void free_preshared_secrets(void) -{ - lock_certs_and_keys("free_preshared_secrets"); - - if (secrets != NULL) - { - secret_t *s, *ns; - - plog("forgetting secrets"); - - for (s = secrets; s != NULL; s = ns) - { - ns = s->next; - s->ids->destroy_offset(s->ids, offsetof(identification_t, destroy)); - - switch (s->kind) - { - case SECRET_PSK: - case SECRET_XAUTH: - free(s->u.preshared_secret.ptr); - break; - case SECRET_PUBKEY: - DESTROY_IF(s->u.private_key); - break; - case SECRET_PIN: - scx_release(s->u.smartcard); - break; - default: - bad_case(s->kind); - } - free(s); - } - secrets = NULL; - } - - unlock_certs_and_keys("free_preshard_secrets"); -} - -void load_preshared_secrets(int whackfd) -{ - free_preshared_secrets(); - (void) process_secrets_file(shared_secrets_file, whackfd); -} - -/* public key machinery - * Note: caller must set dns_auth_level. - */ - -pubkey_t* public_key_from_rsa(public_key_t *key) -{ - pubkey_t *p = malloc_thing(pubkey_t); - - zero(p); - p->id = identification_create_from_string("%any"); /* don't know, doesn't matter */ - p->issuer = NULL; - p->serial = chunk_empty; - p->public_key = key; - - /* note that we return a 1 reference count upon creation: - * invariant: recount > 0. - */ - p->refcnt = 1; - return p; -} - -/* Free a public key record. - * As a convenience, this returns a pointer to next. - */ -pubkey_list_t* free_public_keyentry(pubkey_list_t *p) -{ - pubkey_list_t *nxt = p->next; - - if (p->key != NULL) - { - unreference_key(&p->key); - } - free(p); - return nxt; -} - -void free_public_keys(pubkey_list_t **keys) -{ - while (*keys != NULL) - { - *keys = free_public_keyentry(*keys); - } -} - -/* root of chained public key list */ - -pubkey_list_t *pubkeys = NULL; /* keys from ipsec.conf */ - -void free_remembered_public_keys(void) -{ - free_public_keys(&pubkeys); -} - -/** - * Transfer public keys from *keys list to front of pubkeys list - */ -void transfer_to_public_keys(struct gw_info *gateways_from_dns -#ifdef USE_KEYRR -, pubkey_list_t **keys -#endif /* USE_KEYRR */ -) -{ - { - struct gw_info *gwp; - - for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - pubkey_list_t *pl = malloc_thing(pubkey_list_t); - - pl->key = gwp->key; /* note: this is a transfer */ - gwp->key = NULL; /* really, it is! */ - pl->next = pubkeys; - pubkeys = pl; - } - } - -#ifdef USE_KEYRR - { - pubkey_list_t **pp = keys; - - while (*pp != NULL) - { - pp = &(*pp)->next; - } - *pp = pubkeys; - pubkeys = *keys; - *keys = NULL; - } -#endif /* USE_KEYRR */ -} - - -static void install_public_key(pubkey_t *pk, pubkey_list_t **head) -{ - pubkey_list_t *p = malloc_thing(pubkey_list_t); - - /* install new key at front */ - p->key = reference_key(pk); - p->next = *head; - *head = p; -} - -void delete_public_keys(identification_t *id, key_type_t type, - identification_t *issuer, chunk_t serial) -{ - pubkey_list_t **pp, *p; - pubkey_t *pk; - key_type_t pk_type; - - for (pp = &pubkeys; (p = *pp) != NULL; ) - { - pk = p->key; - pk_type = pk->public_key->get_type(pk->public_key); - - if (id->equals(id, pk->id) && pk_type == type - && (issuer == NULL || pk->issuer == NULL - || issuer->equals(issuer, pk->issuer)) - && (serial.ptr == NULL || chunk_equals(serial, pk->serial))) - { - *pp = free_public_keyentry(p); - } - else - { - pp = &p->next; - } - } -} - -pubkey_t* reference_key(pubkey_t *pk) -{ - DBG(DBG_CONTROLMORE, - DBG_log(" ref key: %p %p cnt %d '%Y'", - pk, pk->public_key, pk->refcnt, pk->id) - ) - pk->refcnt++; - return pk; -} - -void unreference_key(pubkey_t **pkp) -{ - pubkey_t *pk = *pkp; - - if (pk == NULL) - { - return; - } - - DBG(DBG_CONTROLMORE, - DBG_log("unref key: %p %p cnt %d '%Y'", - pk, pk->public_key, pk->refcnt, pk->id) - ) - - /* cancel out the pointer */ - *pkp = NULL; - - passert(pk->refcnt != 0); - pk->refcnt--; - if (pk->refcnt == 0) - { - free_public_key(pk); - } -} - -bool add_public_key(identification_t *id, enum dns_auth_level dns_auth_level, - enum pubkey_alg alg, chunk_t rfc3110_key, - pubkey_list_t **head) -{ - public_key_t *key = NULL; - pubkey_t *pk; - - /* first: algorithm-specific decoding of key chunk */ - switch (alg) - { - case PUBKEY_ALG_RSA: - key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, - BUILD_BLOB_DNSKEY, rfc3110_key, - BUILD_END); - if (key == NULL) - { - return FALSE; - } - break; - default: - bad_case(alg); - } - - pk = malloc_thing(pubkey_t); - zero(pk); - pk->public_key = key; - pk->id = id->clone(id); - pk->dns_auth_level = dns_auth_level; - pk->until_time = UNDEFINED_TIME; - pk->issuer = NULL; - pk->serial = chunk_empty; - install_public_key(pk, head); - return TRUE; -} - -/** - * Extract id and public key a certificate and insert it into a pubkeyrec - */ -void add_public_key_from_cert(cert_t *cert , time_t until, - enum dns_auth_level dns_auth_level) -{ - certificate_t *certificate = cert->cert; - identification_t *subject = certificate->get_subject(certificate); - identification_t *issuer = NULL; - identification_t *id; - chunk_t serialNumber = chunk_empty; - pubkey_t *pk; - key_type_t pk_type; - - /* ID type: ID_DER_ASN1_DN (X.509 subject field) */ - pk = malloc_thing(pubkey_t); - zero(pk); - pk->public_key = certificate->get_public_key(certificate); - pk_type = pk->public_key->get_type(pk->public_key); - pk->id = subject->clone(subject); - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - if (certificate->get_type(certificate) == CERT_X509) - { - x509_t *x509 = (x509_t*)certificate; - - issuer = certificate->get_issuer(certificate); - serialNumber = x509->get_serial(x509); - pk->issuer = issuer->clone(issuer); - pk->serial = chunk_clone(serialNumber); - } - delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); - - if (certificate->get_type(certificate) == CERT_X509) - { - x509_t *x509 = (x509_t*)certificate; - enumerator_t *enumerator; - - /* insert all subjectAltNames from X.509 certificates */ - enumerator = x509->create_subjectAltName_enumerator(x509); - while (enumerator->enumerate(enumerator, &id)) - { - if (id->get_type(id) != ID_ANY) - { - pk = malloc_thing(pubkey_t); - zero(pk); - pk->id = id->clone(id); - pk->public_key = certificate->get_public_key(certificate); - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - pk->issuer = issuer->clone(issuer); - pk->serial = chunk_clone(serialNumber); - delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); - } - } - enumerator->destroy(enumerator); - } - else - { - pgp_certificate_t *pgp_cert = (pgp_certificate_t*)certificate; - chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert); - - /* add v3 or v4 PGP fingerprint */ - pk = malloc_thing(pubkey_t); - zero(pk); - pk->id = identification_create_from_encoding(ID_KEY_ID, fingerprint); - pk->public_key = certificate->get_public_key(certificate); - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); - } -} - -/* when a X.509 certificate gets revoked, all instances of - * the corresponding public key must be removed - */ -void remove_x509_public_key(const cert_t *cert) -{ - public_key_t *revoked_key = cert->cert->get_public_key(cert->cert); - pubkey_list_t *p, **pp; - - p = pubkeys; - pp = &pubkeys; - - while(p != NULL) - { - if (revoked_key->equals(revoked_key, p->key->public_key)) - { - /* remove p from list and free memory */ - *pp = free_public_keyentry(p); - loglog(RC_LOG_SERIOUS, "invalid public key deleted"); - } - else - { - pp = &p->next; - } - p =*pp; - } - revoked_key->destroy(revoked_key); -} - -/* - * list all public keys in the chained list - */ -void list_public_keys(bool utc) -{ - pubkey_list_t *p = pubkeys; - chunk_t serial; - - if (p != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of Public Keys:"); - } - - while (p != NULL) - { - pubkey_t *key = p->key; - public_key_t *public = key->public_key; - chunk_t keyid; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " identity: '%Y'", key->id); - whack_log(RC_COMMENT, " pubkey: %N %4d bits, until %T %s", - key_type_names, public->get_type(public), - public->get_keysize(public), - &key->until_time, utc, - check_expiry(key->until_time, PUBKEY_WARNING_INTERVAL, TRUE)); - if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) - { - whack_log(RC_COMMENT," keyid: %#B", &keyid); - } - if (key->issuer) - { - whack_log(RC_COMMENT," issuer: \"%Y\"", key->issuer); - } - if (key->serial.len) - { - serial = chunk_skip_zero(key->serial); - whack_log(RC_COMMENT," serial: %#B", &serial); - } - p = p->next; - } -} diff --git a/src/pluto/keys.h b/src/pluto/keys.h deleted file mode 100644 index 73cc21392..000000000 --- a/src/pluto/keys.h +++ /dev/null @@ -1,93 +0,0 @@ -/* mechanisms for preshared keys (public, private, and preshared secrets) - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen, Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _KEYS_H -#define _KEYS_H - -#include <utils/identification.h> -#include <credentials/keys/private_key.h> -#include <credentials/keys/public_key.h> - -#include "certs.h" -#include "connections.h" - -#ifndef SHARED_SECRETS_FILE -# define SHARED_SECRETS_FILE IPSEC_CONFDIR "/ipsec.secrets" -#endif - -const char *shared_secrets_file; - -extern void load_preshared_secrets(int whackfd); -extern void free_preshared_secrets(void); - -extern void xauth_defaults(void); - -extern bool get_xauth_secret(identification_t *user, identification_t *server, - chunk_t *secret); -extern const chunk_t *get_preshared_secret(const connection_t *c); -extern private_key_t *get_private_key(const connection_t *c); -extern private_key_t *get_x509_private_key(const cert_t *cert); - -/* public key machinery */ - -typedef struct pubkey pubkey_t; - -struct pubkey { - identification_t *id; - unsigned refcnt; /* reference counted! */ - enum dns_auth_level dns_auth_level; - char *dns_sig; - time_t last_tried_time, last_worked_time, until_time; - identification_t *issuer; - chunk_t serial; - public_key_t *public_key; -}; - -typedef struct pubkey_list pubkey_list_t; - -struct pubkey_list { - pubkey_t *key; - pubkey_list_t *next; -}; - -extern pubkey_list_t *pubkeys; /* keys from ipsec.conf or from certs */ - -extern pubkey_t *public_key_from_rsa(public_key_t *key); -extern pubkey_list_t *free_public_keyentry(pubkey_list_t *p); -extern void free_public_keys(pubkey_list_t **keys); -extern void free_remembered_public_keys(void); -extern void delete_public_keys(identification_t *id, key_type_t type, - identification_t *issuer, chunk_t serial); -extern pubkey_t *reference_key(pubkey_t *pk); -extern void unreference_key(pubkey_t **pkp); -extern bool add_public_key(identification_t *id, - enum dns_auth_level dns_auth_level, - enum pubkey_alg alg, - chunk_t rfc3110_key, - pubkey_list_t **head); -extern bool has_private_key(cert_t *cert); -extern void add_public_key_from_cert(cert_t *cert, time_t until, - enum dns_auth_level dns_auth_level); -extern void remove_x509_public_key(const cert_t *cert); -extern void list_public_keys(bool utc); - -struct gw_info; /* forward declaration of tag (defined in dnskey.h) */ -extern void transfer_to_public_keys(struct gw_info *gateways_from_dns -#ifdef USE_KEYRR - , pubkey_list_t **keys -#endif /* USE_KEYRR */ - ); - -#endif /* _KEYS_H */ diff --git a/src/pluto/lex.c b/src/pluto/lex.c deleted file mode 100644 index d5ebdaba9..000000000 --- a/src/pluto/lex.c +++ /dev/null @@ -1,211 +0,0 @@ -/* lexer (lexical analyzer) for control files - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <ctype.h> -#include <unistd.h> -#include <errno.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "lex.h" - -struct file_lex_position *flp = NULL; - -/* Open a file for lexical processing. - * new_flp and name must point into storage with will live - * at least until the file is closed. - */ -bool -lexopen(struct file_lex_position *new_flp, const char *name, bool optional) -{ - FILE *f = fopen(name, "r"); - - if (f == NULL) - { - if (!optional || errno != ENOENT) - log_errno((e, "could not open \"%s\"", name)); - return FALSE; - } - else - { - new_flp->previous = flp; - flp = new_flp; - flp->filename = name; - flp->fp = f; - flp->lino = 0; - flp->bdry = B_none; - - flp->cur = flp->buffer; /* nothing loaded yet */ - flp->under = *flp->cur = '\0'; - - (void) shift(); /* prime tok */ - return TRUE; - } -} - -void -lexclose(void) -{ - fclose(flp->fp); - flp = flp->previous; -} - -/* Token decoding: shift() loads the next token into tok. - * Iff a token starts at the left margin, it is considered - * to be the first in a record. We create a special condition, - * Record Boundary (analogous to EOF), just before such a token. - * We are unwilling to shift through a record boundary: - * it must be overridden first. - * Returns FALSE iff Record Boundary or EOF (i.e. no token); - * tok will then be NULL. - */ - -char *tok; -#define tokeq(s) (streq(tok, (s))) -#define tokeqword(s) (strcasecmp(tok, (s)) == 0) - -bool -shift(void) -{ - char *p = flp->cur; - char *sor = NULL; /* start of record for any new lines */ - - passert(flp->bdry == B_none); - - *p = flp->under; - flp->under = '\0'; - - for (;;) - { - switch (*p) - { - case '\0': /* end of line */ - case '#': /* comment to end of line: treat as end of line */ - /* get the next line */ - if (fgets(flp->buffer, sizeof(flp->buffer)-1, flp->fp) == NULL) - { - flp->bdry = B_file; - tok = flp->cur = NULL; - return FALSE; - } - else - { - /* strip trailing whitespace, including \n */ - - for (p = flp->buffer+strlen(flp->buffer)-1 - ; p>flp->buffer && isspace(p[-1]); p--) - ; - *p = '\0'; - - flp->lino++; - sor = p = flp->buffer; - } - break; /* try again for a token */ - - case ' ': /* whitespace */ - case '\t': - p++; - break; /* try again for a token */ - - case '"': /* quoted token */ - case '\'': - if (p != sor) - { - /* we have a quoted token: note and advance to its end */ - tok = p; - p = strchr(p+1, *p); - if (p == NULL) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unterminated string" - , flp->filename, flp->lino); - p = tok + strlen(tok); - } - else - { - p++; /* include delimiter in token */ - } - - /* remember token delimiter and replace with '\0' */ - flp->under = *p; - *p = '\0'; - flp->cur = p; - return TRUE; - } - /* FALL THROUGH */ - default: - if (p != sor) - { - /* we seem to have a token: note and advance to its end */ - tok = p; - - if (p[0] == '0' && p[1] == 't') - { - /* 0t... token goes to end of line */ - p += strlen(p); - } - else - { - /* "ordinary" token: up to whitespace or end of line */ - do { - p++; - } while (*p != '\0' && !isspace(*p)) - ; - - /* fudge to separate ':' from a preceding adjacent token */ - if (p-1 > tok && p[-1] == ':') - p--; - } - - /* remember token delimiter and replace with '\0' */ - flp->under = *p; - *p = '\0'; - flp->cur = p; - return TRUE; - } - - /* we have a start-of-record: return it, deferring "real" token */ - flp->bdry = B_record; - tok = NULL; - flp->under = *p; - flp->cur = p; - return FALSE; - } - } -} - -/* ensures we are at a Record (or File) boundary, optionally warning if not */ - -bool -flushline(const char *m) -{ - if (flp->bdry != B_none) - { - return TRUE; - } - else - { - if (m != NULL) - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s", flp->filename, flp->lino, m); - do {} while (shift()); - return FALSE; - } -} diff --git a/src/pluto/lex.h b/src/pluto/lex.h deleted file mode 100644 index aa0be7829..000000000 --- a/src/pluto/lex.h +++ /dev/null @@ -1,50 +0,0 @@ -/* lexer (lexical analyzer) for control files - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#define MAX_TOK_LEN 2048 /* includes terminal '\0' */ -struct file_lex_position -{ - int depth; /* how deeply we are nested */ - const char *filename; - FILE *fp; - enum { B_none, B_record, B_file } bdry; /* current boundary */ - int lino; /* line number in file */ - char buffer[MAX_TOK_LEN + 1]; /* note: one extra char for our use (jamming '"') */ - char *cur; /* cursor */ - char under; /* except in shift(): character originally at *cur */ - struct file_lex_position *previous; -}; - -extern struct file_lex_position *flp; - -extern bool lexopen(struct file_lex_position *new_flp, const char *name, bool optional); -extern void lexclose(void); - - -/* Token decoding: shift() loads the next token into tok. - * Iff a token starts at the left margin, it is considered - * to be the first in a record. We create a special condition, - * Record Boundary (analogous to EOF), just before such a token. - * We are unwilling to shift through a record boundary: - * it must be overridden first. - * Returns FALSE iff Record Boundary or EOF (i.e. no token); - * tok will then be NULL. - */ - -extern char *tok; -#define tokeq(s) (streq(tok, (s))) -#define tokeqword(s) (strcasecmp(tok, (s)) == 0) - -extern bool shift(void); -extern bool flushline(const char *m); diff --git a/src/pluto/log.c b/src/pluto/log.c deleted file mode 100644 index f6fa226d5..000000000 --- a/src/pluto/log.c +++ /dev/null @@ -1,946 +0,0 @@ -/* error logging functions - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <stdarg.h> -#include <syslog.h> -#include <errno.h> -#include <string.h> -#include <unistd.h> -#include <signal.h> /* used only if MSG_NOSIGNAL not defined */ -#include <sys/queue.h> -#include <libgen.h> -#include <sys/stat.h> -#include <sys/types.h> - -#ifdef ANDROID -#include <android/log.h> -#endif - -#include <freeswan.h> -#include <library.h> -#include <debug.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "server.h" -#include "state.h" -#include "connections.h" -#include "myid.h" -#include "kernel.h" -#include "whack.h" -#include "whack_attribute.h" -#include "timer.h" - -/* close one per-peer log */ -static void perpeer_logclose(connection_t *c); /* forward */ - - -bool - log_to_stderr = TRUE, /* should log go to stderr? */ - log_to_syslog = TRUE, /* should log go to syslog? */ - log_to_perpeer= FALSE; /* should log go to per-IP file? */ - -bool - logged_txt_warning = FALSE; /* should we complain about finding KEY? */ - -/* should we complain when we find no local id */ -bool - logged_myid_fqdn_txt_warning = FALSE, - logged_myid_ip_txt_warning = FALSE, - logged_myid_fqdn_key_warning = FALSE, - logged_myid_ip_key_warning = FALSE; - -/* may include trailing / */ -const char *base_perpeer_logdir = PERPEERLOGDIR; -static int perpeer_count = 0; - -/* from sys/queue.h */ -static TAILQ_HEAD(perpeer, connection) perpeer_list; - - -/* Context for logging. - * - * Global variables: must be carefully adjusted at transaction boundaries! - * If the context provides a whack file descriptor, messages - * should be copied to it -- see whack_log() - */ -int whack_log_fd = NULL_FD; /* only set during whack_handle() */ -struct state *cur_state = NULL; /* current state, for diagnostics */ -connection_t *cur_connection = NULL; /* current connection, for diagnostics */ -const ip_address *cur_from = NULL; /* source of current current message */ -u_int16_t cur_from_port; /* host order */ - -/** - * pluto dbg function for libstrongswan - */ -static void pluto_dbg(debug_t group, level_t level, char *fmt, ...) -{ - int priority = LOG_INFO; - int debug_level; - char buffer[8192]; - char *current = buffer, *next; - va_list args; - - if (cur_debugging & DBG_PRIVATE) - { - debug_level = 4; - } - else if (cur_debugging & DBG_RAW) - { - debug_level = 3; - } - else if (cur_debugging & DBG_PARSING) - { - debug_level = 2; - } - else - { - debug_level = 1; - } - - if (level <= debug_level) - { - va_start(args, fmt); - - if (log_to_stderr) - { - if (level > 1) - { - fprintf(stderr, "| "); - } - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - } - if (log_to_syslog -#ifdef ANDROID - || TRUE -#endif - ) - { - /* write in memory buffer first */ - vsnprintf(buffer, sizeof(buffer), fmt, args); - - /* do a syslog with every line */ - while (current) - { - next = strchr(current, '\n'); - if (next) - { - *(next++) = '\0'; - } - syslog(priority, "%s%s\n", (level > 1)? "| ":"", current); -#ifdef ANDROID - __android_log_print(level > 1 ? ANDROID_LOG_DEBUG - : ANDROID_LOG_INFO, "pluto", - "%s%s\n", level > 1 ? "| " : "", current); -#endif - current = next; - } - } - va_end(args); - } -} - -void -init_log(const char *program) -{ - /* enable pluto debugging hook for libstrongswan */ - dbg = pluto_dbg; - - if (log_to_stderr) - { - setbuf(stderr, NULL); - } - if (log_to_syslog) - { - openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV); - } - TAILQ_INIT(&perpeer_list); -} - -void -close_peerlog(void) -{ - /* exit if the queue has not been initialized */ - if (perpeer_list.tqh_first == NULL) - return; - - /* end of queue is given by pointer to "HEAD" */ - while (TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list) - perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer)); -} - -void -close_log(void) -{ - if (log_to_syslog) - closelog(); - - close_peerlog(); -} - -/* Sanitize character string in situ: turns dangerous characters into \OOO. - * With a bit of work, we could use simpler reps for \\, \r, etc., - * but this is only to protect against something that shouldn't be used. - * Truncate resulting string to what fits in buffer. - */ -static size_t -sanitize(char *buf, size_t size) -{ -# define UGLY_WIDTH 4 /* width for ugly character: \OOO */ - size_t len; - size_t added = 0; - char *p; - - passert(size >= UGLY_WIDTH); /* need room to swing cat */ - - /* find right side of string to be sanitized and count - * number of columns to be added. Stop on end of string - * or lack of room for more result. - */ - for (p = buf; *p != '\0' && &p[added] < &buf[size - UGLY_WIDTH]; ) - { - unsigned char c = *p++; - - if (c == '\\' || !isprint(c)) - added += UGLY_WIDTH - 1; - } - - /* at this point, p points after last original character to be - * included. added is how many characters are added to sanitize. - * so p[added] will point after last sanitized character. - */ - - p[added] = '\0'; - len = &p[added] - buf; - - /* scan backwards, copying characters to their new home - * and inserting the expansions for ugly characters. - * It is finished when no more shifting is required. - * This is a predecrement loop. - */ - while (added != 0) - { - char fmtd[UGLY_WIDTH + 1]; - unsigned char c; - - while ((c = *--p) != '\\' && isprint(c)) - p[added] = c; - added -= UGLY_WIDTH - 1; - snprintf(fmtd, sizeof(fmtd), "\\%03o", c); - memcpy(p + added, fmtd, UGLY_WIDTH); - } - return len; -# undef UGLY_WIDTH -} - -/* format a string for the log, with suitable prefixes. - * A format starting with ~ indicates that this is a reprocessing - * of the message, so prefixing and quoting is suppressed. - */ -static void -fmt_log(char *buf, size_t buf_len, const char *fmt, va_list ap) -{ - bool reproc = *fmt == '~'; - size_t ps; - connection_t *c = cur_state != NULL ? cur_state->st_connection - : cur_connection; - - buf[0] = '\0'; - if (reproc) - fmt++; /* ~ at start of format suppresses this prefix */ - else if (c != NULL) - { - /* start with name of connection */ - char *const be = buf + buf_len; - char *bp = buf; - - snprintf(bp, be - bp, "\"%s\"", c->name); - bp += strlen(bp); - - /* if it fits, put in any connection instance information */ - if (be - bp > CONN_INST_BUF) - { - fmt_conn_instance(c, bp); - bp += strlen(bp); - } - - if (cur_state != NULL) - { - /* state number */ - snprintf(bp, be - bp, " #%lu", cur_state->st_serialno); - bp += strlen(bp); - } - snprintf(bp, be - bp, ": "); - } - else if (cur_from != NULL) - { - /* peer's IP address */ - /* Note: must not use ip_str() because our caller might! */ - char ab[ADDRTOT_BUF]; - - (void) addrtot(cur_from, 0, ab, sizeof(ab)); - snprintf(buf, buf_len, "packet from %s:%u: " - , ab, (unsigned)cur_from_port); - } - - ps = strlen(buf); - vsnprintf(buf + ps, buf_len - ps, fmt, ap); - if (!reproc) - (void)sanitize(buf, buf_len); -} - -static void -perpeer_logclose(connection_t *c) -{ - /* only free/close things if we had used them! */ - if (c->log_file != NULL) - { - passert(perpeer_count > 0); - - TAILQ_REMOVE(&perpeer_list, c, log_link); - perpeer_count--; - fclose(c->log_file); - c->log_file=NULL; - } -} - -void -perpeer_logfree(connection_t *c) -{ - perpeer_logclose(c); - if (c->log_file_name != NULL) - { - free(c->log_file_name); - c->log_file_name = NULL; - c->log_file_err = FALSE; - } -} - -/* open the per-peer log */ -static void -open_peerlog(connection_t *c) -{ - syslog(LOG_INFO, "opening log file for conn %s", c->name); - - if (c->log_file_name == NULL) - { - char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF]; - int peernamelen, lf_len; - - addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername)); - peernamelen = strlen(peername); - - /* copy IP address, turning : and . into / */ - { - char ch, *p, *q; - - p = peername; - q = dname; - do { - ch = *p++; - if (ch == '.' || ch == ':') - ch = '/'; - *q++ = ch; - } while (ch != '\0'); - } - - lf_len = peernamelen * 2 - + strlen(base_perpeer_logdir) - + sizeof("//.log") - + 1; - c->log_file_name = malloc(lf_len); - - fprintf(stderr, "base dir |%s| dname |%s| peername |%s|" - , base_perpeer_logdir, dname, peername); - snprintf(c->log_file_name, lf_len, "%s/%s/%s.log" - , base_perpeer_logdir, dname, peername); - - syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name); - } - - /* now open the file, creating directories if necessary */ - - { /* create the directory */ - char *dname; - int bpl_len = strlen(base_perpeer_logdir); - char *slashloc; - - dname = clone_str(c->log_file_name); - dname = dirname(dname); - - if (access(dname, W_OK) != 0) - { - if (errno != ENOENT) - { - if (c->log_file_err) - { - syslog(LOG_CRIT, "can not write to %s: %s" - , dname, strerror(errno)); - c->log_file_err = TRUE; - free(dname); - return; - } - } - - /* directory does not exist, walk path creating dirs */ - /* start at base_perpeer_logdir */ - slashloc = dname + bpl_len; - slashloc++; /* since, by construction there is a slash - right there */ - - while (*slashloc != '\0') - { - char saveslash; - - /* look for next slash */ - while (*slashloc != '\0' && *slashloc != '/') slashloc++; - - saveslash = *slashloc; - - *slashloc = '\0'; - - if (mkdir(dname, 0750) != 0 && errno != EEXIST) - { - syslog(LOG_CRIT, "can not create dir %s: %s" - , dname, strerror(errno)); - c->log_file_err = TRUE; - free(dname); - return; - } - syslog(LOG_DEBUG, "created new directory %s", dname); - *slashloc = saveslash; - slashloc++; - } - } - free(dname); - } - - c->log_file = fopen(c->log_file_name, "a"); - if (c->log_file == NULL) - { - if (c->log_file_err) - { - syslog(LOG_CRIT, "logging system can not open %s: %s" - , c->log_file_name, strerror(errno)); - c->log_file_err = TRUE; - } - return; - } - - /* look for a connection to close! */ - while (perpeer_count >= MAX_PEERLOG_COUNT) - { - /* can not be NULL because perpeer_count > 0 */ - passert(TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list); - - perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer)); - } - - /* insert this into the list */ - TAILQ_INSERT_HEAD(&perpeer_list, c, log_link); - passert(c->log_file != NULL); - perpeer_count++; -} - -/* log a line to cur_connection's log */ -static void -peerlog(const char *prefix, const char *m) -{ - if (cur_connection == NULL) - { - /* we can not log it in this case. Oh well. */ - return; - } - - if (cur_connection->log_file == NULL) - { - open_peerlog(cur_connection); - } - - /* despite our attempts above, we may not be able to open the file. */ - if (cur_connection->log_file != NULL) - { - char datebuf[32]; - time_t n; - struct tm *t; - - time(&n); - t = localtime(&n); - - strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %T", t); - fprintf(cur_connection->log_file, "%s %s%s\n", datebuf, prefix, m); - - /* now move it to the front of the list */ - TAILQ_REMOVE(&perpeer_list, cur_connection, log_link); - TAILQ_INSERT_HEAD(&perpeer_list, cur_connection, log_link); - } -} - -void -plog(const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "%s\n", m); - if (log_to_syslog) - syslog(LOG_WARNING, "%s", m); - if (log_to_perpeer) - peerlog("", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_WARN, "pluto", "%s\n", m); -#endif - - whack_log(RC_LOG, "~%s", m); -} - -void -loglog(int mess_no, const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "%s\n", m); - if (log_to_syslog) - syslog(LOG_WARNING, "%s", m); - if (log_to_perpeer) - peerlog("", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_WARN, "pluto", "%s\n", m); -#endif - - whack_log(mess_no, "~%s", m); -} - -void -log_errno_routine(int e, const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e)); - if (log_to_syslog) - syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e)); - if (log_to_perpeer) - peerlog(strerror(e), m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_ERROR, "pluto", "ERROR: %s. Errno %d: %s\n", - m, e, strerror(e)); -#endif - - whack_log(RC_LOG_SERIOUS - , "~ERROR: %s. Errno %d: %s", m, e, strerror(e)); -} - -void -exit_log(const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "FATAL ERROR: %s\n", m); - if (log_to_syslog) - syslog(LOG_ERR, "FATAL ERROR: %s", m); - if (log_to_perpeer) - peerlog("FATAL ERROR: ", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_ERROR, "pluto", "FATAL ERROR: %s\n", m); -#endif - - whack_log(RC_LOG_SERIOUS, "~FATAL ERROR: %s", m); - - exit_pluto(1); -} - -void -exit_log_errno_routine(int e, const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e)); - if (log_to_syslog) - syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e)); - if (log_to_perpeer) - peerlog(strerror(e), m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_ERROR, "pluto", "FATAL ERROR: %s. " - "Errno %d: %s\n", m, e, strerror(e)); -#endif - - whack_log(RC_LOG_SERIOUS - , "~FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e)); - - exit_pluto(1); -} - -/* emit message to whack. - * form is "ddd statename text" where - * - ddd is a decimal status code (RC_*) as described in whack.h - * - text is a human-readable annotation - */ -#ifdef DEBUG -static volatile sig_atomic_t dying_breath = FALSE; -#endif - -void -whack_log(int mess_no, const char *message, ...) -{ - int wfd = whack_log_fd != NULL_FD ? whack_log_fd - : cur_state != NULL ? cur_state->st_whack_sock - : NULL_FD; - - if (wfd != NULL_FD -#ifdef DEBUG - || dying_breath -#endif - ) - { - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - int prelen = snprintf(m, sizeof(m), "%03d ", mess_no); - - passert(prelen >= 0); - - va_start(args, message); - fmt_log(m+prelen, sizeof(m)-prelen, message, args); - va_end(args); - -#if DEBUG - if (dying_breath) - { - /* status output copied to log */ - if (log_to_stderr) - fprintf(stderr, "%s\n", m + prelen); - if (log_to_syslog) - syslog(LOG_WARNING, "%s", m + prelen); - if (log_to_perpeer) - peerlog("", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_WARN, "pluto", "%s\n", m + prelen); -#endif - } -#endif - - if (wfd != NULL_FD) - { - /* write to whack socket, but suppress possible SIGPIPE */ - size_t len = strlen(m); -#ifdef MSG_NOSIGNAL /* depends on version of glibc??? */ - m[len] = '\n'; /* don't need NUL, do need NL */ - (void) send(wfd, m, len + 1, MSG_NOSIGNAL); -#else /* !MSG_NOSIGNAL */ - int r; - struct sigaction act - , oldact; - - m[len] = '\n'; /* don't need NUL, do need NL */ - act.sa_handler = SIG_IGN; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; /* no nothing */ - r = sigaction(SIGPIPE, &act, &oldact); - passert(r == 0); - - (void) write(wfd, m, len + 1); - - r = sigaction(SIGPIPE, &oldact, NULL); - passert(r == 0); -#endif /* !MSG_NOSIGNAL */ - } - } -} - -/* Build up a diagnostic in a static buffer. - * Although this would be a generally useful function, it is very - * hard to come up with a discipline that prevents different uses - * from interfering. It is intended that by limiting it to building - * diagnostics, we will avoid this problem. - * Juggling is performed to allow an argument to be a previous - * result: the new string may safely depend on the old one. This - * restriction is not checked in any way: violators will produce - * confusing results (without crashing!). - */ -char diag_space[sizeof(diag_space)]; - -err_t -builddiag(const char *fmt, ...) -{ - static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */ - char t[sizeof(diag_space)]; /* build result here first */ - va_list args; - - va_start(args, fmt); - t[0] = '\0'; /* in case nothing terminates string */ - vsnprintf(t, sizeof(t), fmt, args); - va_end(args); - strcpy(diag_space, t); - return diag_space; -} - -/* Debugging message support */ - -#ifdef DEBUG - -void -switch_fail(int n, const char *file_str, unsigned long line_no) -{ - char buf[30]; - - snprintf(buf, sizeof(buf), "case %d unexpected", n); - passert_fail(buf, file_str, line_no); -} - -void -passert_fail(const char *pred_str, const char *file_str, unsigned long line_no) -{ - /* we will get a possibly unplanned prefix. Hope it works */ - loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str); - if (!dying_breath) - { - dying_breath = TRUE; - show_status(TRUE, NULL); - } - abort(); /* exiting correctly doesn't always work */ -} - -void -pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no) -{ - /* we will get a possibly unplanned prefix. Hope it works */ - loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str); -} - -lset_t - base_debugging = DBG_NONE, /* default to reporting nothing */ - cur_debugging = DBG_NONE; - -void -extra_debugging(const connection_t *c) -{ - if(c == NULL) - { - reset_debugging(); - return; - } - - if (c!= NULL && c->extra_debugging != 0) - { - plog("enabling for connection: %s" - , bitnamesof(debug_bit_names, c->extra_debugging & ~cur_debugging)); - cur_debugging |= c->extra_debugging; - } -} - -/* log a debugging message (prefixed by "| ") */ - -void -DBG_log(const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - vsnprintf(m, sizeof(m), message, args); - va_end(args); - - (void)sanitize(m, sizeof(m)); - - if (log_to_stderr) - fprintf(stderr, "| %s\n", m); - if (log_to_syslog) - syslog(LOG_DEBUG, "| %s", m); - if (log_to_perpeer) - peerlog("| ", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_DEBUG, "pluto", "| %s\n", m); -#endif -} - -/* dump raw bytes in hex to stderr (for lack of any better destination) */ - -void -DBG_dump(const char *label, const void *p, size_t len) -{ -# define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */ -# define DUMP_WIDTH (4 * (1 + 4 * 3) + 1) - char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH]; - char *bp; - const unsigned char *cp = p; - - bp = buf; - - if (label != NULL && label[0] != '\0') - { - /* Handle the label. Care must be taken to avoid buffer overrun. */ - size_t llen = strlen(label); - - if (llen + 1 > sizeof(buf)) - { - DBG_log("%s", label); - } - else - { - strcpy(buf, label); - if (buf[llen-1] == '\n') - { - buf[llen-1] = '\0'; /* get rid of newline */ - DBG_log("%s", buf); - } - else if (llen < DUMP_LABEL_WIDTH) - { - bp = buf + llen; - } - else - { - DBG_log("%s", buf); - } - } - } - - do { - int i, j; - - for (i = 0; len!=0 && i!=4; i++) - { - *bp++ = ' '; - for (j = 0; len!=0 && j!=4; len--, j++) - { - static const char hexdig[] = "0123456789abcdef"; - - *bp++ = ' '; - *bp++ = hexdig[(*cp >> 4) & 0xF]; - *bp++ = hexdig[*cp & 0xF]; - cp++; - } - } - *bp = '\0'; - DBG_log("%s", buf); - bp = buf; - } while (len != 0); -# undef DUMP_LABEL_WIDTH -# undef DUMP_WIDTH -} - -#endif /* DEBUG */ - -static void show_loaded_plugins() -{ - whack_log(RC_COMMENT, "loaded plugins: %s", - lib->plugins->loaded_plugins(lib->plugins)); -} - -void show_status(bool all, const char *name) -{ - if (all) - { - whack_log(RC_COMMENT, "Status of IKEv1 pluto daemon (strongSwan "VERSION"):"); - show_ifaces_status(); - show_myid_status(); - show_loaded_plugins(); - show_debug_status(); - show_pools(name); - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ - } - show_connections_status(all, name); - show_states_status(all, name); -} - -/* ip_str: a simple to use variant of addrtot. - * It stores its result in a static buffer. - * This means that newer calls overwrite the storage of older calls. - * Note: this is not used in any of the logging functions, so their - * callers may use it. - */ -const char * -ip_str(const ip_address *src) -{ - static char buf[ADDRTOT_BUF]; - - addrtot(src, 0, buf, sizeof(buf)); - return buf; -} - -/* - * a routine that attempts to schedule itself daily. - * - */ - -void -daily_log_reset(void) -{ - /* now perform actions */ - logged_txt_warning = FALSE; - - logged_myid_fqdn_txt_warning = FALSE; - logged_myid_ip_txt_warning = FALSE; - logged_myid_fqdn_key_warning = FALSE; - logged_myid_ip_key_warning = FALSE; -} - -void -daily_log_event(void) -{ - struct tm lt; - time_t t, interval; - - /* attempt to schedule oneself to midnight, local time - * do this by getting seconds in the day, and delaying - * by 86400 - 3600*hours - 60*minutes - seconds. - */ - time(&t); - localtime_r(&t, <); - interval = 3600 * (24 - lt.tm_hour) - 60 * lt.tm_min - lt.tm_sec; - - event_schedule(EVENT_LOG_DAILY, interval, NULL); - daily_log_reset(); -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/log.h b/src/pluto/log.h deleted file mode 100644 index 52c01bbd4..000000000 --- a/src/pluto/log.h +++ /dev/null @@ -1,234 +0,0 @@ -/* logging definitions - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <freeswan.h> - -#define LOG_WIDTH 1024 /* roof of number of chars in log line */ - -#ifndef PERPEERLOGDIR -#define PERPEERLOGDIR "/var/log/pluto/peer" -#endif - -/* our versions of assert: log result */ - -#ifdef DEBUG - -extern void passert_fail(const char *pred_str - , const char *file_str, unsigned long line_no) NEVER_RETURNS; - -extern void pexpect_log(const char *pred_str - , const char *file_str, unsigned long line_no); - -# define impossible() passert_fail("impossible", __FILE__, __LINE__) - -extern void switch_fail(int n - , const char *file_str, unsigned long line_no) NEVER_RETURNS; - -# define bad_case(n) switch_fail((int) n, __FILE__, __LINE__) - -# define passert(pred) { \ - if (!(pred)) \ - passert_fail(#pred, __FILE__, __LINE__); \ - } - -# define pexpect(pred) { \ - if (!(pred)) \ - pexpect_log(#pred, __FILE__, __LINE__); \ - } - -/* assert that an err_t is NULL; evaluate exactly once */ -# define happy(x) { \ - err_t ugh = x; \ - if (ugh != NULL) \ - passert_fail(ugh, __FILE__, __LINE__); \ - } - -#else /*!DEBUG*/ - -# define impossible() abort() -# define bad_case(n) abort() -# define passert(pred) { } /* do nothing */ -# define happy(x) { (void) x; } /* evaluate non-judgementally */ - -#endif /*!DEBUG*/ - - -extern bool - log_to_stderr, /* should log go to stderr? */ - log_to_syslog, /* should log go to syslog? */ - log_to_perpeer; /* should log go to per-IP file? */ - -extern const char *base_perpeer_logdir; - -/* maximum number of files to keep open for per-peer log files */ -#define MAX_PEERLOG_COUNT 16 - -/* Context for logging. - * - * Global variables: must be carefully adjusted at transaction boundaries! - * All are to be left in RESET condition and will be checked. - * There are several pairs of routines to set and reset them. - * If the context provides a whack file descriptor, messages - * should be copied to it -- see whack_log() - */ -extern int whack_log_fd; /* only set during whack_handle() */ -extern struct state *cur_state; /* current state, for diagnostics */ -extern struct connection *cur_connection; /* current connection, for diagnostics */ -extern const ip_address *cur_from; /* source of current current message */ -extern u_int16_t cur_from_port; /* host order */ - -#ifdef DEBUG - - extern lset_t cur_debugging; /* current debugging level */ - - extern void extra_debugging(const struct connection *c); - -# define reset_debugging() { cur_debugging = base_debugging; } - -# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \ - && cur_state == NULL \ - && cur_connection == NULL \ - && cur_from == NULL \ - && cur_debugging == base_debugging) - -#else /*!DEBUG*/ - -# define extra_debugging(c) { } - -# define reset_debugging() { } - -# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \ - && cur_state == NULL \ - && cur_connection == NULL \ - && cur_from == NULL) - -#endif /*!DEBUG*/ - -#define reset_globals() { \ - whack_log_fd = NULL_FD; \ - cur_state = NULL; \ - cur_from = NULL; \ - reset_cur_connection(); \ - } - - -#define set_cur_connection(c) { \ - cur_connection = (c); \ - extra_debugging(c); \ - } - -#define reset_cur_connection() { \ - cur_connection = NULL; \ - reset_debugging(); \ - } - - -#define set_cur_state(s) { \ - cur_state = (s); \ - extra_debugging((s)->st_connection); \ - } - -#define reset_cur_state() { \ - cur_state = NULL; \ - reset_debugging(); \ - } - -extern void init_log(const char *program); -extern void close_log(void); -extern void plog(const char *message, ...) PRINTF_LIKE(1); -extern void exit_log(const char *message, ...) PRINTF_LIKE(1) NEVER_RETURNS; - -/* close of all per-peer logging */ -extern void close_peerlog(void); - -/* free all per-peer log resources */ -extern void perpeer_logfree(struct connection *c); - - - -/* the following routines do a dance to capture errno before it is changed - * A call must doubly parenthesize the argument list (no varargs macros). - * The first argument must be "e", the local variable that captures errno. - */ -#define log_errno(a) { int e = errno; log_errno_routine a; } -extern void log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2); -#define exit_log_errno(a) { int e = errno; exit_log_errno_routine a; } -extern void exit_log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2) NEVER_RETURNS NEVER_RETURNS; - -extern void whack_log(int mess_no, const char *message, ...) PRINTF_LIKE(2); - -/* Log to both main log and whack log - * Much like log, actually, except for specifying mess_no. - */ -extern void loglog(int mess_no, const char *message, ...) PRINTF_LIKE(2); - -/* show status, usually on whack log */ -extern void show_status(bool all, const char *name); - -/* Build up a diagnostic in a static buffer. - * Although this would be a generally useful function, it is very - * hard to come up with a discipline that prevents different uses - * from interfering. It is intended that by limiting it to building - * diagnostics, we will avoid this problem. - * Juggling is performed to allow an argument to be a previous - * result: the new string may safely depend on the old one. This - * restriction is not checked in any way: violators will produce - * confusing results (without crashing!). - */ -extern char diag_space[LOG_WIDTH]; /* output buffer, but can be occupied at call */ -extern err_t builddiag(const char *fmt, ...) PRINTF_LIKE(1); - -#ifdef DEBUG - -extern lset_t base_debugging; /* bits selecting what to report */ - -#define DBGP(cond) (cur_debugging & (cond)) -#define DBG(cond, action) { if (DBGP(cond)) { action ; } } - -extern void DBG_log(const char *message, ...) PRINTF_LIKE(1); -extern void DBG_dump(const char *label, const void *p, size_t len); -#define DBG_dump_chunk(label, ch) DBG_dump(label, (ch).ptr, (ch).len) - -#else /*!DEBUG*/ - -#define DBG(cond, action) { } /* do nothing */ - -#endif /*!DEBUG*/ - -#define DBG_cond_dump(cond, label, p, len) DBG(cond, DBG_dump(label, p, len)) -#define DBG_cond_dump_chunk(cond, label, ch) DBG(cond, DBG_dump_chunk(label, ch)) - - -/* ip_str: a simple to use variant of addrtot. - * It stores its result in a static buffer. - * This means that newer calls overwrite the storage of older calls. - * Note: this is not used in any of the logging functions, so their - * callers may use it. - */ -extern const char *ip_str(const ip_address *src); - -/* - * call this routine to reset daily items. - */ -extern void daily_log_reset(void); -extern void daily_log_event(void); - -/* - * some events are to be logged only occasionally. - */ -extern bool logged_txt_warning; -extern bool logged_myid_ip_txt_warning; -extern bool logged_myid_ip_key_warning; -extern bool logged_myid_fqdn_txt_warning; -extern bool logged_myid_fqdn_key_warning; diff --git a/src/pluto/modecfg.c b/src/pluto/modecfg.c deleted file mode 100644 index 8298ea601..000000000 --- a/src/pluto/modecfg.c +++ /dev/null @@ -1,1263 +0,0 @@ -/* Mode config related functions - * Copyright (C) 2001-2002 Colubris Networks - * Copyright (C) 2003 Sean Mathews - Nu Tech Software Solutions, inc. - * Copyright (C) 2003-2004 Xelerance Corporation - * Copyright (C) 2006-2010 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * This code originally written by Colubris Networks, Inc. - * Extraction of patch and porting to 1.99 codebases by Xelerance Corporation - * Porting to 2.x by Sean Mathews - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <freeswan.h> - -#include <library.h> -#include <hydra.h> -#include <utils/linked_list.h> -#include <crypto/prfs/prf.h> - -#include "constants.h" -#include "defs.h" -#include "state.h" -#include "demux.h" -#include "timer.h" -#include "ipsec_doi.h" -#include "log.h" -#include "crypto.h" -#include "modecfg.h" -#include "whack.h" -#include "pluto.h" - -#define MAX_XAUTH_TRIES 3 - -#define DEFAULT_UNITY_BANNER "Welcome to strongSwan - the Linux VPN Solution!\n" - -/** - * Creates a modecfg_attribute_t object - */ -static modecfg_attribute_t *modecfg_attribute_create(configuration_attribute_type_t type, - chunk_t value) -{ - modecfg_attribute_t *this; - - this = malloc_thing(modecfg_attribute_t); - this->type = ((u_int16_t)type) & 0x7FFF; - this->is_tv = FALSE; - this->value = chunk_clone(value); - this->handler = NULL; - - return this; -} - -/** - * Creates a modecfg_attribute_t object coded in TV format - */ -static modecfg_attribute_t *modecfg_attribute_create_tv(configuration_attribute_type_t type, - size_t value) -{ - modecfg_attribute_t *this; - - this = modecfg_attribute_create(type, chunk_empty); - this->value.len = value; - this->is_tv = TRUE; - - return this; -} - -/** - * Destroys a modecfg_attribute_t object - */ -void modecfg_attribute_destroy(modecfg_attribute_t *this) -{ - free(this->value.ptr); - free(this); -} - -/** - * Get attributes to be sent to client - */ -static void get_attributes(connection_t *c, linked_list_t *ca_list) -{ - configuration_attribute_type_t type; - identification_t *client_id; - modecfg_attribute_t *ca; - enumerator_t *enumerator; - chunk_t value; - host_t *vip = NULL, *requested_vip = NULL; - bool want_unity_banner = FALSE; - int family; - -#ifdef CISCO_QUIRKS - /* always send banner in ModeCfg push mode */ - if (ca_list->get_count(ca_list) == 0) - { - want_unity_banner = TRUE; - } -#endif - - /* scan list of requested attributes in ModeCfg pull mode */ - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP6_ADDRESS: - { - int family; - - family = (ca->type == INTERNAL_IP4_ADDRESS) ? AF_INET : AF_INET6; - DESTROY_IF(requested_vip); - requested_vip = (ca->value.len) ? - host_create_from_chunk(family, ca->value, 0) : - host_create_any(family); - plog("peer requested virtual IP %H", requested_vip); - break; - } -#ifdef CISCO_QUIRKS - case UNITY_BANNER: - want_unity_banner = TRUE; - break; -#endif - default: - break; - } - modecfg_attribute_destroy(ca); - } - - if (requested_vip == NULL) - { - requested_vip = host_create_any(AF_INET); - } - - client_id = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id; - - /* if no virtual IP has been assigned yet - acquire one */ - if (c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) - { - if (c->spd.that.pool) - { - vip = hydra->attributes->acquire_address(hydra->attributes, - c->spd.that.pool, client_id, requested_vip); - if (vip) - { - c->spd.that.host_srcip->destroy(c->spd.that.host_srcip); - c->spd.that.host_srcip = vip; - } - } - else - { - plog("no virtual IP found"); - } - } - - requested_vip->destroy(requested_vip); - - /* if we have a virtual IP address - send it */ - if (!c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) - { - vip = c->spd.that.host_srcip; - plog("assigning virtual IP %H to peer", vip); - family = vip->get_family(vip); - ca = modecfg_attribute_create((family == AF_INET) ? - INTERNAL_IP4_ADDRESS : - INTERNAL_IP6_ADDRESS, - vip->get_address(vip)); - ca_list->insert_last(ca_list, ca); - - /* set the remote client subnet to virtual IP */ - c->spd.that.client.addr = *(ip_address*)vip->get_sockaddr(vip); - c->spd.that.client.maskbits = (family == AF_INET) ? 32 : 128; - c->spd.that.has_client = TRUE; - } - - /* assign attributes from registered providers */ - enumerator = hydra->attributes->create_responder_enumerator(hydra->attributes, - c->spd.that.pool, client_id, vip); - while (enumerator->enumerate(enumerator, &type, &value)) - { - ca = modecfg_attribute_create(type, value); - ca_list->insert_last(ca_list, ca); - if (type == UNITY_BANNER) - { - want_unity_banner = FALSE; - } - } - enumerator->destroy(enumerator); - - if (want_unity_banner) - { - ca = modecfg_attribute_create(UNITY_BANNER, - chunk_create(DEFAULT_UNITY_BANNER, - strlen(DEFAULT_UNITY_BANNER))); - ca_list->insert_last(ca_list, ca); - } -} - -/** - * Set srcip and client subnet to internal IP address - */ -static bool set_attributes(connection_t *c, linked_list_t *ca_list) -{ - host_t *vip, *srcip; - modecfg_attribute_t *ca, *ca_handler; - enumerator_t *enumerator; - bool vip_set = FALSE; - - enumerator = ca_list->create_enumerator(ca_list); - while (enumerator->enumerate(enumerator, &ca)) - { - int family = AF_INET6; - attribute_handler_t *handler = NULL; - enumerator_t *e; - - switch (ca->type) - { - case INTERNAL_IP4_ADDRESS: - family = AF_INET; - /* fall */ - case INTERNAL_IP6_ADDRESS: - if (ca->value.len == 0) - { - vip = host_create_any(family); - } - else - { - /* skip prefix byte in IPv6 payload*/ - if (family == AF_INET6) - { - ca->value.len = 16; - } - vip = host_create_from_chunk(family, ca->value, 0); - } - if (vip) - { - srcip = c->spd.this.host_srcip; - - if (srcip->is_anyaddr(srcip) || srcip->equals(srcip, vip)) - { - plog("setting virtual IP source address to %H", vip); - } - else - { - plog("replacing virtual IP source address %H by %H", - srcip, vip); - } - srcip->destroy(srcip); - c->spd.this.host_srcip = vip; - - /* setting client subnet to vip/32 */ - addrtosubnet((ip_address*)vip->get_sockaddr(vip), - &c->spd.this.client); - setportof(0, &c->spd.this.client.addr); - c->spd.this.has_client = TRUE; - - vip_set = TRUE; - } - continue; - case APPLICATION_VERSION: -#ifdef CISCO_QUIRKS - case UNITY_BANNER: -#endif - if (ca->value.len > 0) - { - DBG(DBG_PARSING | DBG_CONTROLMORE, - DBG_log(" '%.*s'", ca->value.len, ca->value.ptr) - ) - } - break; - default: - break; - } - - /* find the first handler which requested this attribute */ - e = c->requested->create_enumerator(c->requested); - while (e->enumerate(e, &ca_handler)) - { - if (ca_handler->type == ca->type) - { - handler = ca_handler->handler; - break; - } - } - e->destroy(e); - - /* and pass it to the handle function */ - handler = hydra->attributes->handle(hydra->attributes, - c->spd.that.id, handler, ca->type, ca->value); - if (handler) - { - ca_handler = modecfg_attribute_create(ca->type, ca->value); - ca_handler->handler = handler; - - if (c->attributes == NULL) - { - c->attributes = linked_list_create(); - } - c->attributes->insert_last(c->attributes, ca_handler); - } - } - enumerator->destroy(enumerator); - c->requested->destroy_function(c->requested, (void*)modecfg_attribute_destroy); - c->requested = NULL; - return vip_set; -} - -/** - * Register configuration attribute handlers - */ -static void register_attribute_handlers(connection_t *c) -{ - configuration_attribute_type_t type; - modecfg_attribute_t *ca; - chunk_t value; - attribute_handler_t *handler; - enumerator_t *enumerator; - - /* add configuration attributes requested by handlers */ - if (c->requested == NULL) - { - c->requested = linked_list_create(); - } - enumerator = hydra->attributes->create_initiator_enumerator( - hydra->attributes,c->spd.that.id, c->spd.this.host_srcip); - while (enumerator->enumerate(enumerator, &handler, &type, &value)) - { - ca = modecfg_attribute_create(type, value); - ca->handler = handler; - c->requested->insert_last(c->requested, ca); - } - enumerator->destroy(enumerator); -} - -/** - * Compute HASH of Mode Config. - */ -static size_t modecfg_hash(u_char *dest, u_char *start, u_char *roof, - const struct state *st) -{ - chunk_t msgid_chunk = chunk_from_thing(st->st_msgid); - chunk_t msg_chunk = { start, roof - start }; - size_t prf_block_size; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, dest); - prf_block_size = prf->get_block_size(prf); - prf->destroy(prf); - - DBG(DBG_CRYPT, - DBG_log("ModeCfg HASH computed:"); - DBG_dump("", dest, prf_block_size) - ) - return prf_block_size; -} - - -/** - * Generate an IKE message containing ModeCfg information (eg: IP, DNS, WINS) - */ -static stf_status modecfg_build_msg(struct state *st, pb_stream *rbody, - u_int16_t msg_type, linked_list_t *ca_list, - u_int16_t ap_id) -{ - u_char *r_hash_start, *r_hashval; - struct isakmp_mode_attr attrh; - struct isakmp_attribute attr; - pb_stream strattr,attrval; - enumerator_t *enumerator; - modecfg_attribute_t *ca; - - START_HASH_PAYLOAD(*rbody, ISAKMP_NEXT_ATTR); - - attrh.isama_np = ISAKMP_NEXT_NONE; - attrh.isama_type = msg_type; - attrh.isama_identifier = ap_id; - - if (!out_struct(&attrh, &isakmp_attr_desc, rbody, &strattr)) - { - return STF_INTERNAL_ERROR; - } - - enumerator = ca_list->create_enumerator(ca_list); - while (enumerator->enumerate(enumerator, &ca)) - { - DBG(DBG_CONTROLMORE, - DBG_log("building %N attribute", configuration_attribute_type_names, ca->type) - ) - if (ca->is_tv) - { - attr.isaat_af_type = ca->type | ISAKMP_ATTR_AF_TV; - attr.isaat_lv = ca->value.len; - out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); - } - else - { - char buf[BUF_LEN]; - - attr.isaat_af_type = ca->type | ISAKMP_ATTR_AF_TLV; - out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); - snprintf(buf, BUF_LEN, "%N", configuration_attribute_type_names, ca->type); - out_raw(ca->value.ptr, ca->value.len, &attrval, buf); - } - close_output_pbs(&attrval); - } - enumerator->destroy(enumerator); - close_output_pbs(&strattr); - - modecfg_hash(r_hashval, r_hash_start, rbody->cur, st); - close_message(rbody); - encrypt_message(rbody, st); - return STF_OK; -} - -/** - * Send ModeCfg message - */ -static stf_status modecfg_send_msg(struct state *st, int isama_type, - linked_list_t *ca_list) -{ - pb_stream msg; - pb_stream rbody; - char buf[BUF_LEN]; - - /* set up attr */ - init_pbs(&msg, buf, sizeof(buf), "ModeCfg msg buffer"); - - /* this is the beginning of a new exchange */ - st->st_msgid = generate_msgid(st); - init_phase2_iv(st, &st->st_msgid); - - /* HDR out */ - { - struct isakmp_hdr hdr; - - zero(&hdr); /* default to 0 */ - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - hdr.isa_msgid = st->st_msgid; - - if (!out_struct(&hdr, &isakmp_hdr_desc, &msg, &rbody)) - { - return STF_INTERNAL_ERROR; - } - } - - /* ATTR out with isama_id of 0 */ - modecfg_build_msg(st, &rbody, isama_type, ca_list, 0); - - free(st->st_tpacket.ptr); - st->st_tpacket = chunk_create(msg.start, pbs_offset(&msg)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - /* Transmit */ - send_packet(st, "ModeCfg msg"); - - if (st->st_event->ev_type != EVENT_RETRANSMIT) - { - delete_event(st); - event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); - } - return STF_OK; -} - -/** - * Parse a ModeCfg attribute payload - */ -static stf_status modecfg_parse_attributes(pb_stream *attrs, linked_list_t *ca_list) -{ - struct isakmp_attribute attr; - pb_stream strattr; - u_int16_t attr_type; - u_int16_t attr_len; - chunk_t attr_chunk; - modecfg_attribute_t *ca; - - while (pbs_left(attrs) >= sizeof(struct isakmp_attribute)) - { - if (!in_struct(&attr, &isakmp_modecfg_attribute_desc, attrs, &strattr)) - { - return STF_FAIL; - } - attr_type = attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK; - attr_len = attr.isaat_lv; - DBG(DBG_CONTROLMORE, - DBG_log("processing %N attribute", - configuration_attribute_type_names, attr_type) - ) - - switch (attr_type) - { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP4_NETMASK: - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_NBNS: - case INTERNAL_ADDRESS_EXPIRY: - case INTERNAL_IP4_DHCP: - if (attr_len != 4 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP4_SUBNET: - if (attr_len != 8 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP6_NETMASK: - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: - case INTERNAL_IP6_DHCP: - if (attr_len != 16 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP6_ADDRESS: - if (attr_len != 17 && attr_len != 16 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP6_SUBNET: - if (attr_len != 17 && attr_len != 0) - { - goto error; - } - break; - case SUPPORTED_ATTRIBUTES: - if (attr_len % 2) - { - goto error; - } - break; - case APPLICATION_VERSION: - break; - /* XAUTH attributes */ - case XAUTH_TYPE: - case XAUTH_STATUS: - case XAUTH_USER_NAME: - case XAUTH_USER_PASSWORD: - case XAUTH_PASSCODE: - case XAUTH_MESSAGE: - case XAUTH_CHALLENGE: - case XAUTH_DOMAIN: - case XAUTH_NEXT_PIN: - case XAUTH_ANSWER: - break; - /* Microsoft attributes */ - case INTERNAL_IP4_SERVER: - case INTERNAL_IP6_SERVER: - break; - /* Cisco Unity attributes */ - case UNITY_BANNER: - case UNITY_SAVE_PASSWD: - case UNITY_DEF_DOMAIN: - case UNITY_SPLITDNS_NAME: - case UNITY_SPLIT_INCLUDE: - case UNITY_NATT_PORT: - case UNITY_LOCAL_LAN: - case UNITY_PFS: - case UNITY_FW_TYPE: - case UNITY_BACKUP_SERVERS: - case UNITY_DDNS_HOSTNAME: - break; - default: - plog("unknown attribute type (%u)", attr_type); - continue; - } - - /* add attribute */ - if (attr.isaat_af_type & ISAKMP_ATTR_AF_TV) - { - ca = modecfg_attribute_create_tv(attr_type, attr_len); - } - else - { - attr_chunk = chunk_create(strattr.cur, attr_len); - ca = modecfg_attribute_create(attr_type, attr_chunk); - } - ca_list->insert_last(ca_list, ca); - } - return STF_OK; - -error: - plog("%N attribute has invalid size of %u octets", - configuration_attribute_type_names, attr_type, attr_len); - return STF_FAIL; -} - -/** - * Parse a ModeCfg message - */ -static stf_status modecfg_parse_msg(struct msg_digest *md, int isama_type, - u_int16_t *isama_id, linked_list_t *ca_list) -{ - modecfg_attribute_t *ca; - struct state *const st = md->st; - struct payload_digest *p; - stf_status stat; - - st->st_msgid = md->hdr.isa_msgid; - - CHECK_QUICK_HASH(md, modecfg_hash(hash_val, hash_pbs->roof, - md->message_pbs.roof, st), "MODECFG-HASH", "ISAKMP_CFG_MSG"); - - /* process the ModeCfg payloads received */ - for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next) - { - if (p->payload.attribute.isama_type == isama_type) - { - *isama_id = p->payload.attribute.isama_identifier; - - stat = modecfg_parse_attributes(&p->pbs, ca_list); - if (stat == STF_OK) - { - /* return with a valid set of attributes */ - return STF_OK; - } - } - else - { - plog("expected %s, got %s instead (ignored)" - , enum_name(&attr_msg_type_names, isama_type) - , enum_name(&attr_msg_type_names, p->payload.attribute.isama_type)); - - stat = modecfg_parse_attributes(&p->pbs, ca_list); - } - - /* abort if a parsing error occurred */ - if (stat != STF_OK) - { - ca_list->destroy_function(ca_list, (void*)modecfg_attribute_destroy); - return stat; - } - - /* discard the parsed attributes and look for another payload */ - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) {} - } - return STF_IGNORE; -} - -/** - * Used in ModeCfg pull mode on the client (initiator) - * called in demux.c - * client -> CFG_REQUEST - * STF_OK transitions to STATE_MODE_CFG_I1 - */ -stf_status modecfg_send_request(struct state *st) -{ - connection_t *c = st->st_connection; - stf_status stat; - modecfg_attribute_t *ca; - enumerator_t *enumerator; - int family; - chunk_t value; - host_t *vip; - linked_list_t *ca_list = linked_list_create(); - - vip = c->spd.this.host_srcip; - value = vip->is_anyaddr(vip) ? chunk_empty : vip->get_address(vip); - family = vip->get_family(vip); - ca = modecfg_attribute_create((family == AF_INET) ? - INTERNAL_IP4_ADDRESS : INTERNAL_IP6_ADDRESS, - value); - ca_list->insert_last(ca_list, ca); - - register_attribute_handlers(c); - enumerator = c->requested->create_enumerator(c->requested); - while (enumerator->enumerate(enumerator, &ca)) - { - ca = modecfg_attribute_create(ca->type, chunk_empty); - ca_list->insert_last(ca_list, ca); - } - enumerator->destroy(enumerator); - - plog("sending ModeCfg request"); - - st->st_state = STATE_MODE_CFG_I1; - stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat == STF_OK) - { - st->st_modecfg.started = TRUE; - } - return stat; -} - -/** - * Used in ModeCfg pull mode on the server (responder) - * called in demux.c from STATE_MODE_CFG_R0 - * server <- CFG_REQUEST - * server -> CFG_REPLY - * STF_OK transitions to STATE_MODE_CFG_R0 - */ -stf_status modecfg_inR0(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat, stat_build; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing ModeCfg request"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - - /* build the CFG_REPLY */ - get_attributes(st->st_connection, ca_list); - - plog("sending ModeCfg reply"); - - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_REPLY, - ca_list, isama_id); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - - if (stat_build != STF_OK) - { - return stat_build; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * Used in ModeCfg pull mode on the client (initiator) - * called in demux.c from STATE_MODE_CFG_I1 - * client <- CFG_REPLY - * STF_OK transitions to STATE_MODE_CFG_I2 - */ -stf_status modecfg_inI1(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing ModeCfg reply"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - st->st_modecfg.vars_set = set_attributes(st->st_connection, ca_list); - st->st_msgid = 0; - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - return STF_OK; -} - -/** - * Used in ModeCfg push mode on the server (responder) - * called in demux.c - * server -> CFG_SET - * STF_OK transitions to STATE_MODE_CFG_R3 - */ -stf_status modecfg_send_set(struct state *st) -{ - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - - plog("sending ModeCfg set"); - - get_attributes(st->st_connection, ca_list); - st->st_state = STATE_MODE_CFG_R3; - stat = modecfg_send_msg(st, ISAKMP_CFG_SET, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat == STF_OK) - { - st->st_modecfg.started = TRUE; - } - return stat; -} - -/** - * Used in ModeCfg push mode on the client (initiator) - * called in demux.c from STATE_MODE_CFG_I0 - * client <- CFG_SET - * client -> CFG_ACK - * STF_OK transitions to STATE_MODE_CFG_I3 - */ -stf_status modecfg_inI0(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat, stat_build; - modecfg_attribute_t *ca; - linked_list_t *ca_list, *ca_ack_list; - - plog("parsing ModeCfg set"); - - ca_list = linked_list_create(); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - register_attribute_handlers(st->st_connection); - st->st_modecfg.vars_set = set_attributes(st->st_connection, ca_list); - - /* prepare ModeCfg ack which sends zero length attributes */ - ca_ack_list = linked_list_create(); - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_NBNS: - case APPLICATION_VERSION: - case INTERNAL_IP6_ADDRESS: - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: -#ifdef CISCO_QUIRKS - case UNITY_BANNER: -#endif - /* supported attributes */ - ca->value.len = 0; - ca_ack_list->insert_last(ca_ack_list, ca); - break; - default: - /* unsupportd attributes */ - modecfg_attribute_destroy(ca); - } - } - ca_list->destroy(ca_list); - - plog("sending ModeCfg ack"); - - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_ACK, - ca_ack_list, isama_id); - ca_ack_list->destroy_function(ca_ack_list, (void *)modecfg_attribute_destroy); - if (stat_build != STF_OK) - { - return stat_build; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * Used in ModeCfg push mode on the server (responder) - * called in demux.c from STATE_MODE_CFG_R3 - * server <- CFG_ACK - * STF_OK transitions to STATE_MODE_CFG_R4 - */ -stf_status modecfg_inR3(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing ModeCfg ack"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat != STF_OK) - { - return stat; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * Used on the XAUTH server (responder) - * called in demux.c - * server -> CFG_REQUEST - * STF_OK transitions to STATE_XAUTH_R1 - */ -stf_status xauth_send_request(struct state *st) -{ - stf_status stat; - modecfg_attribute_t *ca; - linked_list_t *ca_list = linked_list_create(); - - ca = modecfg_attribute_create(XAUTH_USER_NAME, chunk_empty); - ca_list->insert_last(ca_list, ca); - ca = modecfg_attribute_create(XAUTH_USER_PASSWORD, chunk_empty); - ca_list->insert_last(ca_list, ca); - - plog("sending XAUTH request"); - st->st_state = STATE_XAUTH_R1; - stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat == STF_OK) - { - st->st_xauth.started = TRUE; - } - return stat; -} - -/** - * Used on the XAUTH client (initiator) - * called in demux.c from STATE_XAUTH_I0 - * client <- CFG_REQUEST - * client -> CFG_REPLY - * STF_OK transitions to STATE_XAUTH_I1 - */ -stf_status xauth_inI0(struct msg_digest *md) -{ - struct state *const st = md->st; - connection_t *c = st->st_connection; - u_int16_t isama_id; - stf_status stat, stat_build; - modecfg_attribute_t *ca; - bool xauth_user_name_present = FALSE; - bool xauth_user_password_present = FALSE; - bool xauth_type_present = FALSE; - chunk_t xauth_user_name, xauth_user_password; - identification_t *user_id; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH request"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case XAUTH_TYPE: - if (ca->value.len != XAUTH_TYPE_GENERIC) - { - plog("xauth type %s is not supported", - enum_name(&xauth_type_names, ca->value.len)); - stat = STF_FAIL; - } - else - { - xauth_type_present = TRUE; - } - break; - case XAUTH_USER_NAME: - xauth_user_name_present = TRUE; - break; - case XAUTH_USER_PASSWORD: - xauth_user_password_present = TRUE; - break; - case XAUTH_MESSAGE: - if (ca->value.len) - { - DBG(DBG_PARSING | DBG_CONTROLMORE, - DBG_log(" '%.*s'", ca->value.len, ca->value.ptr) - ) - } - break; - default: - break; - } - modecfg_attribute_destroy(ca); - } - - if (!xauth_user_name_present) - { - plog("user name attribute is missing in XAUTH request"); - stat = STF_FAIL; - } - if (!xauth_user_password_present) - { - plog("user password attribute is missing in XAUTH request"); - stat = STF_FAIL; - } - - /* prepare XAUTH reply */ - if (stat == STF_OK) - { - /* get user credentials using a plugin function */ - if (!pluto->xauth->get_secret(pluto->xauth, c, &xauth_user_password)) - { - plog("xauth user credentials not found"); - stat = STF_FAIL; - } - } - if (stat == STF_OK) - { - /* insert xauth type if present */ - if (xauth_type_present) - { - ca = modecfg_attribute_create_tv(XAUTH_TYPE, XAUTH_TYPE_GENERIC); - ca_list->insert_last(ca_list, ca); - } - - /* insert xauth user name */ - user_id = (c->xauth_identity) ? c->xauth_identity : c->spd.this.id; - xauth_user_name = user_id->get_encoding(user_id); - DBG(DBG_CONTROL, - DBG_log("my xauth user name is '%.*s'", xauth_user_name.len, - xauth_user_name.ptr) - ) - ca = modecfg_attribute_create(XAUTH_USER_NAME, xauth_user_name); - ca_list->insert_last(ca_list, ca); - - /* insert xauth user password */ - DBG(DBG_PRIVATE, - DBG_log("my xauth user password is '%.*s'", xauth_user_password.len, - xauth_user_password.ptr) - ) - ca = modecfg_attribute_create(XAUTH_USER_PASSWORD, xauth_user_password); - ca_list->insert_last(ca_list, ca); - chunk_clear(&xauth_user_password); - } - else - { - ca = modecfg_attribute_create_tv(XAUTH_STATUS, XAUTH_STATUS_FAIL); - ca_list->insert_last(ca_list, ca); - } - - plog("sending XAUTH reply"); - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_REPLY, - ca_list, isama_id); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat_build != STF_OK) - { - return stat_build; - } - if (stat == STF_OK) - { - st->st_xauth.started = TRUE; - st->st_msgid = 0; - return STF_OK; - } - else - { - /* send XAUTH reply msg and then delete ISAKMP SA */ - free(st->st_tpacket.ptr); - st->st_tpacket = chunk_create(md->reply.start, pbs_offset(&md->reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - send_packet(st, "XAUTH reply msg"); - delete_state(st); - return STF_IGNORE; - } -} - -/** - * Used on the XAUTH server (responder) - * called in demux.c from STATE_XAUTH_R1 - server <- CFG_REPLY - server -> CFG_SET - STF_OK transitions to STATE_XAUTH_R2 - */ -stf_status xauth_inR1(struct msg_digest *md) -{ - struct state *const st = md->st; - connection_t *c = st->st_connection; - u_int16_t isama_id; - stf_status stat, stat_build; - chunk_t xauth_user_name, xauth_user_password; - int xauth_status = XAUTH_STATUS_OK; - modecfg_attribute_t *ca; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH reply"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - - /* initialize xauth_secret */ - xauth_user_name = chunk_empty; - xauth_user_password = chunk_empty; - - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case XAUTH_STATUS: - xauth_status = ca->value.len; - break; - case XAUTH_USER_NAME: - xauth_user_name = chunk_clone(ca->value); - break; - case XAUTH_USER_PASSWORD: - xauth_user_password = chunk_clone(ca->value); - break; - default: - break; - } - modecfg_attribute_destroy(ca); - } - /* did the client return an XAUTH FAIL status? */ - if (xauth_status == XAUTH_STATUS_FAIL) - { - plog("received FAIL status in XAUTH reply"); - - /* client is not able to do XAUTH, delete ISAKMP SA */ - free(xauth_user_name.ptr); - free(xauth_user_password.ptr); - delete_state(st); - ca_list->destroy(ca_list); - return STF_IGNORE; - } - - /* check XAUTH reply */ - if (xauth_user_name.ptr == NULL) - { - plog("user name attribute is missing in XAUTH reply"); - st->st_xauth.status = FALSE; - } - else if (xauth_user_password.ptr == NULL) - { - plog("user password attribute is missing in XAUTH reply"); - st->st_xauth.status = FALSE; - } - else - { - DBG(DBG_CONTROL, - DBG_log("peer xauth user name is '%.*s'", xauth_user_name.len, - xauth_user_name.ptr) - ) - DESTROY_IF(c->xauth_identity); - c->xauth_identity = identification_create_from_data(xauth_user_name); - - DBG(DBG_PRIVATE, - DBG_log("peer xauth user password is '%.*s'", xauth_user_password.len, - xauth_user_password.ptr) - ) - /* verify the user credentials using a plugin function */ - st->st_xauth.status = pluto->xauth->verify_secret(pluto->xauth, c, - xauth_user_password); - plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); - } - chunk_clear(&xauth_user_name); - chunk_clear(&xauth_user_password); - - plog("sending XAUTH status"); - xauth_status = (st->st_xauth.status) ? XAUTH_STATUS_OK : XAUTH_STATUS_FAIL; - ca = modecfg_attribute_create_tv(XAUTH_STATUS, xauth_status); - ca_list->insert_last(ca_list, ca); - stat_build = modecfg_send_msg(st, ISAKMP_CFG_SET, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat_build != STF_OK) - { - return stat_build; - } - return STF_OK; -} - -/** - * Used on the XAUTH client (initiator) - * called in demux.c from STATE_XAUTH_I1 - * client <- CFG_SET - * client -> CFG_ACK - * STF_OK transitions to STATE_XAUTH_I2 - */ -stf_status xauth_inI1(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat, stat_build; - modecfg_attribute_t *ca; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH status"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, ca_list); - if (stat != STF_OK) - { - /* notification payload - not exactly the right choice, but okay */ - md->note = ISAKMP_ATTRIBUTES_NOT_SUPPORTED; - return stat; - } - - st->st_xauth.status = FALSE; - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - if (ca->type == XAUTH_STATUS) - { - st->st_xauth.status = (ca->value.len == XAUTH_STATUS_OK); - } - modecfg_attribute_destroy(ca); - } - plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); - - plog("sending XAUTH ack"); - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_ACK, ca_list, isama_id); - ca_list->destroy(ca_list); - - if (stat_build != STF_OK) - { - return stat_build; - } - if (st->st_xauth.status) - { - st->st_msgid = 0; - return STF_OK; - } - else - { - /* send XAUTH ack msg and then delete ISAKMP SA */ - free(st->st_tpacket.ptr); - st->st_tpacket = chunk_create(md->reply.start, pbs_offset(&md->reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - send_packet(st, "XAUTH ack msg"); - delete_state(st); - return STF_IGNORE; - } -} - -/** - * Used on the XAUTH server (responder) - * called in demux.c from STATE_XAUTH_R2 - * server <- CFG_ACK - * STF_OK transitions to STATE_XAUTH_R3 - */ -stf_status xauth_inR2(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH ack"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - st->st_msgid = 0; - if (st->st_xauth.status) - { - return STF_OK; - } - else - { - delete_state(st); - return STF_IGNORE; - } - -} diff --git a/src/pluto/modecfg.h b/src/pluto/modecfg.h deleted file mode 100644 index 7adf18682..000000000 --- a/src/pluto/modecfg.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Mode Config related functions - * Copyright (C) 2001-2002 Colubris Networks - * Copyright (C) 2003-2004 Xelerance Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _MODECFG_H -#define _MODECFG_H - -#include <chunk.h> -#include <attributes/attribute_handler.h> - -#include "state.h" -#include "demux.h" - -typedef struct modecfg_attribute_t modecfg_attribute_t; - -/** - * Defines a modecfg_attribute_t object. - */ -struct modecfg_attribute_t { - /** - * Type of the attribute. - */ - u_int16_t type; - - /** - * Attribute is coded as TV - */ - bool is_tv; - - /** - * Attribute value as chunk. - */ - chunk_t value; - - /** - * Attribute handler. - */ - attribute_handler_t *handler; -}; - -/* Destroys a modecfg_attribute_t object */ -extern void modecfg_attribute_destroy(modecfg_attribute_t *this); - -/* ModeConfig pull mode start function */ -extern stf_status modecfg_send_request(struct state *st); - -/* ModeConfig pull mode state transition functions */ -extern stf_status modecfg_inR0(struct msg_digest *md); -extern stf_status modecfg_inI1(struct msg_digest *md); - -/* ModeConfig push mode start function */ -extern stf_status modecfg_send_set(struct state *st); - -/* ModeConfig push mode state transition functions */ -extern stf_status modecfg_inI0(struct msg_digest *md); -extern stf_status modecfg_inR3(struct msg_digest *md); - -/* XAUTH start function */ -extern stf_status xauth_send_request(struct state *st); - -/* XAUTH state transition funcgtions */ -extern stf_status xauth_inI0(struct msg_digest *md); -extern stf_status xauth_inR1(struct msg_digest *md); -extern stf_status xauth_inI1(struct msg_digest *md); -extern stf_status xauth_inR2(struct msg_digest *md); - -#endif /* _MODECFG_H */ diff --git a/src/pluto/myid.c b/src/pluto/myid.c deleted file mode 100644 index c90d14ef8..000000000 --- a/src/pluto/myid.c +++ /dev/null @@ -1,121 +0,0 @@ -/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1) - * Copyright (C) 1999-2001 D. Hugh Redelmeier - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <errno.h> -#include <unistd.h> - -#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says <unistd.h> defines this */ -# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */ -#endif - -#include <utils/identification.h> - -#include <freeswan.h> - -#include "myid.h" -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "connections.h" -#include "packet.h" -#include "whack.h" - -enum myid_state myid_state = MYID_UNKNOWN; - -identification_t *myids[MYID_SPECIFIED+1]; /* %myid */ - -/** - * Fills in myid from environment variable IPSECmyid or defaultrouteaddr - */ -void init_myid(void) -{ - myid_state = MYID_UNKNOWN; - { - enum myid_state s; - - for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++) - { - myids[s] = identification_create_from_string("%any"); - } - } - set_myid(MYID_SPECIFIED, getenv("IPSECmyid")); - set_myid(MYID_IP, getenv("defaultrouteaddr")); - set_myFQDN(); -} - -/** - * Free myid module - */ -void free_myid(void) -{ - enum myid_state s; - - for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++) - { - DESTROY_IF(myids[s]); - } -} - -void set_myid(enum myid_state s, char *idstr) -{ - if (idstr) - { - myids[s]->destroy(myids[s]); - myids[s] = identification_create_from_string(idstr); - if (s == MYID_SPECIFIED) - { - myid_state = MYID_SPECIFIED; - } - } -} - -void set_myFQDN(void) -{ - char FQDN[HOST_NAME_MAX + 1]; - int r = gethostname(FQDN, sizeof(FQDN)); - size_t len; - - if (r != 0) - { - log_errno((e, "gethostname() failed in set_myFQDN")); - } - else - { - FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */ - len = strlen(FQDN); - - if (len > 0 && FQDN[len-1] == '.') - { - /* nuke trailing . */ - FQDN[len-1] = '\0'; - } - if (!strcaseeq(FQDN, "localhost.localdomain")) - { - myids[MYID_HOSTNAME]->destroy(myids[MYID_HOSTNAME]); - myids[MYID_HOSTNAME] = identification_create_from_string(FQDN); - } - } -} - -void show_myid_status(void) -{ - whack_log(RC_COMMENT, "%%myid = '%Y'", myids[myid_state]); -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/myid.h b/src/pluto/myid.h deleted file mode 100644 index 012a34968..000000000 --- a/src/pluto/myid.h +++ /dev/null @@ -1,38 +0,0 @@ -/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1) - * Copyright (C) 1999-2001 D. Hugh Redelmeier - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _MYID_H -#define _MYID_H - -#include <utils/identification.h> - -extern void init_myid(void); -extern void free_myid(void); - -enum myid_state { - MYID_UNKNOWN, /* not yet figured out */ - MYID_HOSTNAME, /* our current hostname */ - MYID_IP, /* our default IP address */ - MYID_SPECIFIED /* as specified by ipsec.conf */ -}; - -extern enum myid_state myid_state; -extern identification_t* myids[MYID_SPECIFIED+1]; /* %myid */ -extern void set_myid(enum myid_state s, char *); -extern void show_myid_status(void); -extern void set_myFQDN(void); - -#define resolve_myid(id) ((id)->get_type(id) == ID_MYID? myids[myid_state] : (id)) - -#endif /* _MYID_H */ diff --git a/src/pluto/nat_traversal.c b/src/pluto/nat_traversal.c deleted file mode 100644 index 28be76825..000000000 --- a/src/pluto/nat_traversal.c +++ /dev/null @@ -1,845 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2002-2005 Mathieu Lafon - * Arkoon Network Security - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <stdarg.h> -#include <syslog.h> -#include <errno.h> -#include <string.h> -#include <unistd.h> -#include <signal.h> /* used only if MSG_NOSIGNAL not defined */ -#include <sys/queue.h> - -#include <library.h> -#include <crypto/hashers/hasher.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "server.h" -#include "state.h" -#include "connections.h" -#include "packet.h" -#include "demux.h" -#include "kernel.h" -#include "whack.h" -#include "timer.h" -#include "cookie.h" -#include "crypto.h" -#include "vendor.h" -#include "ike_alg.h" -#include "nat_traversal.h" - -/* #define FORCE_NAT_TRAVERSAL */ -#define NAT_D_DEBUG -#define NAT_T_SUPPORT_LAST_DRAFTS - -#ifndef SOL_UDP -#define SOL_UDP 17 -#endif - -#ifndef UDP_ESPINUDP -#define UDP_ESPINUDP 100 -#endif - -#define DEFAULT_KEEP_ALIVE_PERIOD 20 - -#ifdef _IKE_ALG_H -/* Alg patch: hash_digest_len -> hash_digest_size */ -#define hash_digest_len hash_digest_size -#endif - -bool nat_traversal_enabled = FALSE; -bool nat_traversal_support_non_ike = FALSE; -bool nat_traversal_support_port_floating = FALSE; - -static unsigned int _kap = 0; -static unsigned int _ka_evt = 0; -static bool _force_ka = 0; - -static const char *natt_version = "0.6c"; - -void init_nat_traversal (bool activate, unsigned int keep_alive_period, - bool fka, bool spf) -{ - nat_traversal_enabled = activate; - nat_traversal_support_non_ike = activate; -#ifdef NAT_T_SUPPORT_LAST_DRAFTS - nat_traversal_support_port_floating = activate ? spf : FALSE; -#endif - _force_ka = fka; - _kap = keep_alive_period ? keep_alive_period : DEFAULT_KEEP_ALIVE_PERIOD; - plog(" including NAT-Traversal patch (Version %s)%s%s%s" - , natt_version, activate ? "" : " [disabled]" - , activate & fka ? " [Force KeepAlive]" : "" - , activate & !spf ? " [Port Floating disabled]" : ""); -} - -static void disable_nat_traversal (int type) -{ - if (type == ESPINUDP_WITH_NON_IKE) - nat_traversal_support_non_ike = FALSE; - else - nat_traversal_support_port_floating = FALSE; - - if (!nat_traversal_support_non_ike && - !nat_traversal_support_port_floating) - nat_traversal_enabled = FALSE; -} - -static void _natd_hash(const struct hash_desc *oakley_hasher, char *hash, - u_int8_t *icookie, u_int8_t *rcookie, - const ip_address *ip, u_int16_t port) -{ - if (is_zero_cookie(icookie)) - { - DBG_log("_natd_hash: Warning, icookie is zero !!"); - } - if (is_zero_cookie(rcookie)) - { - DBG_log("_natd_hash: Warning, rcookie is zero !!"); - } - - /** - * draft-ietf-ipsec-nat-t-ike-01.txt - * - * HASH = HASH(CKY-I | CKY-R | IP | Port) - * - * All values in network order - */ - { - chunk_t icookie_chunk = { icookie, COOKIE_SIZE }; - chunk_t rcookie_chunk = { rcookie, COOKIE_SIZE }; - chunk_t port_chunk = chunk_from_thing(port); - chunk_t addr_chunk; - hash_algorithm_t hash_alg; - hasher_t *hasher; - size_t hash_size; - - hash_alg = oakley_to_hash_algorithm(oakley_hasher->algo_id); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - hasher->get_hash(hasher, icookie_chunk, NULL); - hasher->get_hash(hasher, rcookie_chunk, NULL); - switch (addrtypeof(ip)) - { - case AF_INET: - addr_chunk = chunk_from_thing(ip->u.v4.sin_addr.s_addr); - break; - case AF_INET6: - addr_chunk = chunk_from_thing(ip->u.v6.sin6_addr.s6_addr); - break; - default: - addr_chunk = chunk_empty; /* should never occur */ - } - hasher->get_hash(hasher, addr_chunk, NULL); - hasher->get_hash(hasher, port_chunk, hash); - hash_size = hasher->get_hash_size(hasher); - hasher->destroy(hasher); -#ifdef NAT_D_DEBUG - DBG(DBG_NATT, - DBG_dump_chunk("_natd_hash: icookie=", icookie_chunk); - DBG_dump_chunk("_natd_hash: rcookie=", rcookie_chunk); - DBG_dump_chunk("_natd_hash: ip=", addr_chunk); - DBG_log("_natd_hash: port=%d", port); - DBG_dump("_natd_hash: hash=", hash, hash_size); - ) -#endif - } -} - -/* Add NAT-Traversal VIDs (supported ones) - * used when we are Initiator - */ -bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs) -{ - bool r = TRUE; - - if (nat_traversal_support_port_floating) - { - u_int8_t last_np = nat_traversal_support_non_ike ? - ISAKMP_NEXT_VID : np; - - if (r) - r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_RFC); - if (r) - r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_IETF_03); - if (r) - r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_IETF_02); - if (r) - r = out_vendorid(last_np, outs, VID_NATT_IETF_02_N); - } - if (nat_traversal_support_non_ike) - { - if (r) - r = out_vendorid(np, outs, VID_NATT_IETF_00); - } - return r; -} - -u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid) -{ - switch (nat_t_vid) - { - case VID_NATT_IETF_00: - return LELEM(NAT_TRAVERSAL_IETF_00_01); - case VID_NATT_IETF_02: - case VID_NATT_IETF_02_N: - case VID_NATT_IETF_03: - return LELEM(NAT_TRAVERSAL_IETF_02_03); - case VID_NATT_RFC: - return LELEM(NAT_TRAVERSAL_RFC); - } - return 0; -} - -void nat_traversal_natd_lookup(struct msg_digest *md) -{ - char hash[MAX_DIGEST_LEN]; - struct payload_digest *p; - struct state *st = md->st; - int i; - - if (!st || !md->iface || !st->st_oakley.hasher) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return; - } - - /** Count NAT-D **/ - for (p = md->chain[ISAKMP_NEXT_NATD_RFC], i=0; p != NULL; p = p->next, i++); - - /* - * We need at least 2 NAT-D (1 for us, many for peer) - */ - if (i < 2) - { - loglog(RC_LOG_SERIOUS, - "NAT-Traversal: Only %d NAT-D - Aborting NAT-Traversal negotiation", i); - st->nat_traversal = 0; - return; - } - - /* - * First one with my IP & port - */ - p = md->chain[ISAKMP_NEXT_NATD_RFC]; - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie, - &(md->iface->addr), ntohs(st->st_connection->spd.this.host_port)); - - if (!(pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len && - memeq(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len))) - { -#ifdef NAT_D_DEBUG - DBG(DBG_NATT, - DBG_log("NAT_TRAVERSAL_NAT_BHND_ME"); - DBG_dump("expected NAT-D:", hash - , st->st_oakley.hasher->hash_digest_len); - DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs)); - ) -#endif - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME); - } - - /* - * The others with sender IP & port - */ - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie, - &(md->sender), ntohs(md->sender_port)); - for (p = p->next, i=0 ; p != NULL; p = p->next) - { - if (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len && - memeq(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len)) - { - i++; - } - } - if (!i) - { -#ifdef NAT_D_DEBUG - DBG(DBG_NATT, - DBG_log("NAT_TRAVERSAL_NAT_BHND_PEER"); - DBG_dump("expected NAT-D:", hash - , st->st_oakley.hasher->hash_digest_len); - p = md->chain[ISAKMP_NEXT_NATD_RFC]; - for (p = p->next, i=0 ; p != NULL; p = p->next) - { - DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs)); - } - ) -#endif - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER); - } -#ifdef FORCE_NAT_TRAVERSAL - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER); - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME); -#endif -} - -bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, - struct msg_digest *md) -{ - char hash[MAX_DIGEST_LEN]; - struct state *st = md->st; - - if (!st || !st->st_oakley.hasher) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return FALSE; - } - - DBG(DBG_EMITTING, - DBG_log("sending NATD payloads") - ) - - /* - * First one with sender IP & port - */ - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, - is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie, - &(md->sender), -#ifdef FORCE_NAT_TRAVERSAL - 0 -#else - ntohs(md->sender_port) -#endif - ); - if (!out_generic_raw((st->nat_traversal & NAT_T_WITH_RFC_VALUES - ? ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS), &isakmp_nat_d, outs, - hash, st->st_oakley.hasher->hash_digest_len, "NAT-D")) - { - return FALSE; - } - - /* - * Second one with my IP & port - */ - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, - is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie, - &(md->iface->addr), -#ifdef FORCE_NAT_TRAVERSAL - 0 -#else - ntohs(st->st_connection->spd.this.host_port) -#endif - ); - return (out_generic_raw(np, &isakmp_nat_d, outs, - hash, st->st_oakley.hasher->hash_digest_len, "NAT-D")); -} - -/* - * nat_traversal_natoa_lookup() - * - * Look for NAT-OA in message - */ -void nat_traversal_natoa_lookup(struct msg_digest *md) -{ - struct payload_digest *p; - struct state *st = md->st; - int i; - ip_address ip; - - if (!st || !md->iface) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return; - } - - /* Initialize NAT-OA */ - anyaddr(AF_INET, &st->nat_oa); - - /* Count NAT-OA **/ - for (p = md->chain[ISAKMP_NEXT_NATOA_RFC], i=0; p != NULL; p = p->next, i++); - - DBG(DBG_NATT, - DBG_log("NAT-Traversal: received %d NAT-OA.", i) - ) - - if (i == 0) - return; - - if (!(st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER))) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " - "ignored because peer is not NATed", i); - return; - } - - if (i > 1) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " - "using first, ignoring others", i); - } - - /* Take first */ - p = md->chain[ISAKMP_NEXT_NATOA_RFC]; - - DBG(DBG_PARSING, - DBG_dump("NAT-OA:", p->pbs.start, pbs_room(&p->pbs)); - ); - - switch (p->payload.nat_oa.isanoa_idtype) - { - case ID_IPV4_ADDR: - if (pbs_left(&p->pbs) == sizeof(struct in_addr)) - { - initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET, &ip); - } - else - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv4 NAT-OA " - "with invalid IP size (%d)", (int)pbs_left(&p->pbs)); - return; - } - break; - case ID_IPV6_ADDR: - if (pbs_left(&p->pbs) == sizeof(struct in6_addr)) - { - initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET6, &ip); - } - else - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv6 NAT-OA " - "with invalid IP size (%d)", (int)pbs_left(&p->pbs)); - return; - } - break; - default: - loglog(RC_LOG_SERIOUS, "NAT-Traversal: " - "invalid ID Type (%d) in NAT-OA - ignored", - p->payload.nat_oa.isanoa_idtype); - return; - } - - DBG(DBG_NATT, - { - char ip_t[ADDRTOT_BUF]; - addrtot(&ip, 0, ip_t, sizeof(ip_t)); - - DBG_log("received NAT-OA: %s", ip_t); - } - ) - - if (isanyaddr(&ip)) - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %%any NAT-OA..."); - else - st->nat_oa = ip; -} - -bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs, - struct state *st) -{ - struct isakmp_nat_oa natoa; - pb_stream pbs; - unsigned char ip_val[sizeof(struct in6_addr)]; - size_t ip_len = 0; - ip_address *ip; - - if ((!st) || (!st->st_connection)) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return FALSE; - } - ip = &(st->st_connection->spd.this.host_addr); - - memset(&natoa, 0, sizeof(natoa)); - natoa.isanoa_np = np; - - switch (addrtypeof(ip)) - { - case AF_INET: - ip_len = sizeof(ip->u.v4.sin_addr.s_addr); - memcpy(ip_val, &ip->u.v4.sin_addr.s_addr, ip_len); - natoa.isanoa_idtype = ID_IPV4_ADDR; - break; - case AF_INET6: - ip_len = sizeof(ip->u.v6.sin6_addr.s6_addr); - memcpy(ip_val, &ip->u.v6.sin6_addr.s6_addr, ip_len); - natoa.isanoa_idtype = ID_IPV6_ADDR; - break; - default: - loglog(RC_LOG_SERIOUS, "NAT-Traversal: " - "invalid addrtypeof()=%d", addrtypeof(ip)); - return FALSE; - } - - if (!out_struct(&natoa, &isakmp_nat_oa, outs, &pbs)) - return FALSE; - - if (!out_raw(ip_val, ip_len, &pbs, "NAT-OA")) - return FALSE; - - DBG(DBG_NATT, - DBG_dump("NAT-OA (S):", ip_val, ip_len) - ) - - close_output_pbs(&pbs); - return TRUE; -} - -void nat_traversal_show_result (u_int32_t nt, u_int16_t sport) -{ - const char *mth = NULL, *rslt = NULL; - - switch (nt & NAT_TRAVERSAL_METHOD) - { - case LELEM(NAT_TRAVERSAL_IETF_00_01): - mth = natt_type_bitnames[0]; - break; - case LELEM(NAT_TRAVERSAL_IETF_02_03): - mth = natt_type_bitnames[1]; - break; - case LELEM(NAT_TRAVERSAL_RFC): - mth = natt_type_bitnames[2]; - break; - } - - switch (nt & NAT_T_DETECTED) - { - case 0: - rslt = "no NAT detected"; - break; - case LELEM(NAT_TRAVERSAL_NAT_BHND_ME): - rslt = "i am NATed"; - break; - case LELEM(NAT_TRAVERSAL_NAT_BHND_PEER): - rslt = "peer is NATed"; - break; - case LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER): - rslt = "both are NATed"; - break; - } - - loglog(RC_LOG_SERIOUS, - "NAT-Traversal: Result using %s: %s", - mth ? mth : "unknown method", - rslt ? rslt : "unknown result" - ); - - if ((nt & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER)) - && (sport == IKE_UDP_PORT) - && ((nt & NAT_T_WITH_PORT_FLOATING)==0)) - { - loglog(RC_LOG_SERIOUS, - "Warning: peer is NATed but source port is still udp/%d. " - "Ipsec-passthrough NAT device suspected -- NAT-T may not work.", - IKE_UDP_PORT - ); - } -} - -int nat_traversal_espinudp_socket (int sk, u_int32_t type) -{ - int r = setsockopt(sk, SOL_UDP, UDP_ESPINUDP, &type, sizeof(type)); - - if (r < 0 && errno == ENOPROTOOPT) - { - loglog(RC_LOG_SERIOUS, - "NAT-Traversal: ESPINUDP(%d) not supported by kernel -- " - "NAT-T disabled", type); - disable_nat_traversal(type); - } - return r; -} - -void nat_traversal_new_ka_event (void) -{ - if (_ka_evt) - return; /* event already scheduled */ - - event_schedule(EVENT_NAT_T_KEEPALIVE, _kap, NULL); - _ka_evt = 1; -} - -static void nat_traversal_send_ka (struct state *st) -{ - static unsigned char ka_payload = 0xff; - chunk_t sav; - - DBG(DBG_NATT, - DBG_log("ka_event: send NAT-KA to %s:%d", - ip_str(&st->st_connection->spd.that.host_addr), - st->st_connection->spd.that.host_port); - ) - - /* save state chunk */ - sav = st->st_tpacket; - - /* send keep alive */ - st->st_tpacket = chunk_create(&ka_payload, 1); - send_packet(st, "NAT-T Keep Alive"); - - /* restore state chunk */ - st->st_tpacket = sav; -} - -/** - * Find ISAKMP States with NAT-T and send keep-alive - */ -static void nat_traversal_ka_event_state (struct state *st, void *data) -{ - unsigned int *_kap_st = (unsigned int *)data; - const connection_t *c = st->st_connection; - - if (!c) - return; - - if ((st->st_state == STATE_MAIN_R3 || st->st_state == STATE_MAIN_I4) - && (st->nat_traversal & NAT_T_DETECTED) - && ((st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka)) - { - /* - * - ISAKMP established - * - NAT-Traversal detected - * - NAT-KeepAlive needed (we are NATed) - */ - if (c->newest_isakmp_sa != st->st_serialno) - { - /* - * if newest is also valid, ignore this one, we will only use - * newest. - */ - struct state *st_newest; - - st_newest = state_with_serialno(c->newest_isakmp_sa); - if (st_newest - && (st_newest->st_state == STATE_MAIN_R3 || st_newest->st_state == STATE_MAIN_I4) - && (st_newest->nat_traversal & NAT_T_DETECTED) - && ((st_newest->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka)) - { - return; - } - } - set_cur_state(st); - nat_traversal_send_ka(st); - reset_cur_state(); - (*_kap_st)++; - } -} - -void nat_traversal_ka_event (void) -{ - unsigned int _kap_st = 0; - - _ka_evt = 0; /* ready to be reschedule */ - - for_each_state((void *)nat_traversal_ka_event_state, &_kap_st); - - /* if there are still states who needs Keep-Alive, schedule new event */ - if (_kap_st) - nat_traversal_new_ka_event(); -} - -struct _new_mapp_nfo { - ip_address addr; - u_int16_t sport, dport; -}; - -static void nat_traversal_find_new_mapp_state (struct state *st, void *data) -{ - connection_t *c = st->st_connection; - struct _new_mapp_nfo *nfo = (struct _new_mapp_nfo *)data; - - if (c != NULL - && sameaddr(&c->spd.that.host_addr, &(nfo->addr)) - && c->spd.that.host_port == nfo->sport) - { - - /* change host port */ - c->spd.that.host_port = nfo->dport; - - if (IS_IPSEC_SA_ESTABLISHED(st->st_state) - || IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) - { - if (!update_ipsec_sa(st)) - { - /* - * If ipsec update failed, restore old port or we'll - * not be able to update anymore. - */ - c->spd.that.host_port = nfo->sport; - } - } - } -} - -static int nat_traversal_new_mapping(const ip_address *src, u_int16_t sport, - const ip_address *dst, u_int16_t dport) -{ - char srca[ADDRTOT_BUF], dsta[ADDRTOT_BUF]; - struct _new_mapp_nfo nfo; - - addrtot(src, 0, srca, ADDRTOT_BUF); - addrtot(dst, 0, dsta, ADDRTOT_BUF); - - if (!sameaddr(src, dst)) - { - loglog(RC_LOG_SERIOUS, "nat_traversal_new_mapping: " - "address change currently not supported [%s:%d,%s:%d]", - srca, sport, dsta, dport); - return -1; - } - - if (sport == dport) - { - /* no change */ - return 0; - } - - DBG_log("NAT-T: new mapping %s:%d/%d)", srca, sport, dport); - - nfo.addr = *src; - nfo.sport = sport; - nfo.dport = dport; - - for_each_state((void *)nat_traversal_find_new_mapp_state, &nfo); - - return 0; -} - -void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st) -{ - connection_t *c = st ? st->st_connection : NULL; - struct iface *i = NULL; - - if ((st == NULL) || (c == NULL)) - return; - - if (md) - { - /* - * If source port has changed, update (including other states and - * established kernel SA) - */ - if (c->spd.that.host_port != md->sender_port) - { - nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port, - &c->spd.that.host_addr, md->sender_port); - } - - /* - * If interface type has changed, update local port (500/4500) - */ - if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !md->iface->ike_float) - || (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && md->iface->ike_float)) - { - c->spd.this.host_port = (md->iface->ike_float) - ? NAT_T_IKE_FLOAT_PORT : pluto_port; - - DBG(DBG_NATT, - DBG_log("NAT-T: updating local port to %d", c->spd.this.host_port); - ); - } - } - - /* - * If we're initiator and NAT-T (with port floating) is detected, we - * need to change port (MAIN_I3 or QUICK_I1) - */ - if ((st->st_state == STATE_MAIN_I3 || st->st_state == STATE_QUICK_I1) - && (st->nat_traversal & NAT_T_WITH_PORT_FLOATING) - && (st->nat_traversal & NAT_T_DETECTED) - && (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT)) - { - DBG(DBG_NATT, - DBG_log("NAT-T: floating to port %d", NAT_T_IKE_FLOAT_PORT); - ) - c->spd.this.host_port = NAT_T_IKE_FLOAT_PORT; - c->spd.that.host_port = NAT_T_IKE_FLOAT_PORT; - /* - * Also update pending connections or they will be deleted if uniqueids - * option is set. - */ - update_pending(st, st); - } - - /* - * Find valid interface according to local port (500/4500) - */ - if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !c->interface->ike_float) - || (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && c->interface->ike_float)) - { - for (i = interfaces; i != NULL; i = i->next) - { - if (sameaddr(&c->interface->addr, &i->addr) - && i->ike_float != c->interface->ike_float) - { - DBG(DBG_NATT, - DBG_log("NAT-T: using interface %s:%d", i->rname, - i->ike_float ? NAT_T_IKE_FLOAT_PORT : pluto_port); - ) - c->interface = i; - break; - } - } - } -} - -struct _new_kernel_mapp_nfo { - u_int32_t reqid; - u_int32_t spi; - ip_address *addr; -}; - -static void nat_t_new_kernel_mapp (struct state *st, void *data) -{ - connection_t *c = st->st_connection; - struct _new_kernel_mapp_nfo *nfo = (struct _new_kernel_mapp_nfo *)data; - - if (c != NULL && st->st_esp.present - && nfo->spi == st->st_esp.our_spi - && nfo->reqid == c->spd.reqid) - { - u_int16_t port = ntohs(portof(nfo->addr)); - - DBG(DBG_NATT, { - char text_said[SATOT_BUF]; - char olda[ADDRTOT_BUF]; - char newa[ADDRTOT_BUF]; - ip_said said; - - initsaid(&c->spd.that.host_addr, nfo->spi, SA_ESP, &said); - satot(&said, 0, text_said, SATOT_BUF); - addrtot(&c->spd.that.host_addr, 0, olda, ADDRTOT_BUF); - addrtot(nfo->addr, 0, newa, ADDRTOT_BUF); - - DBG_log("new kernel mapping %s %s:%d %s:%d", - text_said, olda, c->spd.that.host_port, newa, port); - }) - - nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port, - nfo->addr, port); - } -} - -void process_nat_t_new_mapping(u_int32_t reqid, u_int32_t spi, - ip_address *new_end) -{ - struct _new_kernel_mapp_nfo nfo = { - .reqid = reqid, - .spi = spi, - .addr = new_end, - }; - for_each_state((void *)nat_t_new_kernel_mapp, &nfo); -} - diff --git a/src/pluto/nat_traversal.h b/src/pluto/nat_traversal.h deleted file mode 100644 index 80bdaf787..000000000 --- a/src/pluto/nat_traversal.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2002-2003 Mathieu Lafon - * Arkoon Network Security - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _NAT_TRAVERSAL_H -#define _NAT_TRAVERSAL_H - -#include "packet.h" - -#define NAT_TRAVERSAL_IETF_00_01 1 -#define NAT_TRAVERSAL_IETF_02_03 2 -#define NAT_TRAVERSAL_RFC 3 - -#define NAT_TRAVERSAL_NAT_BHND_ME 30 -#define NAT_TRAVERSAL_NAT_BHND_PEER 31 - -#define NAT_TRAVERSAL_METHOD (0xffffffff - LELEM(30) - LELEM(31)) - -/** - * NAT-Traversal methods which need NAT-D - */ -#define NAT_T_WITH_NATD \ - ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \ - LELEM(NAT_TRAVERSAL_RFC) ) -/** - * NAT-Traversal methods which need NAT-OA - */ -#define NAT_T_WITH_NATOA \ - ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \ - LELEM(NAT_TRAVERSAL_RFC) ) -/** - * NAT-Traversal methods which use NAT-KeepAlive - */ -#define NAT_T_WITH_KA \ - ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \ - LELEM(NAT_TRAVERSAL_RFC) ) -/** - * NAT-Traversal methods which use floating port - */ -#define NAT_T_WITH_PORT_FLOATING \ - ( LELEM(NAT_TRAVERSAL_IETF_02_03) | LELEM(NAT_TRAVERSAL_RFC) ) - -/** - * NAT-Traversal methods which use officials values (RFC) - */ -#define NAT_T_WITH_RFC_VALUES \ - ( LELEM(NAT_TRAVERSAL_RFC) ) - -/** - * NAT-Traversal detected - */ -#define NAT_T_DETECTED \ - ( LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER) ) - -/** - * NAT-T Port Floating - */ -#define NAT_T_IKE_FLOAT_PORT 4500 - -void init_nat_traversal (bool activate, unsigned int keep_alive_period, - bool fka, bool spf); - -extern bool nat_traversal_enabled; -extern bool nat_traversal_support_non_ike; -extern bool nat_traversal_support_port_floating; - -/** - * NAT-D - */ -void nat_traversal_natd_lookup(struct msg_digest *md); -#ifndef PB_STREAM_UNDEFINED -bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, - struct msg_digest *md); -#endif - -/** - * NAT-OA - */ -void nat_traversal_natoa_lookup(struct msg_digest *md); -#ifndef PB_STREAM_UNDEFINED -bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs, - struct state *st); -#endif - -/** - * NAT-keep_alive - */ -void nat_traversal_new_ka_event (void); -void nat_traversal_ka_event (void); - -void nat_traversal_show_result (u_int32_t nt, u_int16_t sport); - -int nat_traversal_espinudp_socket (int sk, u_int32_t type); - -/** - * Vendor ID - */ -#ifndef PB_STREAM_UNDEFINED -bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs); -#endif -u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid); - -void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st); - -/** - * New NAT mapping - */ -void process_nat_t_new_mapping(u_int32_t reqid, u_int32_t spi, - ip_address *new_end); - -/** - * IKE port floating - */ -bool -nat_traversal_port_float(struct state *st, struct msg_digest *md, bool in); - -/** - * Encapsulation mode macro (see demux.c) - */ -#define NAT_T_ENCAPSULATION_MODE(st,nat_t_policy) ( \ - ((st)->nat_traversal & NAT_T_DETECTED) \ - ? ( ((nat_t_policy) & POLICY_TUNNEL) \ - ? ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \ - ? (ENCAPSULATION_MODE_UDP_TUNNEL_RFC) \ - : (ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS) \ - ) \ - : ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \ - ? (ENCAPSULATION_MODE_UDP_TRANSPORT_RFC) \ - : (ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS) \ - ) \ - ) \ - : ( ((st)->st_policy & POLICY_TUNNEL) \ - ? (ENCAPSULATION_MODE_TUNNEL) \ - : (ENCAPSULATION_MODE_TRANSPORT) \ - ) \ - ) - -#endif /* _NAT_TRAVERSAL_H */ - diff --git a/src/pluto/ocsp.c b/src/pluto/ocsp.c deleted file mode 100644 index c299e3d39..000000000 --- a/src/pluto/ocsp.c +++ /dev/null @@ -1,1558 +0,0 @@ -/* Support of the Online Certificate Status Protocol (OCSP) - * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#include <freeswan.h> - -#include <library.h> -#include <asn1/asn1.h> -#include <asn1/asn1_parser.h> -#include <asn1/oid.h> -#include <crypto/rngs/rng.h> -#include <crypto/hashers/hasher.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "crl.h" -#include "ca.h" -#include "certs.h" -#include "smartcard.h" -#include "whack.h" -#include "keys.h" -#include "fetch.h" -#include "ocsp.h" - -#define NONCE_LENGTH 16 - -static const char *const cert_status_names[] = { - "good", - "revoked", - "unknown", - "undefined" -}; - - -static const char *const response_status_names[] = { - "successful", - "malformed request", - "internal error", - "try later", - "status #4", - "signature required", - "unauthorized" -}; - -/* response container */ -typedef struct response response_t; - -struct response { - chunk_t tbs; - identification_t *responder_id_name; - chunk_t responder_id_key; - time_t produced_at; - chunk_t responses; - chunk_t nonce; - int algorithm; - chunk_t signature; -}; - -const response_t empty_response = { - { NULL, 0 } , /* tbs */ - NULL , /* responder_id_name */ - { NULL, 0 } , /* responder_id_key */ - UNDEFINED_TIME, /* produced_at */ - { NULL, 0 } , /* single_response */ - { NULL, 0 } , /* nonce */ - OID_UNKNOWN , /* signature_algorithm */ - { NULL, 0 } /* signature */ -}; - -/* single response container */ -typedef struct single_response single_response_t; - -struct single_response { - single_response_t *next; - int hash_algorithm; - chunk_t issuer_name_hash; - chunk_t issuer_key_hash; - chunk_t serialNumber; - cert_status_t status; - time_t revocationTime; - crl_reason_t revocationReason; - time_t thisUpdate; - time_t nextUpdate; -}; - -const single_response_t empty_single_response = { - NULL , /* *next */ - OID_UNKNOWN , /* hash_algorithm */ - { NULL, 0 } , /* issuer_name_hash */ - { NULL, 0 } , /* issuer_key_hash */ - { NULL, 0 } , /* serial_number */ - CERT_UNDEFINED , /* status */ - UNDEFINED_TIME , /* revocationTime */ - CRL_REASON_UNSPECIFIED, /* revocationReason */ - UNDEFINED_TIME , /* this_update */ - UNDEFINED_TIME /* next_update */ -}; - - -/* list of single requests */ -typedef struct request_list request_list_t; -struct request_list { - chunk_t request; - request_list_t *next; -}; - -/* some OCSP specific prefabricated ASN.1 constants */ -static const chunk_t ASN1_nonce_oid = chunk_from_chars( - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 -); -static const chunk_t ASN1_response_oid = chunk_from_chars( - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 -); -static const chunk_t ASN1_response_content = chunk_from_chars( - 0x04, 0x0D, - 0x30, 0x0B, - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 -); - -/* default OCSP uri */ -static chunk_t ocsp_default_uri; - -/* ocsp cache: pointer to first element */ -static ocsp_location_t *ocsp_cache = NULL; - -/* static temporary storage for ocsp requestor information */ -static cert_t *ocsp_requestor_cert = NULL; - -static smartcard_t *ocsp_requestor_sc = NULL; - -static private_key_t *ocsp_requestor_key = NULL; - -/** - * ASN.1 definition of ocspResponse - */ -static const asn1Object_t ocspResponseObjects[] = { - { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */ - { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */ - { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ - { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */ - { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define OCSP_RESPONSE_STATUS 1 -#define OCSP_RESPONSE_TYPE 4 -#define OCSP_RESPONSE 5 - -/** - * ASN.1 definition of basicResponse - */ -static const asn1Object_t basicResponseObjects[] = { - { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE | - ASN1_DEF }, /* 2 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ - { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */ - { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ - { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */ - { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */ - { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ - { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ - { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */ - { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */ - { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */ - { 5, "critical", ASN1_BOOLEAN, ASN1_BODY | - ASN1_DEF }, /* 16 */ - { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */ - { 3, "end loop", ASN1_EOC, ASN1_END }, /* 18 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */ - { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */ - { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */ - { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */ - { 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define BASIC_RESPONSE_TBS_DATA 1 -#define BASIC_RESPONSE_VERSION 3 -#define BASIC_RESPONSE_ID_BY_NAME 5 -#define BASIC_RESPONSE_ID_BY_KEY 8 -#define BASIC_RESPONSE_PRODUCED_AT 10 -#define BASIC_RESPONSE_RESPONSES 11 -#define BASIC_RESPONSE_EXT_ID 15 -#define BASIC_RESPONSE_CRITICAL 16 -#define BASIC_RESPONSE_EXT_VALUE 17 -#define BASIC_RESPONSE_ALGORITHM 20 -#define BASIC_RESPONSE_SIGNATURE 21 -#define BASIC_RESPONSE_CERTIFICATE 24 - -/** - * ASN.1 definition of responses - */ -static const asn1Object_t responsesObjects[] = { - { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define RESPONSES_SINGLE_RESPONSE 1 - -/** - * ASN.1 definition of singleResponse - */ -static const asn1Object_t singleResponseObjects[] = { - { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */ - { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */ - { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */ - { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */ - { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ - { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */ - { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */ - { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */ - { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ - { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ - { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */ - { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */ - { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ - { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */ - { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */ - { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ - { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */ - { 4, "critical", ASN1_BOOLEAN, ASN1_BODY | - ASN1_DEF }, /* 24 */ - { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 27 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define SINGLE_RESPONSE_ALGORITHM 2 -#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3 -#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4 -#define SINGLE_RESPONSE_SERIAL_NUMBER 5 -#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6 -#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8 -#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9 -#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11 -#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14 -#define SINGLE_RESPONSE_THIS_UPDATE 16 -#define SINGLE_RESPONSE_NEXT_UPDATE 18 -#define SINGLE_RESPONSE_EXT_ID 23 -#define SINGLE_RESPONSE_CRITICAL 24 -#define SINGLE_RESPONSE_EXT_VALUE 25 - -/* - * Build an ocsp location from certificate information - * without unsharing its contents - */ -static bool build_ocsp_location(const cert_t *cert, ocsp_location_t *location) -{ - certificate_t *certificate = cert->cert; - identification_t *issuer = certificate->get_issuer(certificate); - x509_t *x509 = (x509_t*)certificate; - chunk_t issuer_dn = issuer->get_encoding(issuer); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - hasher_t *hasher; - static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */ - - enumerator_t *enumerator = x509->create_ocsp_uri_enumerator(x509); - - location->uri = NULL; - while (enumerator->enumerate(enumerator, &location->uri)) - { - break; - } - enumerator->destroy(enumerator); - - if (location->uri == NULL) - { - ca_info_t *ca = get_ca_info(issuer, authKeyID); - if (ca && ca->ocspuri) - { - location->uri = ca->ocspuri; - } - else - { /* abort if no ocsp location uri is defined */ - return FALSE; - } - } - - /* compute authNameID from as SHA-1 hash of issuer DN */ - location->authNameID = chunk_create(digest, HASH_SIZE_SHA1); - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - return FALSE; - } - hasher->get_hash(hasher, issuer_dn, digest); - hasher->destroy(hasher); - - location->next = NULL; - location->issuer = issuer; - location->authKeyID = authKeyID; - - if (authKeyID.ptr == NULL) - { - cert_t *authcert = get_authcert(issuer, authKeyID, X509_CA); - - if (authcert) - { - x509_t *x509 = (x509_t*)authcert->cert; - - location->authKeyID = x509->get_subjectKeyIdentifier(x509); - } - } - - location->nonce = chunk_empty; - location->certinfo = NULL; - - return TRUE; -} - -/** - * Compare two ocsp locations for equality - */ -static bool same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b) -{ - return ((a->authKeyID.ptr) - ? same_keyid(a->authKeyID, b->authKeyID) - : a->issuer->equals(a->issuer, b->issuer)) - && streq(a->uri, b->uri); -} - -/** - * Find an existing ocsp location in a chained list - */ -ocsp_location_t* get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain) -{ - - while (chain) - { - if (same_ocsp_location(loc, chain)) - return chain; - chain = chain->next; - } - return NULL; -} - -/** - * Retrieves the status of a cert from the ocsp cache - * returns CERT_UNDEFINED if no status is found - */ -static cert_status_t get_ocsp_status(const ocsp_location_t *loc, - chunk_t serialNumber, - time_t *nextUpdate, time_t *revocationTime, - crl_reason_t *revocationReason) -{ - ocsp_certinfo_t *certinfo, **certinfop; - int cmp = -1; - - /* find location */ - ocsp_location_t *location = get_ocsp_location(loc, ocsp_cache); - - if (location == NULL) - return CERT_UNDEFINED; - - /* traverse list of certinfos in increasing order */ - certinfop = &location->certinfo; - certinfo = *certinfop; - - while (certinfo) - { - cmp = chunk_compare(serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; - certinfo = *certinfop; - } - - if (cmp == 0) - { - *nextUpdate = certinfo->nextUpdate; - *revocationTime = certinfo->revocationTime; - *revocationReason = certinfo->revocationReason; - return certinfo->status; - } - - return CERT_UNDEFINED; -} - -/** - * Verify the ocsp status of a certificate - */ -cert_status_t verify_by_ocsp(const cert_t *cert, time_t *until, - time_t *revocationDate, - crl_reason_t *revocationReason) -{ - x509_t *x509 = (x509_t*)cert->cert; - chunk_t serialNumber = x509->get_serial(x509); - cert_status_t status; - ocsp_location_t location; - time_t nextUpdate = UNDEFINED_TIME; - - *revocationDate = UNDEFINED_TIME; - *revocationReason = CRL_REASON_UNSPECIFIED; - - /* is an ocsp location defined? */ - if (!build_ocsp_location(cert, &location)) - { - return CERT_UNDEFINED; - } - - lock_ocsp_cache("verify_by_ocsp"); - status = get_ocsp_status(&location, serialNumber, &nextUpdate - , revocationDate, revocationReason); - unlock_ocsp_cache("verify_by_ocsp"); - - if (status == CERT_UNDEFINED || nextUpdate < time(NULL)) - { - plog("ocsp status is stale or not in cache"); - add_ocsp_fetch_request(&location, serialNumber); - - /* inititate fetching of ocsp status */ - wake_fetch_thread("verify_by_ocsp"); - } - *until = nextUpdate; - return status; -} - -/** - * Check if an ocsp status is about to expire - */ -void check_ocsp(void) -{ - ocsp_location_t *location; - - lock_ocsp_cache("check_ocsp"); - location = ocsp_cache; - - while (location) - { - char buf[BUF_LEN]; - bool first = TRUE; - ocsp_certinfo_t *certinfo = location->certinfo; - - while (certinfo) - { - if (!certinfo->once) - { - time_t time_left = certinfo->nextUpdate - time(NULL); - - DBG(DBG_CONTROL, - if (first) - { - DBG_log("issuer: \"%Y\"", location->issuer); - if (location->authKeyID.ptr) - { - datatot(location->authKeyID.ptr, location->authKeyID.len - , ':', buf, BUF_LEN); - DBG_log("authkey: %s", buf); - } - first = FALSE; - } - datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len - , ':', buf, BUF_LEN); - DBG_log("serial: %s, %ld seconds left", buf, time_left) - ) - - if (time_left < 2*crl_check_interval) - add_ocsp_fetch_request(location, certinfo->serialNumber); - } - certinfo = certinfo->next; - } - location = location->next; - } - unlock_ocsp_cache("check_ocsp"); -} - -/** - * frees the allocated memory of a certinfo struct - */ -static void free_certinfo(ocsp_certinfo_t *certinfo) -{ - free(certinfo->serialNumber.ptr); - free(certinfo); -} - -/** - * frees all certinfos in a chained list - */ -static void free_certinfos(ocsp_certinfo_t *chain) -{ - ocsp_certinfo_t *certinfo; - - while (chain) - { - certinfo = chain; - chain = chain->next; - free_certinfo(certinfo); - } -} - -/** - * Frees the memory allocated to an ocsp location including all certinfos - */ -static void free_ocsp_location(ocsp_location_t* location) -{ - DESTROY_IF(location->issuer); - free(location->authNameID.ptr); - free(location->authKeyID.ptr); - free(location->uri); - free_certinfos(location->certinfo); - free(location); -} - -/* - * Free a chained list of ocsp locations - */ -void free_ocsp_locations(ocsp_location_t **chain) -{ - while (*chain) - { - ocsp_location_t *location = *chain; - *chain = location->next; - free_ocsp_location(location); - } -} - -/** - * Free the ocsp cache - */ -void free_ocsp_cache(void) -{ - lock_ocsp_cache("free_ocsp_cache"); - free_ocsp_locations(&ocsp_cache); - unlock_ocsp_cache("free_ocsp_cache"); -} - -/** - * Frees the ocsp cache and global variables - */ -void free_ocsp(void) -{ - free(ocsp_default_uri.ptr); - free_ocsp_cache(); -} - -/** - * List a chained list of ocsp_locations - */ -void list_ocsp_locations(ocsp_location_t *location, bool requests, - bool utc, bool strict) -{ - bool first = TRUE; - - while (location) - { - ocsp_certinfo_t *certinfo = location->certinfo; - - if (certinfo) - { - if (first) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of OCSP %s:", requests ? - "Fetch Requests" : "Responses"); - first = FALSE; - } - whack_log(RC_COMMENT, " "); - if (location->issuer) - { - whack_log(RC_COMMENT, " issuer: \"%Y\"", location->issuer); - } - whack_log(RC_COMMENT, " uri: '%s'", location->uri); - if (location->authNameID.ptr) - { - whack_log(RC_COMMENT, " authname: %#B", &location->authNameID); - } - if (location->authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &location->authKeyID); - } - while (certinfo) - { - chunk_t serial = chunk_skip_zero(certinfo->serialNumber); - - if (requests) - { - whack_log(RC_COMMENT, " serial: %#B, %d trials", - &serial, certinfo->trials); - } - else if (certinfo->once) - { - whack_log(RC_COMMENT, " serial: %#B, %s, once%s", - &serial, cert_status_names[certinfo->status], - (certinfo->nextUpdate < time(NULL))? " (expired)": ""); - } - else - { - whack_log(RC_COMMENT, " serial: %#B, %s, until %T %s", - &serial, cert_status_names[certinfo->status], - &certinfo->nextUpdate, utc, - check_expiry(certinfo->nextUpdate, OCSP_WARNING_INTERVAL, strict)); - } - certinfo = certinfo->next; - } - } - location = location->next; - } -} - -/** - * List the ocsp cache - */ -void list_ocsp_cache(bool utc, bool strict) -{ - lock_ocsp_cache("list_ocsp_cache"); - list_ocsp_locations(ocsp_cache, FALSE, utc, strict); - unlock_ocsp_cache("list_ocsp_cache"); -} - -static bool get_ocsp_requestor_cert(ocsp_location_t *location) -{ - cert_t *cert = NULL; - - /* initialize temporary static storage */ - ocsp_requestor_cert = NULL; - ocsp_requestor_sc = NULL; - ocsp_requestor_key = NULL; - - for (;;) - { - certificate_t *certificate; - - /* looking for a certificate from the same issuer */ - cert = get_x509cert(location->issuer, location->authKeyID, cert); - if (cert == NULL) - { - break; - } - certificate = cert->cert; - DBG(DBG_CONTROL, - DBG_log("candidate: '%Y'", certificate->get_subject(certificate)); - ) - - if (cert->smartcard) - { - /* look for a matching private key on a smartcard */ - smartcard_t *sc = scx_get(cert); - - if (sc) - { - DBG(DBG_CONTROL, - DBG_log("matching smartcard found") - ) - if (sc->valid) - { - ocsp_requestor_cert = cert; - ocsp_requestor_sc = sc; - return TRUE; - } - plog("unable to sign ocsp request without PIN"); - } - } - else - { - /* look for a matching private key in the chained list */ - private_key_t *private = get_x509_private_key(cert); - - if (private) - { - DBG(DBG_CONTROL, - DBG_log("matching private key found") - ) - ocsp_requestor_cert = cert; - ocsp_requestor_key = private; - return TRUE; - } - } - } - return FALSE; -} - -static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc) -{ - hasher_t *hasher; - u_char *pos; - chunk_t digest; - chunk_t digest_info, sigdata; - size_t siglen = 0; - - if (!scx_establish_context(sc) || !scx_login(sc)) - { - scx_release_context(sc); - return chunk_empty; - } - - siglen = scx_get_keylength(sc); - - if (siglen == 0) - { - plog("failed to get keylength from smartcard"); - scx_release_context(sc); - return chunk_empty; - } - - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)" - , (int)sc->slot, sc->id) - ) - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - return chunk_empty; - } - hasher->allocate_hash(hasher, tbs, &digest); - hasher->destroy(hasher); - - /* according to PKCS#1 v2.1 digest must be packaged into - * an ASN.1 structure for encryption - */ - digest_info = asn1_wrap(ASN1_SEQUENCE, "mm" - , asn1_algorithmIdentifier(OID_SHA1) - , asn1_wrap(ASN1_OCTET_STRING, "m", digest)); - - pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen); - *pos++ = 0x00; - scx_sign_hash(sc, digest_info.ptr, digest_info.len, pos, siglen); - free(digest_info.ptr); - - if (!pkcs11_keep_state) - { - scx_release_context(sc); - } - return sigdata; -} - -/** - * build signature into ocsp request gets built only if a request cert - * with a corresponding private key is found - */ -static chunk_t build_signature(chunk_t tbsRequest) -{ - chunk_t sigdata, cert, certs = chunk_empty; - - if (ocsp_requestor_sc) - { - /* RSA signature is done on smartcard */ - sigdata = sc_build_sha1_signature(tbsRequest, ocsp_requestor_sc); - } - else - { - /* RSA signature is done in software */ - sigdata = x509_build_signature(tbsRequest, OID_SHA1, ocsp_requestor_key, - TRUE); - } - if (sigdata.ptr == NULL) - { - return chunk_empty; - } - - /* include our certificate */ - if (ocsp_requestor_cert->cert->get_encoding(ocsp_requestor_cert->cert, - CERT_ASN1_DER, &cert)) - { - certs = asn1_wrap(ASN1_CONTEXT_C_0, "m", - asn1_wrap(ASN1_SEQUENCE, "m", cert)); - } - /* build signature comprising algorithm, signature and cert */ - return asn1_wrap(ASN1_CONTEXT_C_0, "m" - , asn1_wrap(ASN1_SEQUENCE, "mmm" - , asn1_algorithmIdentifier(OID_SHA1_WITH_RSA) - , sigdata - , certs - ) - ); -} - -/** - * Build request (into requestList) - * no singleRequestExtensions used - */ -static chunk_t build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo) -{ - chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "mmmm" - , asn1_algorithmIdentifier(OID_SHA1) - , asn1_simple_object(ASN1_OCTET_STRING, location->authNameID) - , asn1_simple_object(ASN1_OCTET_STRING, location->authKeyID) - , asn1_simple_object(ASN1_INTEGER, certinfo->serialNumber)); - - return asn1_wrap(ASN1_SEQUENCE, "m", reqCert); -} - -/** - * build requestList (into TBSRequest) - */ -static chunk_t build_request_list(ocsp_location_t *location) -{ - chunk_t requestList; - request_list_t *reqs = NULL; - ocsp_certinfo_t *certinfo = location->certinfo; - u_char *pos; - - size_t datalen = 0; - - /* build content */ - while (certinfo) - { - /* build request for every certificate in list - * and store them in a chained list - */ - request_list_t *req = malloc_thing(request_list_t); - - req->request = build_request(location, certinfo); - req->next = reqs; - reqs = req; - - datalen += req->request.len; - certinfo = certinfo->next; - } - - pos = asn1_build_object(&requestList, ASN1_SEQUENCE, datalen); - - /* copy all in chained list, free list afterwards */ - while (reqs) - { - request_list_t *req = reqs; - - mv_chunk(&pos, req->request); - reqs = reqs->next; - free(req); - } - - return requestList; -} - -/** - * Build requestorName (into TBSRequest) - */ -static chunk_t build_requestor_name(void) -{ - certificate_t *certificate = ocsp_requestor_cert->cert; - identification_t *subject = certificate->get_subject(certificate); - - return asn1_wrap(ASN1_CONTEXT_C_1, "m" - , asn1_simple_object(ASN1_CONTEXT_C_4 - , subject->get_encoding(subject))); -} - -/** - * build nonce extension (into requestExtensions) - */ -static chunk_t build_nonce_extension(ocsp_location_t *location) -{ - rng_t *rng; - - /* generate a random nonce */ - location->nonce.ptr = malloc(NONCE_LENGTH), - location->nonce.len = NONCE_LENGTH; - rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - rng->get_bytes(rng, location->nonce.len, location->nonce.ptr); - rng->destroy(rng); - - return asn1_wrap(ASN1_SEQUENCE, "cm" - , ASN1_nonce_oid - , asn1_simple_object(ASN1_OCTET_STRING, location->nonce)); -} - -/** - * Build requestExtensions (into TBSRequest) - */ -static chunk_t build_request_ext(ocsp_location_t *location) -{ - return asn1_wrap(ASN1_CONTEXT_C_2, "m" - , asn1_wrap(ASN1_SEQUENCE, "mm" - , build_nonce_extension(location) - , asn1_wrap(ASN1_SEQUENCE, "cc" - , ASN1_response_oid - , ASN1_response_content - ) - ) - ); -} - -/** - * Build TBSRequest (into OCSPRequest) - */ -static chunk_t build_tbs_request(ocsp_location_t *location, bool has_requestor_cert) -{ - /* version is skipped since the default is ok */ - return asn1_wrap(ASN1_SEQUENCE, "mmm" - , (has_requestor_cert) - ? build_requestor_name() - : chunk_empty - , build_request_list(location) - , build_request_ext(location)); -} - -/** - * Assembles an ocsp request to given location - * and sets nonce field in location to the sent nonce - */ -chunk_t build_ocsp_request(ocsp_location_t *location) -{ - bool has_requestor_cert; - chunk_t tbsRequest, signature; - - DBG(DBG_CONTROL, - DBG_log("assembling ocsp request"); - DBG_log("issuer: \"%Y\"", location->issuer); - if (location->authKeyID.ptr) - { - DBG_log("authkey: %#B", &location->authKeyID); - } - ) - lock_certs_and_keys("build_ocsp_request"); - - /* looks for requestor cert and matching private key */ - has_requestor_cert = get_ocsp_requestor_cert(location); - - /* build content */ - tbsRequest = build_tbs_request(location, has_requestor_cert); - - /* sign tbsReuqest */ - signature = (has_requestor_cert)? build_signature(tbsRequest) - : chunk_empty; - - unlock_certs_and_keys("build_ocsp_request"); - - return asn1_wrap(ASN1_SEQUENCE, "mm" - , tbsRequest - , signature); -} - -/** - * Check if the OCSP response has a valid signature - */ -static bool valid_ocsp_response(response_t *res) -{ - int pathlen, pathlen_constraint; - cert_t *authcert; - - lock_authcert_list("valid_ocsp_response"); - - authcert = get_authcert(res->responder_id_name, res->responder_id_key, - X509_OCSP_SIGNER | X509_CA); - if (authcert == NULL) - { - plog("no matching ocsp signer cert found"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("ocsp signer cert found") - ) - - if (!x509_check_signature(res->tbs, res->signature, res->algorithm, - authcert->cert)) - { - plog("signature of ocsp response is invalid"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("signature of ocsp response is valid") - ) - - - for (pathlen = -1; pathlen <= X509_MAX_PATH_LEN; pathlen++) - { - cert_t *cert = authcert; - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *subject = certificate->get_subject(certificate); - identification_t *issuer = certificate->get_issuer(certificate); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - time_t not_before, not_after; - - DBG(DBG_CONTROL, - DBG_log("subject: '%Y'", subject); - DBG_log("issuer: '%Y'", issuer); - if (authKeyID.ptr) - { - DBG_log("authkey: %#B", &authKeyID); - } - ) - - if (!certificate->get_validity(certificate, NULL, ¬_before, ¬_after)) - { - plog("certificate is invalid (valid from %T to %T)", - ¬_before, FALSE, ¬_after, FALSE); - - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate is valid") - ) - - authcert = get_authcert(issuer, authKeyID, X509_CA); - if (authcert == NULL) - { - plog("issuer cacert not found"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("issuer cacert found") - ) - - if (!certificate->issued_by(certificate, authcert->cert)) - { - plog("certificate signature is invalid"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate signature is valid") - ) - - /* check path length constraint */ - pathlen_constraint = x509->get_constraint(x509, X509_PATH_LEN); - if (pathlen_constraint != X509_NO_CONSTRAINT && - pathlen > pathlen_constraint) - { - plog("path length of %d violates constraint of %d", - pathlen, pathlen_constraint); - return FALSE; - } - - /* check if cert is self-signed */ - if (x509->get_flags(x509) & X509_SELF_SIGNED) - { - DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca with a path length of %d", - pathlen) - ) - unlock_authcert_list("valid_ocsp_response"); - return TRUE; - } - } - plog("maximum path length of %d exceeded", X509_MAX_PATH_LEN); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; -} - -/** - * Parse a basic OCSP response - */ -static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) -{ - asn1_parser_t *parser; - chunk_t object; - u_int version; - int objectID; - int extn_oid = OID_UNKNOWN; - bool success = FALSE; - bool critical; - - parser = asn1_parser_create(basicResponseObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case BASIC_RESPONSE_TBS_DATA: - res->tbs = object; - break; - case BASIC_RESPONSE_VERSION: - version = (object.len)? (1 + (u_int)*object.ptr) : 1; - if (version != OCSP_BASIC_RESPONSE_VERSION) - { - plog("wrong ocsp basic response version (version= %i)", version); - goto end; - } - break; - case BASIC_RESPONSE_ID_BY_NAME: - res->responder_id_name = identification_create_from_encoding( - ID_DER_ASN1_DN, object); - DBG(DBG_PARSING, - DBG_log(" '%Y'", res->responder_id_name) - ) - break; - case BASIC_RESPONSE_ID_BY_KEY: - res->responder_id_key = object; - break; - case BASIC_RESPONSE_PRODUCED_AT: - res->produced_at = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case BASIC_RESPONSE_RESPONSES: - res->responses = object; - break; - case BASIC_RESPONSE_EXT_ID: - extn_oid = asn1_known_oid(object); - break; - case BASIC_RESPONSE_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - break; - case BASIC_RESPONSE_EXT_VALUE: - if (extn_oid == OID_NONCE) - res->nonce = object; - break; - case BASIC_RESPONSE_ALGORITHM: - res->algorithm = asn1_parse_algorithmIdentifier(object, - parser->get_level(parser)+1, NULL); - break; - case BASIC_RESPONSE_SIGNATURE: - res->signature = object; - break; - case BASIC_RESPONSE_CERTIFICATE: - { - cert_t *cert = malloc_thing(cert_t); - x509_t *x509; - - *cert = cert_empty; - cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, object, - BUILD_END); - if (cert->cert == NULL) - { - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log("parsing of embedded ocsp certificate failed") - ) - cert_free(cert); - break; - } - x509 = (x509_t*)cert->cert; - - if ((x509->get_flags(x509) & X509_OCSP_SIGNER) && - trust_authcert_candidate(cert, NULL)) - { - add_authcert(cert, X509_OCSP_SIGNER); - } - else - { - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log("embedded ocsp certificate rejected") - ) - cert_free(cert); - } - } - break; - } - } - success = parser->success(parser); - -end: - parser->destroy(parser); - return success; - -} - - -/** - * Parse an ocsp response and return the result as a response_t struct - */ -static response_status parse_ocsp_response(chunk_t blob, response_t * res) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - int ocspResponseType = OID_UNKNOWN; - bool success = FALSE; - response_status rStatus = STATUS_INTERNALERROR; - - parser = asn1_parser_create(ocspResponseObjects, blob); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) { - case OCSP_RESPONSE_STATUS: - rStatus = (response_status) *object.ptr; - - switch (rStatus) - { - case STATUS_SUCCESSFUL: - break; - case STATUS_MALFORMEDREQUEST: - case STATUS_INTERNALERROR: - case STATUS_TRYLATER: - case STATUS_SIGREQUIRED: - case STATUS_UNAUTHORIZED: - plog("ocsp response: server said '%s'" - , response_status_names[rStatus]); - goto end; - default: - goto end; - } - break; - case OCSP_RESPONSE_TYPE: - ocspResponseType = asn1_known_oid(object); - break; - case OCSP_RESPONSE: - { - switch (ocspResponseType) { - case OID_BASIC: - success = parse_basic_ocsp_response(object, - parser->get_level(parser)+1, res); - break; - default: - DBG(DBG_CONTROL, - DBG_log("ocsp response is not of type BASIC"); - DBG_dump_chunk("ocsp response OID: ", object); - ) - goto end; - } - } - break; - } - } - success &= parser->success(parser); - -end: - parser->destroy(parser); - return rStatus; -} - -/** - * Parse a basic OCSP response - */ -static bool parse_ocsp_single_response(chunk_t blob, int level0, - single_response_t *sres) -{ - asn1_parser_t *parser; - chunk_t object; - u_int extn_oid; - int objectID; - bool critical; - bool success = FALSE; - - parser = asn1_parser_create(singleResponseObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case SINGLE_RESPONSE_ALGORITHM: - sres->hash_algorithm = asn1_parse_algorithmIdentifier(object, - parser->get_level(parser)+1, NULL); - break; - case SINGLE_RESPONSE_ISSUER_NAME_HASH: - sres->issuer_name_hash = object; - break; - case SINGLE_RESPONSE_ISSUER_KEY_HASH: - sres->issuer_key_hash = object; - break; - case SINGLE_RESPONSE_SERIAL_NUMBER: - sres->serialNumber = object; - break; - case SINGLE_RESPONSE_CERT_STATUS_GOOD: - sres->status = CERT_GOOD; - break; - case SINGLE_RESPONSE_CERT_STATUS_REVOKED: - sres->status = CERT_REVOKED; - break; - case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME: - sres->revocationTime = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON: - sres->revocationReason = (object.len == 1) - ? *object.ptr : CRL_REASON_UNSPECIFIED; - break; - case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN: - sres->status = CERT_UNKNOWN; - break; - case SINGLE_RESPONSE_THIS_UPDATE: - sres->thisUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_NEXT_UPDATE: - sres->nextUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_EXT_ID: - extn_oid = asn1_known_oid(object); - break; - case SINGLE_RESPONSE_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - case SINGLE_RESPONSE_EXT_VALUE: - break; - } - } - success = parser->success(parser); - parser->destroy(parser); - return success; -} - -/** - * Add an ocsp location to a chained list - */ -ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc, - ocsp_location_t **chain) -{ - ocsp_location_t *location = malloc_thing(ocsp_location_t); - - /* unshare location fields */ - location->issuer = loc->issuer->clone(loc->issuer); - location->authNameID = chunk_clone(loc->authNameID); - location->authKeyID = chunk_clone(loc->authKeyID); - location->uri = strdup(loc->uri); - location->certinfo = NULL; - - /* insert new ocsp location in front of chain */ - location->next = *chain; - *chain = location; - - DBG(DBG_CONTROL, - DBG_log("new ocsp location added") - ) - - return location; -} - -/** - * add a certinfo struct to a chained list - */ -void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, - ocsp_location_t **chain, bool request) -{ - ocsp_location_t *location; - ocsp_certinfo_t *certinfo, **certinfop; - char buf[BUF_LEN]; - time_t now; - int cmp = -1; - - location = get_ocsp_location(loc, *chain); - if (location == NULL) - { - location = add_ocsp_location(loc, chain); - } - - /* traverse list of certinfos in increasing order */ - certinfop = &location->certinfo; - certinfo = *certinfop; - - while (certinfo) - { - cmp = chunk_compare(info->serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; - certinfo = *certinfop; - } - - if (cmp != 0) - { - /* add a new certinfo entry */ - ocsp_certinfo_t *cnew = malloc_thing(ocsp_certinfo_t); - - cnew->serialNumber = chunk_clone(info->serialNumber); - cnew->next = certinfo; - cnew->trials = 0; - *certinfop = cnew; - certinfo = cnew; - } - - DBG(DBG_CONTROL, - datatot(info->serialNumber.ptr, info->serialNumber.len, ':' - , buf, BUF_LEN); - DBG_log("ocsp %s for serial %s %s" - , request?"fetch request":"certinfo" - , buf - , (cmp == 0)? (request?"already exists":"updated"):"added") - ) - - time(&now); - - if (request) - { - certinfo->status = CERT_UNDEFINED; - - if (cmp != 0) - { - certinfo->thisUpdate = now; - } - certinfo->nextUpdate = UNDEFINED_TIME; - } - else - { - certinfo->status = info->status; - certinfo->revocationTime = info->revocationTime; - certinfo->revocationReason = info->revocationReason; - - certinfo->thisUpdate = (info->thisUpdate != UNDEFINED_TIME)? - info->thisUpdate : now; - - certinfo->once = (info->nextUpdate == UNDEFINED_TIME); - - certinfo->nextUpdate = (certinfo->once)? - (now + OCSP_DEFAULT_VALID_TIME) : info->nextUpdate; - } -} - -/** - * Process received ocsp single response and add it to ocsp cache - */ -static void process_single_response(ocsp_location_t *location, - single_response_t *sres) -{ - ocsp_certinfo_t *certinfo, **certinfop; - int cmp = -1; - - if (sres->hash_algorithm != OID_SHA1) - { - plog("only SHA-1 hash supported in OCSP single response"); - return; - } - if (!(chunk_equals(sres->issuer_name_hash, location->authNameID) - && chunk_equals(sres->issuer_key_hash, location->authKeyID))) - { - plog("ocsp single response has wrong issuer"); - return; - } - - /* traverse list of certinfos in increasing order */ - certinfop = &location->certinfo; - certinfo = *certinfop; - - while (certinfo) - { - cmp = chunk_compare(sres->serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; - certinfo = *certinfop; - } - - if (cmp != 0) - { - plog("received unrequested cert status from ocsp server"); - return; - } - - /* unlink cert from ocsp fetch request list */ - *certinfop = certinfo->next; - - /* update certinfo using the single response information */ - certinfo->thisUpdate = sres->thisUpdate; - certinfo->nextUpdate = sres->nextUpdate; - certinfo->status = sres->status; - certinfo->revocationTime = sres->revocationTime; - certinfo->revocationReason = sres->revocationReason; - - /* add or update certinfo in ocsp cache */ - lock_ocsp_cache("process_single_response"); - add_certinfo(location, certinfo, &ocsp_cache, FALSE); - unlock_ocsp_cache("process_single_response"); - - /* free certinfo unlinked from ocsp fetch request list */ - free_certinfo(certinfo); -} - -/** - * Destroy a response_t object - */ -static void free_response(response_t *res) -{ - DESTROY_IF(res->responder_id_name); -} - -/** - * Parse and verify ocsp response and update the ocsp cache - */ -void parse_ocsp(ocsp_location_t *location, chunk_t blob) -{ - response_t res = empty_response; - - /* parse the ocsp response without looking at the single responses yet */ - response_status status = parse_ocsp_response(blob, &res); - - if (status != STATUS_SUCCESSFUL) - { - plog("error in ocsp response"); - goto free; - } - /* check if there was a nonce in the request */ - if (location->nonce.ptr && res.nonce.ptr == NULL) - { - plog("ocsp response contains no nonce, replay attack possible"); - } - /* check if the nonce is identical */ - if (res.nonce.ptr && !chunk_equals(res.nonce, location->nonce)) - { - plog("invalid nonce in ocsp response"); - goto free; - } - /* check if the response is signed by a trusted key */ - if (!valid_ocsp_response(&res)) - { - plog("invalid ocsp response"); - goto free; - } - DBG(DBG_CONTROL, - DBG_log("valid ocsp response") - ) - - /* now parse the single responses one at a time */ - { - asn1_parser_t *parser; - chunk_t object; - int objectID; - - parser = asn1_parser_create(responsesObjects, res.responses); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == RESPONSES_SINGLE_RESPONSE) - { - single_response_t sres = empty_single_response; - - if (!parse_ocsp_single_response(object, - parser->get_level(parser)+1, &sres)) - { - goto end; - } - process_single_response(location, &sres); - } - } -end: - parser->destroy(parser); - } - -free: - free_response(&res); -} diff --git a/src/pluto/ocsp.h b/src/pluto/ocsp.h deleted file mode 100644 index 977cca3c8..000000000 --- a/src/pluto/ocsp.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Support of the Online Certificate Status Protocol (OCSP) Support - * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen - * Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "constants.h" - -#include <credentials/certificates/crl.h> - -/* constants */ - -#define OCSP_BASIC_RESPONSE_VERSION 1 -#define OCSP_DEFAULT_VALID_TIME 120 /* validity of one-time response in seconds */ -#define OCSP_WARNING_INTERVAL 2 /* days */ - -/* OCSP response status */ - -typedef enum { - STATUS_SUCCESSFUL = 0, - STATUS_MALFORMEDREQUEST = 1, - STATUS_INTERNALERROR = 2, - STATUS_TRYLATER = 3, - STATUS_SIGREQUIRED = 5, - STATUS_UNAUTHORIZED= 6 -} response_status; - -/* OCSP access structures */ - -typedef struct ocsp_certinfo ocsp_certinfo_t; - -struct ocsp_certinfo { - ocsp_certinfo_t *next; - int trials; - chunk_t serialNumber; - cert_status_t status; - bool once; - crl_reason_t revocationReason; - time_t revocationTime; - time_t thisUpdate; - time_t nextUpdate; -}; - -typedef struct ocsp_location ocsp_location_t; - -struct ocsp_location { - ocsp_location_t *next; - identification_t *issuer; - chunk_t authNameID; - chunk_t authKeyID; - chunk_t nonce; - char *uri; - ocsp_certinfo_t *certinfo; -}; - -extern ocsp_location_t* get_ocsp_location(const ocsp_location_t *loc - , ocsp_location_t *chain); -extern ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc - , ocsp_location_t **chain); -extern void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info - , ocsp_location_t **chain, bool request); -extern void check_ocsp(void); -extern cert_status_t verify_by_ocsp(const cert_t *cert, time_t *until - , time_t *revocationTime, crl_reason_t *revocationReason); -extern bool ocsp_set_request_cert(char* path); -extern void ocsp_set_default_uri(char* uri); -extern void ocsp_cache_add_cert(const cert_t* cert); -extern chunk_t build_ocsp_request(ocsp_location_t* location); -extern void parse_ocsp(ocsp_location_t* location, chunk_t blob); -extern void list_ocsp_locations(ocsp_location_t *location, bool requests - , bool utc, bool strict); -extern void list_ocsp_cache(bool utc, bool strict); -extern void free_ocsp_locations(ocsp_location_t **chain); -extern void free_ocsp_cache(void); -extern void free_ocsp(void); -extern void ocsp_purge_cache(void); diff --git a/src/pluto/packet.c b/src/pluto/packet.c deleted file mode 100644 index 35fc4afcc..000000000 --- a/src/pluto/packet.c +++ /dev/null @@ -1,1242 +0,0 @@ -/* parsing packets: formats and tools - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <netinet/in.h> -#include <string.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "packet.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ - -/* ISAKMP Header: for all messages - * layout from RFC 2408 "ISAKMP" section 3.1 - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Initiator ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Responder ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Message ID ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -static field_desc isa_fields[] = { - { ft_raw, COOKIE_SIZE, "initiator cookie", NULL }, - { ft_raw, COOKIE_SIZE, "responder cookie", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_enum, 8/BITS_PER_BYTE, "ISAKMP version", &version_names }, - { ft_enum, 8/BITS_PER_BYTE, "exchange type", &exchange_names }, - { ft_set, 8/BITS_PER_BYTE, "flags", flag_bit_names }, - { ft_raw, 32/BITS_PER_BYTE, "message ID", NULL }, - { ft_len, 32/BITS_PER_BYTE, "length", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_hdr_desc = { "ISAKMP Message", isa_fields, sizeof(struct isakmp_hdr) }; - -/* Generic portion of all ISAKMP payloads. - * layout from RFC 2408 "ISAKMP" section 3.2 - * This describes the first 32-bit chunk of all payloads. - * The previous next payload depends on the actual payload type. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -static field_desc isag_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_generic_desc = { "ISAKMP Generic Payload", isag_fields, sizeof(struct isakmp_generic) }; - - -/* ISAKMP Data Attribute (generic representation within payloads) - * layout from RFC 2408 "ISAKMP" section 3.3 - * This is not a payload type. - * In TLV format, this is followed by a value field. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * !A! Attribute Type ! AF=0 Attribute Length ! - * !F! ! AF=1 Attribute Value ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . AF=0 Attribute Value . - * . AF=1 Not Transmitted . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -/* Oakley Attributes */ -static field_desc isaat_fields_oakley[] = { - { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &oakley_attr_names }, - { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_oakley_attribute_desc = { - "ISAKMP Oakley attribute", - isaat_fields_oakley, sizeof(struct isakmp_attribute) }; - -/* IPsec DOI Attributes */ -static field_desc isaat_fields_ipsec[] = { - { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &ipsec_attr_names }, - { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ipsec_attribute_desc = { - "ISAKMP IPsec DOI attribute", - isaat_fields_ipsec, sizeof(struct isakmp_attribute) }; - -/* Mode Config Attributes */ -static field_desc isaat_fields_modecfg[] = { - { ft_af_loose_enum, 16/BITS_PER_BYTE, "ModeCfg attr type", &modecfg_attr_names }, - { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_modecfg_attribute_desc = { - "ISAKMP ModeCfg attribute", - isaat_fields_modecfg, sizeof(struct isakmp_attribute) }; - -/* ISAKMP Security Association Payload - * layout from RFC 2408 "ISAKMP" section 3.4 - * A variable length Situation follows. - * Previous next payload: ISAKMP_NEXT_SA - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Situation ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isasa_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_sa_desc = { "ISAKMP Security Association Payload", isasa_fields, sizeof(struct isakmp_sa) }; - -static field_desc ipsec_sit_field[] = { - { ft_set, 32/BITS_PER_BYTE, "IPsec DOI SIT", &sit_bit_names }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc ipsec_sit_desc = { "IPsec DOI SIT", ipsec_sit_field, sizeof(u_int32_t) }; - -/* ISAKMP Proposal Payload - * layout from RFC 2408 "ISAKMP" section 3.5 - * A variable length SPI follows. - * Previous next payload: ISAKMP_NEXT_P - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! SPI (variable) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isap_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "proposal number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "protocol ID", &protocol_names }, - { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "number of transforms", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_proposal_desc = { "ISAKMP Proposal Payload", isap_fields, sizeof(struct isakmp_proposal) }; - -/* ISAKMP Transform Payload - * layout from RFC 2408 "ISAKMP" section 3.6 - * Variable length SA Attributes follow. - * Previous next payload: ISAKMP_NEXT_T - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Transform # ! Transform-Id ! RESERVED2 ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ SA Attributes ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -/* PROTO_ISAKMP */ -static field_desc isat_fields_isakmp[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &isakmp_transformid_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_isakmp_transform_desc = { - "ISAKMP Transform Payload (ISAKMP)", - isat_fields_isakmp, sizeof(struct isakmp_transform) }; - -/* PROTO_IPSEC_AH */ -static field_desc isat_fields_ah[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ah_transform_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ah_transform_desc = { - "ISAKMP Transform Payload (AH)", - isat_fields_ah, sizeof(struct isakmp_transform) }; - -/* PROTO_IPSEC_ESP */ -static field_desc isat_fields_esp[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &esp_transform_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_esp_transform_desc = { - "ISAKMP Transform Payload (ESP)", - isat_fields_esp, sizeof(struct isakmp_transform) }; - -/* PROTO_IPCOMP */ -static field_desc isat_fields_ipcomp[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ipcomp_transformid_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ipcomp_transform_desc = { - "ISAKMP Transform Payload (COMP)", - isat_fields_ipcomp, sizeof(struct isakmp_transform) }; - - -/* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.7 - * Variable Key Exchange Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_KE - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Key Exchange Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_keyex_desc = { "ISAKMP Key Exchange Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Identification Payload - * layout from RFC 2408 "ISAKMP" section 3.8 - * See "struct identity" declared later. - * Variable length Identification Data follow. - * Previous next payload: ISAKMP_NEXT_ID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! DOI Specific ID Data ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Identification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isaid_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, /* ??? depends on DOI? */ - { ft_nat, 8/BITS_PER_BYTE, "DOI specific A", NULL }, /* ??? depends on DOI? */ - { ft_nat, 16/BITS_PER_BYTE, "DOI specific B", NULL }, /* ??? depends on DOI? */ - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_identification_desc = { "ISAKMP Identification Payload", isaid_fields, sizeof(struct isakmp_id) }; - -/* IPSEC Identification Payload Content - * layout from RFC 2407 "IPsec DOI" section 4.6.2 - * See struct isakmp_id declared earlier. - * Note: Hashing skips the ISAKMP generic payload header - * Variable length Identification Data follow. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! Protocol ID ! Port ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Identification Data ~ - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isaiid_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, - { ft_nat, 8/BITS_PER_BYTE, "Protocol ID", NULL }, /* ??? UDP/TCP or 0? */ - { ft_nat, 16/BITS_PER_BYTE, "port", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ipsec_identification_desc = { "ISAKMP Identification Payload (IPsec DOI)", isaiid_fields, sizeof(struct isakmp_ipsec_id) }; - -/* ISAKMP Certificate Payload: oddball fixed field beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.9 - * Variable length Certificate Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_CERT. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert Encoding ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isacert_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "cert encoding", &cert_type_names }, - { ft_end, 0, NULL, NULL } -}; - -/* Note: the size field of isakmp_ipsec_certificate_desc cannot be - * sizeof(struct isakmp_cert) because that will rounded up for padding. - */ - struct_desc isakmp_ipsec_certificate_desc = { "ISAKMP Certificate Payload", isacert_fields, ISAKMP_CERT_SIZE }; - -/* ISAKMP Certificate Request Payload: oddball field beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.10 - * Variable length Certificate Types and Certificate Authorities follow. - * Previous next payload: ISAKMP_NEXT_CR. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert. Type ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Authority ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isacr_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "cert type", &cert_type_names }, - { ft_end, 0, NULL, NULL } -}; - -/* Note: the size field of isakmp_ipsec_cert_req_desc cannot be - * sizeof(struct isakmp_cr) because that will rounded up for padding. - */ -struct_desc isakmp_ipsec_cert_req_desc = { "ISAKMP Certificate RequestPayload", isacr_fields, ISAKMP_CR_SIZE }; - -/* ISAKMP Hash Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.11 - * Variable length Hash Data follow. - * Previous next payload: ISAKMP_NEXT_HASH. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Hash Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_hash_desc = { "ISAKMP Hash Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Signature Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.12 - * Variable length Signature Data follow. - * Previous next payload: ISAKMP_NEXT_SIG. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Signature Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_signature_desc = { "ISAKMP Signature Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Nonce Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.13 - * Variable length Nonce Data follow. - * Previous next payload: ISAKMP_NEXT_NONCE. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Nonce Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_nonce_desc = { "ISAKMP Nonce Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Notification Payload - * layout from RFC 2408 "ISAKMP" section 3.14 - * This is followed by a variable length SPI - * and then possibly by variable length Notification Data. - * Previous next payload: ISAKMP_NEXT_N - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-ID ! SPI Size ! Notify Message Type ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Notification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isan_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names }, - { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC, ESP, ... */ - { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL }, - { ft_enum, 16/BITS_PER_BYTE, "Notify Message Type", ¬ification_names }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_notification_desc = { "ISAKMP Notification Payload", isan_fields, sizeof(struct isakmp_notification) }; - -/* ISAKMP Delete Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length SPI. - * Previous next payload: ISAKMP_NEXT_D - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-Id ! SPI Size ! # of SPIs ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index(es) (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isad_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names }, - { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC */ - { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "number of SPIs", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_delete_desc = { "ISAKMP Delete Payload", isad_fields, sizeof(struct isakmp_delete) }; - -/* ISAKMP Vendor ID Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length VID. - * Previous next payload: ISAKMP_NEXT_VID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Vendor ID (VID) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_vendor_id_desc = { "ISAKMP Vendor ID Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* MODECFG */ -/* - * From draft-dukes-ike-mode-cfg -3.2. Attribute Payload - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Next Payload ! RESERVED ! Payload Length ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Type ! RESERVED ! Identifier ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! ! - ~ Attributes ~ - ! ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ -static field_desc isaattr_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "Attr Msg Type", &attr_msg_type_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Identifier", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_attr_desc = { "ISAKMP Mode Attribute", isaattr_fields, sizeof(struct isakmp_mode_attr) }; - -/* ISAKMP NAT-Traversal NAT-D - * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 3.2 - * - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! HASH of the address and port ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_nat_d = { "ISAKMP NAT-D Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP NAT-Traversal NAT-OA - * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 4.2 - * - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! RESERVED ! RESERVED ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! IPv4 (4 octets) or IPv6 address (16 octets) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isanat_oa_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, - { ft_mbz, 24/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof(struct isakmp_nat_oa) }; - -/* descriptor for each payload type - * - * There is a slight problem in that some payloads differ, depending - * on the mode. Since this is table only used for top-level payloads, - * Proposal and Transform payloads need not be handled. - * That leaves only Identification payloads as a problem. - * We make all these entries NULL - */ -struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = { - NULL, /* 0 ISAKMP_NEXT_NONE (No other payload following) */ - &isakmp_sa_desc, /* 1 ISAKMP_NEXT_SA (Security Association) */ - NULL, /* 2 ISAKMP_NEXT_P (Proposal) */ - NULL, /* 3 ISAKMP_NEXT_T (Transform) */ - &isakmp_keyex_desc, /* 4 ISAKMP_NEXT_KE (Key Exchange) */ - NULL, /* 5 ISAKMP_NEXT_ID (Identification) */ - &isakmp_ipsec_certificate_desc, /* 6 ISAKMP_NEXT_CERT (Certificate) */ - &isakmp_ipsec_cert_req_desc, /* 7 ISAKMP_NEXT_CR (Certificate Request) */ - &isakmp_hash_desc, /* 8 ISAKMP_NEXT_HASH (Hash) */ - &isakmp_signature_desc, /* 9 ISAKMP_NEXT_SIG (Signature) */ - &isakmp_nonce_desc, /* 10 ISAKMP_NEXT_NONCE (Nonce) */ - &isakmp_notification_desc, /* 11 ISAKMP_NEXT_N (Notification) */ - &isakmp_delete_desc, /* 12 ISAKMP_NEXT_D (Delete) */ - &isakmp_vendor_id_desc, /* 13 ISAKMP_NEXT_VID (Vendor ID) */ - &isakmp_attr_desc, /* 14 ISAKMP_NEXT_ATTR (Mode Config) */ - NULL, /* 15 */ - NULL, /* 16 */ - NULL, /* 17 */ - NULL, /* 18 */ - NULL, /* 19 */ - &isakmp_nat_d, /* 20=130 ISAKMP_NEXT_NATD (NAT-D) */ - &isakmp_nat_oa, /* 20=131 ISAKMP_NEXT_NATOA (NAT-OA) */ -}; - -void -init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name) -{ - pbs->container = NULL; - pbs->desc = NULL; - pbs->name = name; - pbs->start = pbs->cur = start; - pbs->roof = start + len; - pbs->lenfld = NULL; - pbs->lenfld_desc = NULL; -} - -#ifdef DEBUG - -/* print a host struct - * - * This code assumes that the network and host structure - * members have the same alignment and size! This requires - * that all padding be explicit. - */ -void -DBG_print_struct(const char *label, const void *struct_ptr -, struct_desc *sd, bool len_meaningful) -{ - bool immediate = FALSE; - const u_int8_t *inp = struct_ptr; - field_desc *fp; - - DBG_log("%s%s:", label, sd->name); - - for (fp = sd->fields; fp->field_type != ft_end; fp++) - { - int i = fp->size; - u_int32_t n = 0; - - switch (fp->field_type) - { - case ft_mbz: /* must be zero */ - inp += i; - break; - case ft_nat: /* natural number (may be 0) */ - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - case ft_set: /* bits representing set */ - switch (i) - { - case 8/BITS_PER_BYTE: - n = *(const u_int8_t *)inp; - break; - case 16/BITS_PER_BYTE: - n = *(const u_int16_t *)inp; - break; - case 32/BITS_PER_BYTE: - n = *(const u_int32_t *)inp; - break; - default: - bad_case(i); - } - switch (fp->field_type) - { - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - if (!immediate && !len_meaningful) - break; - /* FALL THROUGH */ - case ft_nat: /* natural number (may be 0) */ - DBG_log(" %s: %lu", fp->name, (unsigned long)n); - break; - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - /* FALL THROUGH */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - DBG_log(" %s: %s", fp->name, enum_show(fp->desc, n)); - break; - case ft_set: /* bits representing set */ - DBG_log(" %s: %s", fp->name, bitnamesof(fp->desc, n)); - break; - default: - bad_case(fp->field_type); - } - inp += i; - break; - - case ft_raw: /* bytes to be left in network-order */ - { - char m[50]; /* arbitrary limit on name width in log */ - - snprintf(m, sizeof(m), " %s:", fp->name); - DBG_dump(m, inp, i); - inp += i; - } - break; - default: - bad_case(fp->field_type); - } - } -} - -static void -DBG_prefix_print_struct(const pb_stream *pbs -, const char *label, const void *struct_ptr -, struct_desc *sd, bool len_meaningful) -{ - /* print out a title, with a prefix of asterisks to show - * the nesting level. - */ - char space[40]; /* arbitrary limit on label+flock-of-* */ - size_t len = strlen(label); - - if (sizeof(space) <= len) - { - DBG_print_struct(label, struct_ptr, sd, len_meaningful); - } - else - { - const pb_stream *p = pbs; - char *pre = &space[sizeof(space) - (len + 1)]; - - strcpy(pre, label); - - /* put at least one * out */ - for (;;) - { - if (pre <= space) - break; - *--pre = '*'; - if (p == NULL) - break; - p = p->container; - } - DBG_print_struct(pre, struct_ptr, sd, len_meaningful); - } -} - -#endif - -/* "parse" a network struct into a host struct. - * - * This code assumes that the network and host structure - * members have the same alignment and size! This requires - * that all padding be explicit. - * - * If obj_pbs is supplied, a new pb_stream is created for the - * variable part of the structure (this depends on their - * being one length field in the structure). The cursor of this - * new PBS is set to after the parsed part of the struct. - * - * This routine returns TRUE iff it succeeds. - */ - -bool -in_struct(void *struct_ptr, struct_desc *sd -, pb_stream *ins, pb_stream *obj_pbs) -{ - err_t ugh = NULL; - u_int8_t *cur = ins->cur; - - if (ins->roof - cur < (ptrdiff_t)sd->size) - { - ugh = builddiag("not enough room in input packet for %s", sd->name); - } - else - { - u_int8_t *roof = cur + sd->size; /* may be changed by a length field */ - u_int8_t *outp = struct_ptr; - bool immediate = FALSE; - field_desc *fp; - - for (fp = sd->fields; ugh == NULL; fp++) - { - size_t i = fp->size; - - passert(ins->roof - cur >= (ptrdiff_t)i); - passert(cur - ins->cur <= (ptrdiff_t)(sd->size - i)); - passert(outp - (cur - ins->cur) == struct_ptr); - -#if 0 - DBG(DBG_PARSING, DBG_log("%d %s" - , (int) (cur - ins->cur), fp->name == NULL? "" : fp->name)); -#endif - switch (fp->field_type) - { - case ft_mbz: /* must be zero */ - for (; i != 0; i--) - { - if (*cur++ != 0) - { - ugh = builddiag("byte %d of %s must be zero, but is not" - , (int) (cur - ins->cur), sd->name); - break; - } - *outp++ = '\0'; /* probably redundant */ - } - break; - - case ft_nat: /* natural number (may be 0) */ - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - case ft_set: /* bits representing set */ - { - u_int32_t n = 0; - - for (; i != 0; i--) - n = (n << BITS_PER_BYTE) | *cur++; - - switch (fp->field_type) - { - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - { - u_int32_t len = fp->field_type == ft_len? n - : immediate? sd->size : n + sd->size; - - if (len < sd->size) - { - ugh = builddiag("%s of %s is smaller than minimum" - , fp->name, sd->name); - } - else if (pbs_left(ins) < len) - { - ugh = builddiag("%s of %s is larger than can fit" - , fp->name, sd->name); - } - else - { - roof = ins->cur + len; - } - break; - } - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - break; - case ft_af_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - /* FALL THROUGH */ - case ft_enum: /* value from an enumeration */ - if (enum_name(fp->desc, n) == NULL) - { - ugh = builddiag("%s of %s has an unknown value: %lu" - , fp->name, sd->name, (unsigned long)n); - } - /* FALL THROUGH */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - break; - case ft_set: /* bits representing set */ - if (!testset(fp->desc, n)) - { - ugh = builddiag("bitset %s of %s has unknown member(s): %s" - , fp->name, sd->name, bitnamesof(fp->desc, n)); - } - break; - default: - break; - } - i = fp->size; - switch (i) - { - case 8/BITS_PER_BYTE: - *(u_int8_t *)outp = n; - break; - case 16/BITS_PER_BYTE: - *(u_int16_t *)outp = n; - break; - case 32/BITS_PER_BYTE: - *(u_int32_t *)outp = n; - break; - default: - bad_case(i); - } - outp += i; - break; - } - - case ft_raw: /* bytes to be left in network-order */ - for (; i != 0; i--) - { - *outp++ = *cur++; - } - break; - - case ft_end: /* end of field list */ - passert(cur == ins->cur + sd->size); - if (obj_pbs != NULL) - { - init_pbs(obj_pbs, ins->cur, roof - ins->cur, sd->name); - obj_pbs->container = ins; - obj_pbs->desc = sd; - obj_pbs->cur = cur; - } - ins->cur = roof; - DBG(DBG_PARSING - , DBG_prefix_print_struct(ins, "parse ", struct_ptr, sd, TRUE)); - return TRUE; - - default: - bad_case(fp->field_type); - } - } - } - - /* some failure got us here: report it */ - loglog(RC_LOG_SERIOUS, ugh); - return FALSE; -} - -bool -in_raw(void *bytes, size_t len, pb_stream *ins, const char *name) -{ - if (pbs_left(ins) < len) - { - loglog(RC_LOG_SERIOUS, "not enough bytes left to get %s from %s", name, ins->name); - return FALSE; - } - else - { - if (bytes == NULL) - { - DBG(DBG_PARSING - , DBG_log("skipping %u raw bytes of %s (%s)" - , (unsigned) len, ins->name, name); - DBG_dump(name, ins->cur, len)); - } - else - { - memcpy(bytes, ins->cur, len); - DBG(DBG_PARSING - , DBG_log("parsing %u raw bytes of %s into %s" - , (unsigned) len, ins->name, name); - DBG_dump(name, bytes, len)); - } - ins->cur += len; - return TRUE; - } -} - -/* "emit" a host struct into a network packet. - * - * This code assumes that the network and host structure - * members have the same alignment and size! This requires - * that all padding be explicit. - * - * If obj_pbs is non-NULL, its pbs describes a new output stream set up - * to contain the object. The cursor will be left at the variable part. - * This new stream must subsequently be finalized by close_output_pbs(). - * - * The value of any field of type ft_len is computed, not taken - * from the input struct. The length is actually filled in when - * the object's output stream is finalized. If obj_pbs is NULL, - * finalization is done by out_struct before it returns. - * - * This routine returns TRUE iff it succeeds. - */ - -bool -out_struct(const void *struct_ptr, struct_desc *sd -, pb_stream *outs, pb_stream *obj_pbs) -{ - err_t ugh = NULL; - const u_int8_t *inp = struct_ptr; - u_int8_t *cur = outs->cur; - - DBG(DBG_EMITTING - , DBG_prefix_print_struct(outs, "emit ", struct_ptr, sd, obj_pbs==NULL)); - - if (outs->roof - cur < (ptrdiff_t)sd->size) - { - ugh = builddiag("not enough room left in output packet to place %s" - , sd->name); - } - else - { - bool immediate = FALSE; - pb_stream obj; - field_desc *fp; - - obj.lenfld = NULL; /* until a length field is discovered */ - obj.lenfld_desc = NULL; - - for (fp = sd->fields; ugh == NULL; fp++) - { - size_t i = fp->size; - - passert(outs->roof - cur >= (ptrdiff_t)i); - passert(cur - outs->cur <= (ptrdiff_t)(sd->size - i)); - passert(inp - (cur - outs->cur) == struct_ptr); - -#if 0 - DBG(DBG_EMITTING, DBG_log("%d %s" - , (int) (cur - outs->cur), fp->name == NULL? "" : fp->name); -#endif - switch (fp->field_type) - { - case ft_mbz: /* must be zero */ - inp += i; - for (; i != 0; i--) - *cur++ = '\0'; - break; - case ft_nat: /* natural number (may be 0) */ - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - case ft_set: /* bits representing set */ - { - u_int32_t n = 0; - - switch (i) - { - case 8/BITS_PER_BYTE: - n = *(const u_int8_t *)inp; - break; - case 16/BITS_PER_BYTE: - n = *(const u_int16_t *)inp; - break; - case 32/BITS_PER_BYTE: - n = *(const u_int32_t *)inp; - break; - default: - bad_case(i); - } - - switch (fp->field_type) - { - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - if (immediate) - break; /* not a length */ - /* We can't check the length because it will likely - * be filled in after variable part is supplied. - * We do record where this is so that it can be - * filled in by a subsequent close_output_pbs(). - */ - passert(obj.lenfld == NULL); /* only one ft_len allowed */ - obj.lenfld = cur; - obj.lenfld_desc = fp; - break; - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - break; - case ft_af_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - /* FALL THROUGH */ - case ft_enum: /* value from an enumeration */ - if (enum_name(fp->desc, n) == NULL) - { - ugh = builddiag("%s of %s has an unknown value: %lu" - , fp->name, sd->name, (unsigned long)n); - } - /* FALL THROUGH */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - break; - case ft_set: /* bits representing set */ - if (!testset(fp->desc, n)) - { - ugh = builddiag("bitset %s of %s has unknown member(s): %s" - , fp->name, sd->name, bitnamesof(fp->desc, n)); - } - break; - default: - break; - } - - while (i-- != 0) - { - cur[i] = (u_int8_t)n; - n >>= BITS_PER_BYTE; - } - inp += fp->size; - cur += fp->size; - break; - } - case ft_raw: /* bytes to be left in network-order */ - for (; i != 0; i--) - *cur++ = *inp++; - break; - case ft_end: /* end of field list */ - passert(cur == outs->cur + sd->size); - - obj.container = outs; - obj.desc = sd; - obj.name = sd->name; - obj.start = outs->cur; - obj.cur = cur; - obj.roof = outs->roof; /* limit of possible */ - /* obj.lenfld and obj.lenfld_desc already set */ - - if (obj_pbs == NULL) - { - close_output_pbs(&obj); /* fill in length field, if any */ - } - else - { - /* We set outs->cur to outs->roof so that - * any attempt to output something into outs - * before obj is closed will trigger an error. - */ - outs->cur = outs->roof; - - *obj_pbs = obj; - } - return TRUE; - - default: - bad_case(fp->field_type); - } - } - } - - /* some failure got us here: report it */ - loglog(RC_LOG_SERIOUS, ugh); /* ??? serious, but errno not relevant */ - return FALSE; -} - -bool -out_generic(u_int8_t np, struct_desc *sd -, pb_stream *outs, pb_stream *obj_pbs) -{ - struct isakmp_generic gen; - - passert(sd->fields == isakmp_generic_desc.fields); - gen.isag_np = np; - return out_struct(&gen, sd, outs, obj_pbs); -} - -bool -out_generic_raw(u_int8_t np, struct_desc *sd -, pb_stream *outs, const void *bytes, size_t len, const char *name) -{ - pb_stream pbs; - - if (!out_generic(np, sd, outs, &pbs) - || !out_raw(bytes, len, &pbs, name)) - return FALSE; - close_output_pbs(&pbs); - return TRUE; -} - -bool -out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name) -{ - if (pbs_left(outs) < len) - { - loglog(RC_LOG_SERIOUS, "not enough room left to place %lu bytes of %s in %s" - , (unsigned long) len, name, outs->name); - return FALSE; - } - else - { - DBG(DBG_EMITTING - , DBG_log("emitting %u raw bytes of %s into %s" - , (unsigned) len, name, outs->name); - DBG_dump(name, bytes, len)); - memcpy(outs->cur, bytes, len); - outs->cur += len; - return TRUE; - } -} - -bool -out_zero(size_t len, pb_stream *outs, const char *name) -{ - if (pbs_left(outs) < len) - { - loglog(RC_LOG_SERIOUS, "not enough room left to place %s in %s", name, outs->name); - return FALSE; - } - else - { - DBG(DBG_EMITTING, DBG_log("emitting %u zero bytes of %s into %s" - , (unsigned) len, name, outs->name)); - memset(outs->cur, 0x00, len); - outs->cur += len; - return TRUE; - } -} - -/* Record current length. - * Note: currently, this may be repeated any number of times; - * the last one wins. - */ -void -close_output_pbs(pb_stream *pbs) -{ - if (pbs->lenfld != NULL) - { - u_int32_t len = pbs_offset(pbs); - int i = pbs->lenfld_desc->size; - - if (pbs->lenfld_desc->field_type == ft_lv) - len -= sizeof(struct isakmp_attribute); - DBG(DBG_EMITTING, DBG_log("emitting length of %s: %lu" - , pbs->name, (unsigned long) len)); - while (i-- != 0) - { - pbs->lenfld[i] = (u_int8_t)len; - len >>= BITS_PER_BYTE; - } - } - if (pbs->container != NULL) - pbs->container->cur = pbs->cur; /* pass space utilization up */ -} diff --git a/src/pluto/packet.h b/src/pluto/packet.h deleted file mode 100644 index 1510b81a0..000000000 --- a/src/pluto/packet.h +++ /dev/null @@ -1,653 +0,0 @@ -/* parsing packets: formats and tools - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _PACKET_H -#define _PACKET_H - -/* a struct_desc describes a structure for the struct I/O routines. - * This requires arrays of field_desc values to describe struct fields. - */ - -typedef const struct struct_desc { - const char *name; - const struct field_desc *fields; - size_t size; -} struct_desc; - -/* Note: if an ft_af_enum field has the ISAKMP_ATTR_AF_TV bit set, - * the subsequent ft_lv field will be interpreted as an immediate value. - * This matches how attributes are encoded. - * See RFC 2408 "ISAKMP" 3.3 - */ - -enum field_type { - ft_mbz, /* must be zero */ - ft_nat, /* natural number (may be 0) */ - ft_len, /* length of this struct and any following crud */ - ft_lv, /* length/value field of attribute */ - ft_enum, /* value from an enumeration */ - ft_loose_enum, /* value from an enumeration with only some names known */ - ft_af_loose_enum, /* Attribute Format + enumeration, some names known */ - ft_af_enum, /* Attribute Format + value from an enumeration */ - ft_set, /* bits representing set */ - ft_raw, /* bytes to be left in network-order */ - ft_end, /* end of field list */ -}; - -typedef const struct field_desc { - enum field_type field_type; - int size; /* size, in bytes, of field */ - const char *name; - const void *desc; /* enum_names for enum or char *[] for bits */ -} field_desc; - -/* The formatting of input and output of packets is done - * through packet_byte_stream objects. - * These describe a stream of bytes in memory. - * Several routines are provided to manipulate these objects - * Actual packet transfer is done elsewhere. - */ -typedef struct packet_byte_stream { - struct packet_byte_stream *container; /* PBS of which we are part */ - struct_desc *desc; - const char *name; /* what does this PBS represent? */ - u_int8_t - *start, - *cur, /* current position in stream */ - *roof; /* byte after last in PBS (actually just a limit on output) */ - /* For an output PBS, the length field will be filled in later so - * we need to record its particulars. Note: it may not be aligned. - */ - u_int8_t *lenfld; - field_desc *lenfld_desc; -} pb_stream; - -/* For an input PBS, pbs_offset is amount of stream processed. - * For an output PBS, pbs_offset is current size of stream. - * For an input PBS, pbs_room is size of stream. - * For an output PBS, pbs_room is maximum size allowed. - */ -#define pbs_offset(pbs) ((size_t)((pbs)->cur - (pbs)->start)) -#define pbs_room(pbs) ((size_t)((pbs)->roof - (pbs)->start)) -#define pbs_left(pbs) ((size_t)((pbs)->roof - (pbs)->cur)) - -extern void init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name); - -extern bool in_struct(void *struct_ptr, struct_desc *sd, - pb_stream *ins, pb_stream *obj_pbs); -extern bool in_raw(void *bytes, size_t len, pb_stream *ins, const char *name); - -extern bool out_struct(const void *struct_ptr, struct_desc *sd, - pb_stream *outs, pb_stream *obj_pbs); -extern bool out_generic(u_int8_t np, struct_desc *sd, - pb_stream *outs, pb_stream *obj_pbs); -extern bool out_generic_raw(u_int8_t np, struct_desc *sd, - pb_stream *outs, const void *bytes, size_t len, const char *name); -#define out_generic_chunk(np, sd, outs, ch, name) \ - out_generic_raw(np, sd, outs, (ch).ptr, (ch).len, name) -extern bool out_zero(size_t len, pb_stream *outs, const char *name); -extern bool out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name); -#define out_chunk(ch, outs, name) out_raw((ch).ptr, (ch).len, (outs), (name)) -extern void close_output_pbs(pb_stream *pbs); - -#ifdef DEBUG -extern void DBG_print_struct(const char *label, const void *struct_ptr, - struct_desc *sd, bool len_meaningful); -#endif - -/* ISAKMP Header: for all messages - * layout from RFC 2408 "ISAKMP" section 3.1 - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Initiator ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Responder ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Message ID ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * Although the drafts are a little unclear, there are a few - * places that specify that messages should be padded with 0x00 - * octets (bytes) to make the length a multiple of something. - * - * RFC 2408 "ISAKMP" 3.6 specifies that all messages will be - * padded to be a multiple of 4 octets in length. - * ??? This looks vestigial, and we ignore this requirement. - * - * RFC 2409 "IKE" Appedix B specifies: - * Each message should be padded up to the nearest block size - * using bytes containing 0x00. - * ??? This does not appear to be limited to encrypted messages, - * but it surely must be: the block size is meant to be the encryption - * block size, and that is meaningless for a non-encrypted message. - * - * RFC 2409 "IKE" 5.3 specifies: - * Encrypted payloads are padded up to the nearest block size. - * All padding bytes, except for the last one, contain 0x00. The - * last byte of the padding contains the number of the padding - * bytes used, excluding the last one. Note that this means there - * will always be padding. - * ??? This is nuts since payloads are not padded, messages are. - * It also contradicts Appendix B. So we ignore it. - * - * Summary: we pad encrypted output messages with 0x00 to bring them - * up to a multiple of the encryption block size. On input, we require - * that any encrypted portion of a message be a multiple of the encryption - * block size. After any decryption, we ignore padding (any bytes after - * the first payload that specifies a next payload of none; we don't - * require them to be zero). - */ - -struct isakmp_hdr -{ - u_int8_t isa_icookie[COOKIE_SIZE]; - u_int8_t isa_rcookie[COOKIE_SIZE]; - u_int8_t isa_np; /* Next payload */ - u_int8_t isa_version; /* high-order 4 bits: Major; low order 4: Minor */ -#define ISA_MAJ_SHIFT 4 -#define ISA_MIN_MASK (~((~0u) << ISA_MAJ_SHIFT)) - u_int8_t isa_xchg; /* Exchange type */ - u_int8_t isa_flags; - u_int32_t isa_msgid; /* Message ID (RAW) */ - u_int32_t isa_length; /* Length of message */ -}; - -extern struct_desc isakmp_hdr_desc; - -/* Generic portion of all ISAKMP payloads. - * layout from RFC 2408 "ISAKMP" section 3.2 - * This describes the first 32-bit chunk of all payloads. - * The previous next payload depends on the actual payload type. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_generic -{ - u_int8_t isag_np; - u_int8_t isag_reserved; - u_int16_t isag_length; -}; - -extern struct_desc isakmp_generic_desc; - -/* ISAKMP Data Attribute (generic representation within payloads) - * layout from RFC 2408 "ISAKMP" section 3.3 - * This is not a payload type. - * In TLV format, this is followed by a value field. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * !A! Attribute Type ! AF=0 Attribute Length ! - * !F! ! AF=1 Attribute Value ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . AF=0 Attribute Value . - * . AF=1 Not Transmitted . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_attribute -{ - /* The high order bit of isaat_af_type is the Attribute Format - * If it is off, the format is TLV: lv is the length of the following - * attribute value. - * If it is on, the format is TV: lv is the value of the attribute. - * ISAKMP_ATTR_AF_MASK is the mask in host form. - * - * The low order 15 bits of isaat_af_type is the Attribute Type. - * ISAKMP_ATTR_RTYPE_MASK is the mask in host form. - */ - u_int16_t isaat_af_type; /* high order bit: AF; lower 15: rtype */ - u_int16_t isaat_lv; /* Length or value */ -}; - -#define ISAKMP_ATTR_AF_MASK 0x8000 -#define ISAKMP_ATTR_AF_TV ISAKMP_ATTR_AF_MASK /* value in lv */ -#define ISAKMP_ATTR_AF_TLV 0 /* length in lv; value follows */ - -#define ISAKMP_ATTR_RTYPE_MASK 0x7FFF - -extern struct_desc - isakmp_oakley_attribute_desc, - isakmp_ipsec_attribute_desc; - -/* ISAKMP Security Association Payload - * layout from RFC 2408 "ISAKMP" section 3.4 - * A variable length Situation follows. - * Previous next payload: ISAKMP_NEXT_SA - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Situation ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_sa -{ - u_int8_t isasa_np; /* Next payload */ - u_int8_t isasa_reserved; - u_int16_t isasa_length; /* Payload length */ - u_int32_t isasa_doi; /* DOI */ -}; - -extern struct_desc isakmp_sa_desc; - -extern struct_desc ipsec_sit_desc; - -/* ISAKMP Proposal Payload - * layout from RFC 2408 "ISAKMP" section 3.5 - * A variable length SPI follows. - * Previous next payload: ISAKMP_NEXT_P - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! SPI (variable) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_proposal -{ - u_int8_t isap_np; - u_int8_t isap_reserved; - u_int16_t isap_length; - u_int8_t isap_proposal; - u_int8_t isap_protoid; - u_int8_t isap_spisize; - u_int8_t isap_notrans; /* Number of transforms */ -}; - -extern struct_desc isakmp_proposal_desc; - -/* ISAKMP Transform Payload - * layout from RFC 2408 "ISAKMP" section 3.6 - * Variable length SA Attributes follow. - * Previous next payload: ISAKMP_NEXT_T - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Transform # ! Transform-Id ! RESERVED2 ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ SA Attributes ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_transform -{ - u_int8_t isat_np; - u_int8_t isat_reserved; - u_int16_t isat_length; - u_int8_t isat_transnum; /* Number of the transform */ - u_int8_t isat_transid; - u_int16_t isat_reserved2; -}; - -extern struct_desc - isakmp_isakmp_transform_desc, - isakmp_ah_transform_desc, - isakmp_esp_transform_desc, - isakmp_ipcomp_transform_desc; - -/* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.7 - * Variable Key Exchange Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_KE - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Key Exchange Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_keyex_desc; - -/* ISAKMP Identification Payload - * layout from RFC 2408 "ISAKMP" section 3.8 - * See "struct identity" declared later. - * Variable length Identification Data follow. - * Previous next payload: ISAKMP_NEXT_ID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! DOI Specific ID Data ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Identification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_id -{ - u_int8_t isaid_np; - u_int8_t isaid_reserved; - u_int16_t isaid_length; - u_int8_t isaid_idtype; - u_int8_t isaid_doi_specific_a; - u_int16_t isaid_doi_specific_b; -}; - -extern struct_desc isakmp_identification_desc; - -/* IPSEC Identification Payload Content - * layout from RFC 2407 "IPsec DOI" section 4.6.2 - * See struct isakmp_id declared earlier. - * Note: Hashing skips the ISAKMP generic payload header - * Variable length Identification Data follow. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! Protocol ID ! Port ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Identification Data ~ - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_ipsec_id -{ - u_int8_t isaiid_np; - u_int8_t isaiid_reserved; - u_int16_t isaiid_length; - u_int8_t isaiid_idtype; - u_int8_t isaiid_protoid; - u_int16_t isaiid_port; -}; - -extern struct_desc isakmp_ipsec_identification_desc; - -/* ISAKMP Certificate Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.9 - * Variable length Certificate Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_CERT. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert Encoding ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_cert -{ - u_int8_t isacert_np; - u_int8_t isacert_reserved; - u_int16_t isacert_length; - u_int8_t isacert_type; -}; - -/* NOTE: this packet type has a fixed portion that is not a - * multiple of 4 octets. This means that sizeof(struct isakmp_cert) - * yields the wrong value for the length. - */ -#define ISAKMP_CERT_SIZE 5 - -extern struct_desc isakmp_ipsec_certificate_desc; - -/* ISAKMP Certificate Request Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.10 - * Variable length Certificate Types and Certificate Authorities follow. - * Previous next payload: ISAKMP_NEXT_CR. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert. Type ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Authority ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_cr -{ - u_int8_t isacr_np; - u_int8_t isacr_reserved; - u_int16_t isacr_length; - u_int8_t isacr_type; -}; - -/* NOTE: this packet type has a fixed portion that is not a - * multiple of 4 octets. This means that sizeof(struct isakmp_cr) - * yields the wrong value for the length. - */ -#define ISAKMP_CR_SIZE 5 - -extern struct_desc isakmp_ipsec_cert_req_desc; - -/* ISAKMP Hash Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.11 - * Variable length Hash Data follow. - * Previous next payload: ISAKMP_NEXT_HASH. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Hash Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_hash_desc; - -/* ISAKMP Signature Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.12 - * Variable length Signature Data follow. - * Previous next payload: ISAKMP_NEXT_SIG. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Signature Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_signature_desc; - -/* ISAKMP Nonce Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.13 - * Variable length Nonce Data follow. - * Previous next payload: ISAKMP_NEXT_NONCE. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Nonce Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_nonce_desc; - -/* ISAKMP Notification Payload - * layout from RFC 2408 "ISAKMP" section 3.14 - * This is followed by a variable length SPI - * and then possibly by variable length Notification Data. - * Previous next payload: ISAKMP_NEXT_N - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-ID ! SPI Size ! Notify Message Type ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Notification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_notification -{ - u_int8_t isan_np; - u_int8_t isan_reserved; - u_int16_t isan_length; - u_int32_t isan_doi; - u_int8_t isan_protoid; - u_int8_t isan_spisize; - u_int16_t isan_type; -}; - -extern struct_desc isakmp_notification_desc; - -/* ISAKMP Delete Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length SPI. - * Previous next payload: ISAKMP_NEXT_D - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-Id ! SPI Size ! # of SPIs ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index(es) (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_delete -{ - u_int8_t isad_np; - u_int8_t isad_reserved; - u_int16_t isad_length; - u_int32_t isad_doi; - u_int8_t isad_protoid; - u_int8_t isad_spisize; - u_int16_t isad_nospi; -}; - -extern struct_desc isakmp_delete_desc; - -/* From draft-dukes-ike-mode-cfg -3.2. Attribute Payload - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Next Payload ! RESERVED ! Payload Length ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Type ! RESERVED ! Identifier ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! ! - ! ! - ~ Attributes ~ - ! ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ -struct isakmp_mode_attr -{ - u_int8_t isama_np; - u_int8_t isama_reserved; - u_int16_t isama_length; - u_int8_t isama_type; - u_int8_t isama_reserved2; - u_int16_t isama_identifier; -}; - -extern struct_desc isakmp_attr_desc; -extern struct_desc isakmp_modecfg_attribute_desc; - -/* ISAKMP Vendor ID Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length VID. - * Previous next payload: ISAKMP_NEXT_VID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Vendor ID (VID) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_vendor_id_desc; - -struct isakmp_nat_oa -{ - u_int8_t isanoa_np; - u_int8_t isanoa_reserved_1; - u_int16_t isanoa_length; - u_int8_t isanoa_idtype; - u_int8_t isanoa_reserved_2; - u_int16_t isanoa_reserved_3; -}; - -extern struct_desc isakmp_nat_d; -extern struct_desc isakmp_nat_oa; - -/* union of all payloads */ - -union payload { - struct isakmp_generic generic; - struct isakmp_sa sa; - struct isakmp_proposal proposal; - struct isakmp_transform transform; - struct isakmp_id id; /* Main Mode */ - struct isakmp_cert cert; - struct isakmp_cr cr; - struct isakmp_ipsec_id ipsec_id; /* Quick Mode */ - struct isakmp_notification notification; - struct isakmp_delete delete; - struct isakmp_nat_oa nat_oa; - struct isakmp_mode_attr attribute; -}; - -/* descriptor for each payload type - * - * There is a slight problem in that some payloads differ, depending - * on the mode. Since this is table only used for top-level payloads, - * Proposal and Transform payloads need not be handled. - * That leaves only Identification payloads as a problem. - * We make all these entries NULL - */ -extern struct_desc *const payload_descs[ISAKMP_NEXT_ROOF]; - -#endif /* _PACKET_H */ diff --git a/src/pluto/pkcs7.c b/src/pluto/pkcs7.c deleted file mode 100644 index 10b2a4d5a..000000000 --- a/src/pluto/pkcs7.c +++ /dev/null @@ -1,755 +0,0 @@ -/* Support of PKCS#7 data structures - * Copyright (C) 2005 Jan Hutter, Martin Willi - * Copyright (C) 2002-2009 Andreas Steffen - * - * HSR Hochschule fuer Technik Rapperswil, Switzerland - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include <library.h> -#include <debug.h> -#include <asn1/asn1.h> -#include <asn1/asn1_parser.h> -#include <asn1/oid.h> -#include <crypto/rngs/rng.h> -#include <crypto/crypters/crypter.h> -#include <credentials/certificates/x509.h> - -#include "pkcs7.h" - -const contentInfo_t empty_contentInfo = { - OID_UNKNOWN , /* type */ - { NULL, 0 } /* content */ -}; - -/** - * ASN.1 definition of the PKCS#7 ContentInfo type - */ -static const asn1Object_t contentInfoObjects[] = { - { 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */ - { 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 2 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define PKCS7_INFO_TYPE 1 -#define PKCS7_INFO_CONTENT 2 - -/** - * ASN.1 definition of the PKCS#7 signedData type - */ -static const asn1Object_t signedDataObjects[] = { - { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ - { 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */ - { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */ - { 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */ - { 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */ - { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 6 */ - { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */ - { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */ - { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_LOOP }, /* 9 */ - { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ - { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */ - { 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */ - { 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */ - { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */ - { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */ - { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */ - { 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */ - { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 19 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ - { 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */ - { 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */ - { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */ - { 1, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define PKCS7_SIGNED_VERSION 1 -#define PKCS7_DIGEST_ALG 3 -#define PKCS7_SIGNED_CONTENT_INFO 5 -#define PKCS7_SIGNED_CERT 7 -#define PKCS7_SIGNER_INFO 13 -#define PKCS7_SIGNER_INFO_VERSION 14 -#define PKCS7_SIGNED_ISSUER 16 -#define PKCS7_SIGNED_SERIAL_NUMBER 17 -#define PKCS7_DIGEST_ALGORITHM 18 -#define PKCS7_AUTH_ATTRIBUTES 19 -#define PKCS7_DIGEST_ENC_ALGORITHM 21 -#define PKCS7_ENCRYPTED_DIGEST 22 - -/** - * ASN.1 definition of the PKCS#7 envelopedData type - */ -static const asn1Object_t envelopedDataObjects[] = { - { 0, "envelopedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ - { 1, "recipientInfos", ASN1_SET, ASN1_LOOP }, /* 2 */ - { 2, "recipientInfo", ASN1_SEQUENCE, ASN1_BODY }, /* 3 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 4 */ - { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */ - { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ - { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 7 */ - { 3, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 8 */ - { 3, "encryptedKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 9 */ - { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ - { 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ - { 2, "contentType", ASN1_OID, ASN1_BODY }, /* 12 */ - { 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 13 */ - { 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY }, /* 14 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define PKCS7_ENVELOPED_VERSION 1 -#define PKCS7_RECIPIENT_INFO_VERSION 4 -#define PKCS7_ISSUER 6 -#define PKCS7_SERIAL_NUMBER 7 -#define PKCS7_ENCRYPTION_ALG 8 -#define PKCS7_ENCRYPTED_KEY 9 -#define PKCS7_CONTENT_TYPE 12 -#define PKCS7_CONTENT_ENC_ALGORITHM 13 -#define PKCS7_ENCRYPTED_CONTENT 14 -#define PKCS7_ENVELOPED_ROOF 15 - -/** - * Parse PKCS#7 ContentInfo object - */ -bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, contentInfo_t *cInfo) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - bool success = FALSE; - - parser = asn1_parser_create(contentInfoObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == PKCS7_INFO_TYPE) - { - cInfo->type = asn1_known_oid(object); - if (cInfo->type < OID_PKCS7_DATA - || cInfo->type > OID_PKCS7_ENCRYPTED_DATA) - { - DBG1(DBG_LIB, "unknown pkcs7 content type"); - goto end; - } - } - else if (objectID == PKCS7_INFO_CONTENT) - { - cInfo->content = object; - } - } - success = parser->success(parser); - -end: - parser->destroy(parser); - return success; -} - -/** - * Parse a PKCS#7 signedData object - */ -bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, - linked_list_t *certs, - chunk_t *attributes, certificate_t *cacert) -{ - asn1_parser_t *parser; - chunk_t object; - int digest_alg = OID_UNKNOWN; - int enc_alg = OID_UNKNOWN; - int signerInfos = 0; - int version; - int objectID; - bool success = FALSE; - - contentInfo_t cInfo = empty_contentInfo; - chunk_t encrypted_digest = chunk_empty; - - if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) - { - return FALSE; - } - if (cInfo.type != OID_PKCS7_SIGNED_DATA) - { - DBG1(DBG_LIB, "pkcs7 content type is not signedData"); - return FALSE; - } - - parser = asn1_parser_create(signedDataObjects, cInfo.content); - parser->set_top_level(parser, 2); - - while (parser->iterate(parser, &objectID, &object)) - { - u_int level = parser->get_level(parser); - - switch (objectID) - { - case PKCS7_SIGNED_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - break; - case PKCS7_DIGEST_ALG: - digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case PKCS7_SIGNED_CONTENT_INFO: - if (data != NULL) - { - pkcs7_parse_contentInfo(object, level, data); - } - break; - case PKCS7_SIGNED_CERT: - { - certificate_t *cert; - - DBG2(DBG_LIB, " parsing pkcs7-wrapped certificate"); - cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, object, - BUILD_END); - if (cert) - { - certs->insert_last(certs, cert); - } - } - break; - case PKCS7_SIGNER_INFO: - signerInfos++; - DBG2(DBG_LIB, " signer #%d", signerInfos); - break; - case PKCS7_SIGNER_INFO_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - break; - case PKCS7_SIGNED_ISSUER: - { - identification_t *issuer = identification_create_from_encoding( - ID_DER_ASN1_DN, object); - DBG2(DBG_LIB, " \"%Y\"", issuer); - issuer->destroy(issuer); - break; - } - case PKCS7_AUTH_ATTRIBUTES: - if (attributes != NULL) - { - *attributes = object; - *attributes->ptr = ASN1_SET; - } - break; - case PKCS7_DIGEST_ALGORITHM: - digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case PKCS7_DIGEST_ENC_ALGORITHM: - enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case PKCS7_ENCRYPTED_DIGEST: - encrypted_digest = object; - } - } - success = parser->success(parser); - parser->destroy(parser); - if (!success) - { - return FALSE; - } - - /* check the signature only if a cacert is available */ - if (cacert != NULL) - { - public_key_t *key; - signature_scheme_t scheme; - - scheme = signature_scheme_from_oid(digest_alg); - if (scheme == SIGN_UNKNOWN) - { - DBG1(DBG_LIB, "unsupported signature scheme"); - return FALSE; - } - if (signerInfos == 0) - { - DBG1(DBG_LIB, "no signerInfo object found"); - return FALSE; - } - else if (signerInfos > 1) - { - DBG1(DBG_LIB, "more than one signerInfo object found"); - return FALSE; - } - if (attributes->ptr == NULL) - { - DBG1(DBG_LIB, "no authenticatedAttributes object found"); - return FALSE; - } - if (enc_alg != OID_RSA_ENCRYPTION) - { - DBG1(DBG_LIB, "only RSA digest encryption supported"); - return FALSE; - } - - /* verify the signature */ - key = cacert->get_public_key(cacert); - if (key == NULL) - { - DBG1(DBG_LIB, "no public key found in CA certificate"); - return FALSE; - } - if (key->verify(key, scheme, *attributes, encrypted_digest)) - { - DBG2(DBG_LIB, "signature is valid"); - } - else - { - DBG1(DBG_LIB, "invalid signature"); - success = FALSE; - } - key->destroy(key); - } - return success; -} - -/** - * Parse a PKCS#7 envelopedData object - */ -bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, - chunk_t serialNumber, - private_key_t *key) -{ - asn1_parser_t *parser; - chunk_t object; - chunk_t iv = chunk_empty; - chunk_t symmetric_key = chunk_empty; - chunk_t encrypted_content = chunk_empty; - - crypter_t *crypter = NULL; - - int enc_alg = OID_UNKNOWN; - int content_enc_alg = OID_UNKNOWN; - int version; - int objectID; - bool success = FALSE; - - contentInfo_t cInfo = empty_contentInfo; - *data = chunk_empty; - - if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) - { - goto failed; - } - if (cInfo.type != OID_PKCS7_ENVELOPED_DATA) - { - DBG1(DBG_LIB, "pkcs7 content type is not envelopedData"); - goto failed; - } - - parser = asn1_parser_create(envelopedDataObjects, cInfo.content); - parser->set_top_level(parser, 2); - - while (parser->iterate(parser, &objectID, &object)) - { - u_int level = parser->get_level(parser); - - switch (objectID) - { - case PKCS7_ENVELOPED_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - if (version != 0) - { - DBG1(DBG_LIB, "envelopedData version is not 0"); - goto end; - } - break; - case PKCS7_RECIPIENT_INFO_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - if (version != 0) - { - DBG1(DBG_LIB, "recipient info version is not 0"); - goto end; - } - break; - case PKCS7_ISSUER: - { - identification_t *issuer = identification_create_from_encoding( - ID_DER_ASN1_DN, object); - DBG2(DBG_LIB, " \"%Y\"", issuer); - issuer->destroy(issuer); - break; - } - case PKCS7_SERIAL_NUMBER: - if (!chunk_equals(serialNumber, object)) - { - DBG1(DBG_LIB, "serial numbers do not match"); - goto end; - } - break; - case PKCS7_ENCRYPTION_ALG: - enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - if (enc_alg != OID_RSA_ENCRYPTION) - { - DBG1(DBG_LIB, "only rsa encryption supported"); - goto end; - } - break; - case PKCS7_ENCRYPTED_KEY: - if (!key->decrypt(key, ENCRYPT_RSA_PKCS1, object, &symmetric_key)) - { - DBG1(DBG_LIB, "symmetric key could not be decrypted with rsa"); - goto end; - } - DBG4(DBG_LIB, "symmetric key %B", &symmetric_key); - break; - case PKCS7_CONTENT_TYPE: - if (asn1_known_oid(object) != OID_PKCS7_DATA) - { - DBG1(DBG_LIB, "encrypted content not of type pkcs7 data"); - goto end; - } - break; - case PKCS7_CONTENT_ENC_ALGORITHM: - content_enc_alg = asn1_parse_algorithmIdentifier(object, level, &iv); - - if (content_enc_alg == OID_UNKNOWN) - { - DBG1(DBG_LIB, "unknown content encryption algorithm"); - goto end; - } - if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV")) - { - DBG1(DBG_LIB, "IV could not be parsed"); - goto end; - } - break; - case PKCS7_ENCRYPTED_CONTENT: - encrypted_content = object; - break; - } - } - success = parser->success(parser); - -end: - parser->destroy(parser); - if (!success) - { - goto failed; - } - success = FALSE; - - /* decrypt the content */ - { - encryption_algorithm_t alg; - size_t key_size; - crypter_t *crypter; - - alg = encryption_algorithm_from_oid(content_enc_alg, &key_size); - if (alg == ENCR_UNDEFINED) - { - DBG1(DBG_LIB, "unsupported content encryption algorithm"); - goto failed; - } - crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size); - if (crypter == NULL) - { - DBG1(DBG_LIB, "crypter %N not available", encryption_algorithm_names, alg); - goto failed; - } - if (symmetric_key.len != crypter->get_key_size(crypter)) - { - DBG1(DBG_LIB, "symmetric key length %d is wrong", symmetric_key.len); - goto failed; - } - if (iv.len != crypter->get_iv_size(crypter)) - { - DBG1(DBG_LIB, "IV length %d is wrong", iv.len); - goto failed; - } - crypter->set_key(crypter, symmetric_key); - crypter->decrypt(crypter, encrypted_content, iv, data); - DBG4(DBG_LIB, "decrypted content with padding: %B", data); - } - - /* remove the padding */ - { - u_char *pos = data->ptr + data->len - 1; - u_char pattern = *pos; - size_t padding = pattern; - - if (padding > data->len) - { - DBG1(DBG_LIB, "padding greater than data length"); - goto failed; - } - data->len -= padding; - - while (padding-- > 0) - { - if (*pos-- != pattern) - { - DBG1(DBG_LIB, "wrong padding pattern"); - goto failed; - } - } - } - success = TRUE; - -failed: - DESTROY_IF(crypter); - chunk_clear(&symmetric_key); - if (!success) - { - free(data->ptr); - } - return success; -} - -/** - * @brief Builds a contentType attribute - * - * @return ASN.1 encoded contentType attribute - */ -chunk_t pkcs7_contentType_attribute(void) -{ - return asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_build_known_oid(OID_PKCS9_CONTENT_TYPE), - asn1_wrap(ASN1_SET, "m", - asn1_build_known_oid(OID_PKCS7_DATA))); -} - -/** - * @brief Builds a messageDigest attribute - * - * - * @param[in] blob content to create digest of - * @param[in] digest_alg digest algorithm to be used - * @return ASN.1 encoded messageDigest attribute - * - */ -chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg) -{ - chunk_t digest; - hash_algorithm_t hash_alg; - hasher_t *hasher; - - hash_alg = hasher_algorithm_from_oid(digest_alg); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - hasher->allocate_hash(hasher, content, &digest); - hasher->destroy(hasher); - - return asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_build_known_oid(OID_PKCS9_MESSAGE_DIGEST), - asn1_wrap(ASN1_SET, "m", - asn1_wrap(ASN1_OCTET_STRING, "m", digest))); -} - -/** - * build a DER-encoded contentInfo object - */ -static chunk_t pkcs7_build_contentInfo(contentInfo_t *cInfo) -{ - return (cInfo->content.ptr) ? - asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_build_known_oid(cInfo->type), - asn1_simple_object(ASN1_CONTEXT_C_0, cInfo->content)) : - asn1_build_known_oid(cInfo->type); -} - -/** - * build issuerAndSerialNumber object - */ -chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert) -{ - identification_t *issuer = cert->get_issuer(cert); - x509_t *x509 = (x509_t*)cert; - - return asn1_wrap(ASN1_SEQUENCE, "cm", - issuer->get_encoding(issuer), - asn1_integer("c", x509->get_serial(x509))); -} - -/** - * create a signed pkcs7 contentInfo object - */ -chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, - certificate_t *cert, int digest_alg, - private_key_t *key) -{ - contentInfo_t pkcs7Data, signedData; - chunk_t authenticatedAttributes = chunk_empty; - chunk_t encryptedDigest = chunk_empty; - chunk_t signerInfo, cInfo, signature, encoding = chunk_empty;; - signature_scheme_t scheme = signature_scheme_from_oid(digest_alg); - - if (attributes.ptr) - { - if (key->sign(key, scheme, attributes, &signature)) - { - encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature); - authenticatedAttributes = chunk_clone(attributes); - *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; - } - } - else if (data.ptr) - { - if (key->sign(key, scheme, data, &signature)) - { - encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature); - } - } - signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm" - , ASN1_INTEGER_1 - , pkcs7_build_issuerAndSerialNumber(cert) - , asn1_algorithmIdentifier(digest_alg) - , authenticatedAttributes - , asn1_algorithmIdentifier(OID_RSA_ENCRYPTION) - , encryptedDigest); - - pkcs7Data.type = OID_PKCS7_DATA; - pkcs7Data.content = (data.ptr == NULL)? chunk_empty - : asn1_simple_object(ASN1_OCTET_STRING, data); - - cert->get_encoding(cert, CERT_ASN1_DER, &encoding); - signedData.type = OID_PKCS7_SIGNED_DATA; - signedData.content = asn1_wrap(ASN1_SEQUENCE, "cmmmm" - , ASN1_INTEGER_1 - , asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_alg)) - , pkcs7_build_contentInfo(&pkcs7Data) - , asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding) - , asn1_wrap(ASN1_SET, "m", signerInfo)); - - cInfo = pkcs7_build_contentInfo(&signedData); - DBG3(DBG_LIB, "signedData %B", &cInfo); - - free(pkcs7Data.content.ptr); - free(signedData.content.ptr); - return cInfo; -} - -/** - * create a symmetrically encrypted pkcs7 contentInfo object - */ -chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, int enc_alg) -{ - encryption_algorithm_t alg; - size_t alg_key_size; - chunk_t symmetricKey, protectedKey, iv, in, out; - crypter_t *crypter; - - alg = encryption_algorithm_from_oid(enc_alg, &alg_key_size); - crypter = lib->crypto->create_crypter(lib->crypto, alg, - alg_key_size/BITS_PER_BYTE); - if (crypter == NULL) - { - DBG1(DBG_LIB, "crypter for %N not available", encryption_algorithm_names, alg); - return chunk_empty; - } - - /* generate a true random symmetric encryption key and a pseudo-random iv */ - { - rng_t *rng; - - rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE); - rng->allocate_bytes(rng, crypter->get_key_size(crypter), &symmetricKey); - DBG4(DBG_LIB, "symmetric encryption key %B", &symmetricKey); - rng->destroy(rng); - - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->allocate_bytes(rng, crypter->get_iv_size(crypter), &iv); - DBG4(DBG_LIB, "initialization vector: %B", &iv); - rng->destroy(rng); - } - - /* pad the data to a multiple of the block size */ - { - size_t block_size = crypter->get_block_size(crypter); - size_t padding = block_size - data.len % block_size; - - in.len = data.len + padding; - in.ptr = malloc(in.len); - - DBG2(DBG_LIB, "padding %u bytes of data to multiple block size of %u bytes", - data.len, in.len); - - /* copy data */ - memcpy(in.ptr, data.ptr, data.len); - /* append padding */ - memset(in.ptr + data.len, padding, padding); - } - DBG3(DBG_LIB, "padded unencrypted data %B", &in); - - /* symmetric encryption of data object */ - crypter->set_key(crypter, symmetricKey); - crypter->encrypt(crypter, in, iv, &out); - crypter->destroy(crypter); - chunk_clear(&in); - DBG3(DBG_LIB, "encrypted data %B", &out); - - /* protect symmetric key by public key encryption */ - { - public_key_t *key = cert->get_public_key(cert); - - if (key == NULL) - { - DBG1(DBG_LIB, "public key not found in encryption certificate"); - chunk_clear(&symmetricKey); - chunk_free(&iv); - chunk_free(&out); - return chunk_empty; - } - key->encrypt(key, ENCRYPT_RSA_PKCS1, symmetricKey, &protectedKey); - key->destroy(key); - } - - /* build pkcs7 enveloped data object */ - { - - chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm" - , asn1_build_known_oid(enc_alg) - , asn1_simple_object(ASN1_OCTET_STRING, iv)); - - chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "mmm" - , asn1_build_known_oid(OID_PKCS7_DATA) - , contentEncryptionAlgorithm - , asn1_wrap(ASN1_CONTEXT_S_0, "m", out)); - - chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m" - , protectedKey); - - chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmmm" - , ASN1_INTEGER_0 - , pkcs7_build_issuerAndSerialNumber(cert) - , asn1_algorithmIdentifier(OID_RSA_ENCRYPTION) - , encryptedKey); - - chunk_t cInfo; - contentInfo_t envelopedData; - - envelopedData.type = OID_PKCS7_ENVELOPED_DATA; - envelopedData.content = asn1_wrap(ASN1_SEQUENCE, "cmm" - , ASN1_INTEGER_0 - , asn1_wrap(ASN1_SET, "m", recipientInfo) - , encryptedContentInfo); - - cInfo = pkcs7_build_contentInfo(&envelopedData); - DBG3(DBG_LIB, "envelopedData %B", &cInfo); - - chunk_free(&envelopedData.content); - chunk_free(&iv); - chunk_clear(&symmetricKey); - return cInfo; - } -} diff --git a/src/pluto/pkcs7.h b/src/pluto/pkcs7.h deleted file mode 100644 index 1743ea9c4..000000000 --- a/src/pluto/pkcs7.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Support of PKCS#7 data structures - * Copyright (C) 2005 Jan Hutter, Martin Willi - * Copyright (C) 2002-2009 Andreas Steffen - * - * Hochschule fuer Technik Rapperswil, Switzerland - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _PKCS7_H -#define _PKCS7_H - -#include <utils/linked_list.h> -#include <crypto/crypters/crypter.h> -#include <credentials/keys/private_key.h> -#include <credentials/certificates/certificate.h> - -/* Access structure for a PKCS#7 ContentInfo object */ - -typedef struct contentInfo contentInfo_t; - -struct contentInfo { - int type; - chunk_t content; -}; - -extern const contentInfo_t empty_contentInfo; - -extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, - contentInfo_t *cInfo); -extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, - linked_list_t *cert, chunk_t *attributes, - certificate_t *cacert); -extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, - chunk_t serialNumber, private_key_t *key); -extern chunk_t pkcs7_contentType_attribute(void); -extern chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg); -extern chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert); -extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, - certificate_t *cert, int digest_alg, - private_key_t *key); -extern chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, - int enc_alg); - -#endif /* _PKCS7_H */ diff --git a/src/pluto/plugin_list.c b/src/pluto/plugin_list.c deleted file mode 100644 index 499218904..000000000 --- a/src/pluto/plugin_list.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2011 Martin Willi, revosec AG - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <whack.h> -#include <log.h> - -#include <library.h> -#include <utils/linked_list.h> - -/** - * List loaded plugin information - */ -void plugin_list(void) -{ - plugin_feature_t *features, *fp; - enumerator_t *enumerator; - linked_list_t *list; - plugin_t *plugin; - int count, i; - bool loaded; - char *str; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of loaded Plugins:"); - whack_log(RC_COMMENT, " "); - - enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); - while (enumerator->enumerate(enumerator, &plugin, &list)) - { - whack_log(RC_COMMENT, "%s:", plugin->get_name(plugin)); - if (plugin->get_features) - { - count = plugin->get_features(plugin, &features); - for (i = 0; i < count; i++) - { - str = plugin_feature_get_string(&features[i]); - switch (features[i].kind) - { - case FEATURE_PROVIDE: - fp = &features[i]; - loaded = list->find_first(list, NULL, - (void**)&fp) == SUCCESS; - whack_log(RC_COMMENT, " %s%s", - str, loaded ? "" : " (not loaded)"); - break; - case FEATURE_DEPENDS: - whack_log(RC_COMMENT, " %s", str); - break; - case FEATURE_SDEPEND: - whack_log(RC_COMMENT, " %s(soft)", str); - break; - default: - break; - } - free(str); - } - } - } - enumerator->destroy(enumerator); -} diff --git a/src/pluto/plugin_list.h b/src/pluto/plugin_list.h deleted file mode 100644 index 62e4a167d..000000000 --- a/src/pluto/plugin_list.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Generates a list of all loaded plugins and their dependencies - * Copyright (C) 2011 Andreas Steffen - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _PLUGIN_LIST_H -#define _PLUGIN_LIST_H - -extern void plugin_list(void); - -#endif /* _PLUGIN_LIST_H */ diff --git a/src/pluto/plugins/xauth/Makefile.am b/src/pluto/plugins/xauth/Makefile.am deleted file mode 100644 index 354325b35..000000000 --- a/src/pluto/plugins/xauth/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ - -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ - -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/whack \ - -I$(top_srcdir)/src/pluto - -AM_CFLAGS = -rdynamic - -plugin_LTLIBRARIES = libstrongswan-xauth.la - -libstrongswan_xauth_la_SOURCES = \ - xauth_plugin.h xauth_plugin.c \ - xauth_default_provider.c xauth_default_provider.h \ - xauth_default_verifier.c xauth_default_verifier.h - -libstrongswan_xauth_la_LDFLAGS = -module -avoid-version diff --git a/src/pluto/plugins/xauth/Makefile.in b/src/pluto/plugins/xauth/Makefile.in deleted file mode 100644 index 5a575548e..000000000 --- a/src/pluto/plugins/xauth/Makefile.in +++ /dev/null @@ -1,603 +0,0 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = src/pluto/plugins/xauth -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ - $(top_srcdir)/m4/config/ltoptions.m4 \ - $(top_srcdir)/m4/config/ltsugar.m4 \ - $(top_srcdir)/m4/config/ltversion.m4 \ - $(top_srcdir)/m4/config/lt~obsolete.m4 \ - $(top_srcdir)/m4/macros/with.m4 \ - $(top_srcdir)/m4/macros/enable-disable.m4 \ - $(top_srcdir)/m4/macros/add-plugin.m4 \ - $(top_srcdir)/configure.in -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__installdirs = "$(DESTDIR)$(plugindir)" -LTLIBRARIES = $(plugin_LTLIBRARIES) -libstrongswan_xauth_la_LIBADD = -am_libstrongswan_xauth_la_OBJECTS = xauth_plugin.lo \ - xauth_default_provider.lo xauth_default_verifier.lo -libstrongswan_xauth_la_OBJECTS = $(am_libstrongswan_xauth_la_OBJECTS) -libstrongswan_xauth_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libstrongswan_xauth_la_LDFLAGS) $(LDFLAGS) -o $@ -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ -SOURCES = $(libstrongswan_xauth_la_SOURCES) -DIST_SOURCES = $(libstrongswan_xauth_la_SOURCES) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALLOCA = @ALLOCA@ -AMTAR = @AMTAR@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BTLIB = @BTLIB@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLIB = @DLLIB@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GPERF = @GPERF@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LEX = @LEX@ -LEXLIB = @LEXLIB@ -LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -MYSQLCFLAG = @MYSQLCFLAG@ -MYSQLCONFIG = @MYSQLCONFIG@ -MYSQLLIB = @MYSQLLIB@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PERL = @PERL@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PTHREADLIB = @PTHREADLIB@ -RANLIB = @RANLIB@ -RTLIB = @RTLIB@ -RUBY = @RUBY@ -RUBYINCLUDE = @RUBYINCLUDE@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -SOCKLIB = @SOCKLIB@ -STRIP = @STRIP@ -VERSION = @VERSION@ -YACC = @YACC@ -YFLAGS = @YFLAGS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -attest_plugins = @attest_plugins@ -axis2c_CFLAGS = @axis2c_CFLAGS@ -axis2c_LIBS = @axis2c_LIBS@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -c_plugins = @c_plugins@ -clearsilver_LIBS = @clearsilver_LIBS@ -datadir = @datadir@ -datarootdir = @datarootdir@ -dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -gtk_CFLAGS = @gtk_CFLAGS@ -gtk_LIBS = @gtk_LIBS@ -h_plugins = @h_plugins@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -imcvdir = @imcvdir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -ipsecdir = @ipsecdir@ -ipsecgroup = @ipsecgroup@ -ipseclibdir = @ipseclibdir@ -ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ -libdir = @libdir@ -libexecdir = @libexecdir@ -linux_headers = @linux_headers@ -localedir = @localedir@ -localstatedir = @localstatedir@ -lt_ECHO = @lt_ECHO@ -maemo_CFLAGS = @maemo_CFLAGS@ -maemo_LIBS = @maemo_LIBS@ -manager_plugins = @manager_plugins@ -mandir = @mandir@ -medsrv_plugins = @medsrv_plugins@ -mkdir_p = @mkdir_p@ -nm_CFLAGS = @nm_CFLAGS@ -nm_LIBS = @nm_LIBS@ -nm_ca_dir = @nm_ca_dir@ -oldincludedir = @oldincludedir@ -openac_plugins = @openac_plugins@ -p_plugins = @p_plugins@ -pcsclite_CFLAGS = @pcsclite_CFLAGS@ -pcsclite_LIBS = @pcsclite_LIBS@ -pdfdir = @pdfdir@ -piddir = @piddir@ -pki_plugins = @pki_plugins@ -plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ -pool_plugins = @pool_plugins@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -random_device = @random_device@ -resolv_conf = @resolv_conf@ -routing_table = @routing_table@ -routing_table_prio = @routing_table_prio@ -s_plugins = @s_plugins@ -sbindir = @sbindir@ -scepclient_plugins = @scepclient_plugins@ -scripts_plugins = @scripts_plugins@ -sharedstatedir = @sharedstatedir@ -soup_CFLAGS = @soup_CFLAGS@ -soup_LIBS = @soup_LIBS@ -srcdir = @srcdir@ -starter_plugins = @starter_plugins@ -strongswan_conf = @strongswan_conf@ -sysconfdir = @sysconfdir@ -systemdsystemunitdir = @systemdsystemunitdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -urandom_device = @urandom_device@ -xml_CFLAGS = @xml_CFLAGS@ -xml_LIBS = @xml_LIBS@ -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ - -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/whack \ - -I$(top_srcdir)/src/pluto - -AM_CFLAGS = -rdynamic -plugin_LTLIBRARIES = libstrongswan-xauth.la -libstrongswan_xauth_la_SOURCES = \ - xauth_plugin.h xauth_plugin.c \ - xauth_default_provider.c xauth_default_provider.h \ - xauth_default_verifier.c xauth_default_verifier.h - -libstrongswan_xauth_la_LDFLAGS = -module -avoid-version -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pluto/plugins/xauth/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/pluto/plugins/xauth/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): -install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) - @$(NORMAL_INSTALL) - test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" - @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ - } - -uninstall-pluginLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ - done - -clean-pluginLTLIBRARIES: - -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) - @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -libstrongswan-xauth.la: $(libstrongswan_xauth_la_OBJECTS) $(libstrongswan_xauth_la_DEPENDENCIES) - $(libstrongswan_xauth_la_LINK) -rpath $(plugindir) $(libstrongswan_xauth_la_OBJECTS) $(libstrongswan_xauth_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_default_provider.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_default_verifier.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_plugin.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LTLIBRARIES) -installdirs: - for dir in "$(DESTDIR)$(plugindir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ - mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-pluginLTLIBRARIES - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-pluginLTLIBRARIES - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ - clean-libtool clean-pluginLTLIBRARIES ctags distclean \ - distclean-compile distclean-generic distclean-libtool \ - distclean-tags distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-pluginLTLIBRARIES \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags uninstall uninstall-am uninstall-pluginLTLIBRARIES - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/pluto/plugins/xauth/xauth_default_provider.c b/src/pluto/plugins/xauth/xauth_default_provider.c deleted file mode 100644 index 77c5facc4..000000000 --- a/src/pluto/plugins/xauth/xauth_default_provider.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <keys.h> - -#include "xauth_default_provider.h" - -typedef struct private_xauth_default_provider_t private_xauth_default_provider_t; - -/** - * private data of xauth_default_provider - */ -struct private_xauth_default_provider_t { - - /** - * public functions - */ - xauth_provider_t public; -}; - -METHOD(xauth_provider_t, get_secret, bool, - private_xauth_default_provider_t *this, connection_t *c, chunk_t *secret) -{ - identification_t *user, *server; - - server = c->spd.that.id; - user = (c->xauth_identity) ? c->xauth_identity : c->spd.this.id; - - return get_xauth_secret(user, server, secret); -} - -METHOD(xauth_provider_t, destroy, void, - private_xauth_default_provider_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -xauth_provider_t *xauth_default_provider_create() -{ - private_xauth_default_provider_t *this; - - INIT(this, - .public = { - .get_secret = _get_secret, - .destroy = _destroy, - } - ); - - return &this->public; -} - diff --git a/src/pluto/plugins/xauth/xauth_default_provider.h b/src/pluto/plugins/xauth/xauth_default_provider.h deleted file mode 100644 index ff1a91d16..000000000 --- a/src/pluto/plugins/xauth/xauth_default_provider.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_default_provider xauth_default_provider - * @{ @ingroup xauth - */ - -#ifndef XAUTH_DEFAULT_PROVIDER_H_ -#define XAUTH_DEFAULT_PROVIDER_H_ - -#include <xauth/xauth_provider.h> - - -/** - * Create an xauth_default_provider instance. - */ -xauth_provider_t *xauth_default_provider_create(); - -#endif /** XAUTH_DEFAULT_PROVIDER_H_ @}*/ - diff --git a/src/pluto/plugins/xauth/xauth_default_verifier.c b/src/pluto/plugins/xauth/xauth_default_verifier.c deleted file mode 100644 index ca2e36aa0..000000000 --- a/src/pluto/plugins/xauth/xauth_default_verifier.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <keys.h> - -#include "xauth_default_verifier.h" - -typedef struct private_xauth_default_verifier_t private_xauth_default_verifier_t; - -/** - * private data of xauth_default_verifier - */ -struct private_xauth_default_verifier_t { - - /** - * public functions - */ - xauth_verifier_t public; -}; - -METHOD(xauth_verifier_t, verify_secret, bool, - private_xauth_default_verifier_t *this, connection_t *c, chunk_t secret) -{ - identification_t *user, *server; - chunk_t xauth_secret; - bool success = FALSE; - - server = c->spd.this.id; - user = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id; - - if (get_xauth_secret(user, server, &xauth_secret)) - { - success = chunk_equals(secret, xauth_secret); - - if (!success && secret.len && secret.ptr[secret.len - 1] == 0) - { /* fix for null-terminated passwords (e.g. from Android 4) */ - secret.len--; - success = chunk_equals(secret, xauth_secret); - } - - chunk_clear(&xauth_secret); - } - return success; -} - -METHOD(xauth_verifier_t, destroy, void, - private_xauth_default_verifier_t *this) -{ - free(this); -} - - -/* - * Described in header. - */ -xauth_verifier_t *xauth_default_verifier_create() -{ - private_xauth_default_verifier_t *this; - - INIT(this, - .public = { - .verify_secret = _verify_secret, - .destroy = _destroy, - } - ); - - return &this->public; -} - diff --git a/src/pluto/plugins/xauth/xauth_default_verifier.h b/src/pluto/plugins/xauth/xauth_default_verifier.h deleted file mode 100644 index e5814d7b4..000000000 --- a/src/pluto/plugins/xauth/xauth_default_verifier.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_default_verifier xauth_default_verifier - * @{ @ingroup xauth - */ - -#ifndef XAUTH_DEFAULT_VERIFIER_H_ -#define XAUTH_DEFAULT_VERIFIER_H_ - -#include <xauth/xauth_verifier.h> - - -/** - * Create an xauth_default_verifier instance. - */ -xauth_verifier_t *xauth_default_verifier_create(); - -#endif /** XAUTH_DEFAULT_VERIFIER_H_ @}*/ - diff --git a/src/pluto/plugins/xauth/xauth_plugin.c b/src/pluto/plugins/xauth/xauth_plugin.c deleted file mode 100644 index bfc4820ed..000000000 --- a/src/pluto/plugins/xauth/xauth_plugin.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <pluto.h> - -#include "xauth_plugin.h" -#include "xauth_default_provider.h" -#include "xauth_default_verifier.h" - -METHOD(plugin_t, get_name, char*, - xauth_plugin_t *this) -{ - return "xauth"; -} - -METHOD(plugin_t, destroy, void, - xauth_plugin_t *this) -{ - free(this); -} - -/* - * see header file - */ -plugin_t *xauth_plugin_create() -{ - xauth_plugin_t *this; - - INIT(this, - .plugin = { - .get_name = _get_name, - .reload = (void*)return_false, - .destroy = _destroy, - }, - ); - - pluto->xauth->add_provider(pluto->xauth, xauth_default_provider_create()); - pluto->xauth->add_verifier(pluto->xauth, xauth_default_verifier_create()); - - return &this->plugin; -} - diff --git a/src/pluto/plugins/xauth/xauth_plugin.h b/src/pluto/plugins/xauth/xauth_plugin.h deleted file mode 100644 index 4f14828d2..000000000 --- a/src/pluto/plugins/xauth/xauth_plugin.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth xauth - * @ingroup pplugins - * - * @defgroup xauth_plugin xauth_plugin - * @{ @ingroup xauth - */ - -#ifndef XAUTH_PLUGIN_H_ -#define XAUTH_PLUGIN_H_ - -#include <plugins/plugin.h> - -typedef struct xauth_plugin_t xauth_plugin_t; - -/** - * XAUTH plugin - */ -struct xauth_plugin_t { - - /** - * implements plugin interface - */ - plugin_t plugin; -}; - -#endif /** XAUTH_PLUGIN_H_ @}*/ diff --git a/src/pluto/pluto.8 b/src/pluto/pluto.8 deleted file mode 100644 index ed6f78050..000000000 --- a/src/pluto/pluto.8 +++ /dev/null @@ -1,1594 +0,0 @@ -.TH IPSEC_PLUTO 8 "28 March 1999" -.SH NAME -pluto \- IPsec IKE keying daemon and control interface -.PP -whack \- control interface for IKE keying daemon -.SH SYNOPSIS -.na -.nh -.HP -.ft B -ipsec pluto -[\-\-help] -[\-\-version] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-nofork] -[\-\-stderrlog] -[\-\-uniqueids] -[\fB\-\-interface\fP \fIinterfacename\fP] -[\-\-ikeport\ \c -\fIportnumber\fP] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-secretsfile\ \c -\fIsecrets\(hyfile\fP] -[\-\-adns \fIpathname\fP] -[\-\-lwdnsq \fIpathname\fP] -[\-\-perpeerlog] -[\-\-perpeerlogbase\ \c -\fIdirname\fP] -[\-\-debug\(hynone] -[\-\-debug\(hyall] -[\-\-debug\(hyraw] -[\-\-debug\(hycrypt] -[\-\-debug\(hyparsing] -[\-\-debug\(hyemitting] -[\-\-debug\(hycontrol] -[\-\-debug\(hylifecycle] -[\-\-debug\(hykernel] -[\-\-debug\(hydns] -[\-\-debug\(hyoppo] -[\-\-debug\(hyprivate] -.HP -.ft B -ipsec whack -[\-\-help] -[\-\-version] -.HP -.ft B -ipsec whack -\-\-name\ \c -\fIconnection-name\fP -.br -[\-\-id\ \c -\fIid\fP] \c -[\-\-host\ \c -\fIip\(hyaddress\fP] -[\-\-ikeport\ \c -\fIport\(hynumber\fP] -[\-\-nexthop\ \c -\fIip\(hyaddress\fP] -[\-\-client\ \c -\fIsubnet\fP] -[\-\-dnskeyondemand] -[\-\-updown\ \c -\fIupdown\fP] -.br -\-\-to -.br -[\-\-id\ \c -\fIid\fP] -[\-\-host\ \c -\fIip\(hyaddress\fP] -[\-\-ikeport\ \c -\fIport\(hynumber\fP] -[\-\-nexthop\ \c -\fIip\(hyaddress\fP] -[\-\-client\ \c -\fIsubnet\fP] -[\-\-dnskeyondemand] -[\-\-updown\ \c -\fIupdown\fP] -.br -[\-\-psk] -[\-\-rsasig] -[\-\-encrypt] -[\-\-authenticate] -[\-\-compress] -[\-\-tunnel] -[\-\-pfs] -[\-\-disablearrivalcheck] -[\-\-ipv4] -[\-\-ipv6] -[\-\-tunnelipv4] -[\-\-tunnelipv6] -[\-\-ikelifetime\ \c -\fIseconds\fP] -[\-\-ipseclifetime\ \c -\fIseconds\fP] -[\-\-rekeymargin\ \c -\fIseconds\fP] -[\-\-rekeyfuzz\ \c -\fIpercentage\fP] -[\-\-keyingtries\ \c -\fIcount\fP] -[\-\-dontrekey] -[\-\-delete] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-keyid\ \c -\fIid\fP -[\-\-addkey] -[\-\-pubkeyrsa\ \c -\fIkey\fP] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-myid\ \c -\fIid\fP -.HP -.ft B -ipsec whack -\-\-listen|\-\-unlisten -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-route|\-\-unroute -\-\-name\ \c -\fIconnection-name\fP -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-initiate|\-\-terminate -\-\-name\ \c -\fIconnection-name\fP -[\-\-asynchronous] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -[\-\-tunnelipv4] -[\-\-tunnelipv6] -\-\-oppohere \fIip\(hyaddress\fP -\-\-oppothere \fIip\(hyaddress\fP -.HP -.ft B -ipsec whack -\-\-delete -\-\-name\ \c -\fIconnection-name\fP -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-deletestate\ \c -\fIstate-number\fP -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -[\-\-name\ \c -\fIconnection-name\fP] -[\-\-debug\(hynone] -[\-\-debug\(hyall] -[\-\-debug\(hyraw] -[\-\-debug\(hycrypt] -[\-\-debug\(hyparsing] -[\-\-debug\(hyemitting] -[\-\-debug\(hycontrol] -[\-\-debug\(hylifecycle] -[\-\-debug\(hykernel] -[\-\-debug\(hydns] -[\-\-debug\(hyoppo] -[\-\-debug\(hyprivate] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-status -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-shutdown -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.ft R -.hy -.ad -.SH DESCRIPTION -.BR pluto -is an IKE (``IPsec Key Exchange'') daemon. -.BR whack -is an auxiliary program to allow requests to be made to a running -.BR pluto . -.LP -.BR pluto -is used to automatically build shared ``security associations'' on a -system that has IPsec, the secure IP protocol. -In other words, -.BR pluto -can eliminate much of the work of manual keying. -The actual -secure transmission of packets is the responsibility of the Linux kernel. -\fIipsec_auto\fP(8) provides a more convenient interface to -\fBpluto\fP and \fBwhack\fP. -.SS IKE's Job -.LP -A \fISecurity Association\fP (\fISA\fP) is an agreement between two network nodes on -how to process certain traffic between them. This processing involves -encapsulation, authentication, encryption, or compression. -.LP -IKE can be deployed on a network node to negotiate Security -Associations for that node. These IKE implementations can only -negotiate with other IKE implementations, so IKE must be on each node -that is to be an endpoint of an IKE-negotiated Security Association. -No other nodes need to be running IKE. -.LP -An IKE instance (i.e. an IKE implementation on a particular network -node) communicates with another IKE instance using UDP IP packets, so -there must be a route between the nodes in each direction. -.LP -The negotiation of Security Associations requires a number of choices -that involve tradeoffs between security, convenience, trust, and -efficiency. These are policy issues and are normally specified to the -IKE instance by the system administrator. -.LP -IKE deals with two kinds of Security Associations. The first part of -a negotiation between IKE instances is to build an ISAKMP SA. An -ISAKMP SA is used to protect communication between the two IKEs. -IPsec SAs can then be built by the IKEs \- these are used to carry -protected IP traffic between the systems. -.LP -The negotiation of the ISAKMP SA is known as Phase 1. In theory, -Phase 1 can be accomplished by a couple of different exchange types, -but we only implement one called Main Mode (we don't implement -Aggressive Mode). -.LP -Any negotiation under the protection of an ISAKMP SA, including the -negotiation of IPsec SAs, is part of Phase 2. The exchange type -that we use to negotiate an IPsec SA is called Quick Mode. -.LP -IKE instances must be able to authenticate each other as part of their -negotiation of an ISAKMP SA. This can be done by several mechanisms -described in the draft standards. -.LP -IKE negotiation can be initiated by any instance with any other. If -both can find an agreeable set of characteristics for a Security -Association, and both recognize each others authenticity, they can set -up a Security Association. The standards do not specify what causes -an IKE instance to initiate a negotiation. -.LP -In summary, an IKE instance is prepared to automate the management of -Security Associations in an IPsec environment, but a number of issues -are considered policy and are left in the system administrator's hands. -.SS Pluto -.LP -\fBpluto\fP is an implementation of IKE. It runs as a daemon on a network -node. Currently, this network node must be a Linux 2.6 system running the -native \fBNETKEY\fP IPsec stack. -.LP -\fBpluto\fP only implements a subset of IKE. This is enough for it to -interoperate with other instances of \fBpluto\fP, and many other IKE -implementations. We are working on implementing more of IKE. -.LP -The policy for acceptable characteristics for Security Associations is -mostly hardwired into the code of \fBpluto\fP (spdb.c). Eventually -this will be moved into a security policy database with reasonable -expressive power and more convenience. -.LP -\fBpluto\fP uses shared secrets or RSA signatures to authenticate -peers with whom it is negotiating. -.LP -\fBpluto\fP initiates negotiation of a Security Association when it is -manually prodded: the program \fBwhack\fP is run to trigger this. -It will also initiate a negotiation when the Linux kernel traps an outbound -packet for Opportunistic Encryption. -.LP -\fBpluto\fP implements ISAKMP SAs itself. After it has negotiated the -characteristics of an IPsec SA, it directs the Linux kernel to implement it. -It also invokes a script to adjust any firewall and issue \fIroute\fP(8) -commands. -.LP -When \fBpluto\fP shuts down, it closes all Security Associations. -.SS Before Running Pluto -.LP -\fBpluto\fP runs as a daemon with userid root. Before running it, a few -things must be set up. -.LP -\fBpluto\fP requires a Linux 2.6 kernel with the modules for the native IPsec -stack enabled. -.LP -\fBpluto\fP supports multiple public networks (that is, networks -that are considered insecure and thus need to have their traffic -encrypted or authenticated). It discovers the -public interfaces to use by looking at all interfaces that are -configured (the \fB\-\-interface\fP option can be used to limit -the interfaces considered). -It does this only when \fBwhack\fP tells it to \-\-listen, -so the interfaces must be configured by then. -\fIifconfig\fP(8) with the \fB\-a\fP flag will show -the name and status of each network interface. -.LP -\fBpluto\fP requires a database of preshared secrets and RSA private keys. -This is described in the -.IR ipsec.secrets (5). -\fBpluto\fP is told of RSA public keys via \fBwhack\fP commands. -If the connection is Opportunistic, and no RSA public key is known, -\fBpluto\fP will attempt to fetch RSA keys using the Domain Name System. -.SS ipsec.secrets file -.LP -A \fBpluto\fP daemon and another IKE daemon (for example, another instance -of \fBpluto\fP) must convince each other that they are who they are supposed -to be before any negotiation can succeed. This authentication is -accomplished by using either secrets that have been shared beforehand -(manually) or by using RSA signatures. There are other techniques, -but they have not been implemented in \fBpluto\fP. -.LP -The file \fI/etc/ipsec.secrets\fP is used to keep preshared secret keys -and RSA private keys for -authentication with other IKE daemons. For debugging, there is an -argument to the \fBpluto\fP command to use a different file. -This file is described in -.IR ipsec.secrets (5). -.SS Running Pluto -.LP -To fire up the daemon, just type \fBpluto\fP (be sure to be running as -the superuser). -The default IKE port number is 500, the UDP port assigned by IANA for IKE Daemons. -\fBpluto\fP must be run by the superuser to be able to use the UDP 500 port. -.LP -\fBpluto\fP attempts to create a lockfile with the name -\fI/var/run/pluto.pid\fP. If the lockfile cannot be created, -\fBpluto\fP exits \- this prevents multiple \fBpluto\fPs from -competing Any ``leftover'' lockfile must be removed before -\fBpluto\fP will run. \fBpluto\fP writes its pid into this file so -that scripts can find it. This lock will not function properly if it -is on an NFS volume (but sharing locks on multiple machines doesn't -make sense anyway). -.LP -\fBpluto\fP then forks and the parent exits. This is the conventional -``daemon fork''. It can make debugging awkward, so there is an option -to suppress this fork. -.LP -All logging, including diagnostics, is sent to -.IR syslog (3) -with facility=authpriv; -it decides where to put these messages (possibly in /var/log/secure). -Since this too can make debugging awkward, there is an option to -steer logging to stderr. -.LP -If the \fB\-\-perpeerlog\fP option is given, then pluto will open -a log file per connection. By default, this is in /var/log/pluto/peer, -in a subdirectory formed by turning all dot (.) [IPv4} or colon (:) -[IPv6] into slashes (/). -.LP -The base directory can be changed with the \fB\-\-perpeerlogbase\fP. -.LP -Once \fBpluto\fP is started, it waits for requests from \fBwhack\fP. -.SS Pluto's Internal State -.LP -To understand how to use \fBpluto\fP, it is helpful to understand a little -about its internal state. Furthermore, the terminology is needed to decipher -some of the diagnostic messages. -.LP -The \fI(potential) connection\fP database describes attributes of a -connection. These include the IP addresses of the hosts and client -subnets and the security characteristics desired. \fBpluto\fP -requires this information (simply called a connection) before it can -respond to a request to build an SA. Each connection is given a name -when it is created, and all references are made using this name. -.LP -During the IKE exchange to build an SA, the information about the -negotiation is represented in a \fIstate object\fP. Each state object -reflects how far the negotiation has reached. Once the negotiation is -complete and the SA established, the state object remains to represent -the SA. When the SA is terminated, the state object is discarded. -Each State object is given a serial number and this is used to refer -to the state objects in logged messages. -.LP -Each state object corresponds to a connection and can be thought of -as an instantiation of that connection. -At any particular time, there may be any number of state objects -corresponding to a particular connection. -Often there is one representing an ISAKMP SA and another representing -an IPsec SA. -.LP -Each connection may be routed, and must be while it has an IPsec SA. -The connection specifies the characteristics of the route: the -interface on this machine, the ``gateway'' (the nexthop), -and the peer's client subnet. Two -connections may not be simultaneously routed if they are for the same -peer's client subnet but use different interfaces or gateways -(\fBpluto\fP's logic does not reflect any advanced routing capabilities). -.LP -Each eroute is associated with the state object for an IPsec SA -because it has the particular characteristics of the SA. -Two eroutes conflict if they specify the identical local -and remote clients (unlike for routes, the local clients are -taken into account). -.LP -When \fBpluto\fP needs to install a route for a connection, -it must make sure that no conflicting route is in use. If another -connection has a conflicting route, that route will be taken down, as long -as there is no IPsec SA instantiating that connection. -If there is such an IPsec SA, the attempt to install a route will fail. -.LP -There is an exception. If \fBpluto\fP, as Responder, needs to install -a route to a fixed client subnet for a connection, and there is -already a conflicting route, then the SAs using the route are deleted -to make room for the new SAs. The rationale is that the new -connection is probably more current. The need for this usually is a -product of Road Warrior connections (these are explained later; they -cannot be used to initiate). -.LP -When \fBpluto\fP needs to install an eroute for an IPsec SA (for a -state object), first the state object's connection must be routed (if -this cannot be done, the eroute and SA will not be installed). -If a conflicting eroute is already in place for another connection, -the eroute and SA will not be installed (but note that the routing -exception mentioned above may have already deleted potentially conflicting SAs). -If another IPsec -SA for the same connection already has an eroute, all its outgoing traffic -is taken over by the new eroute. The incoming traffic will still be -processed. This characteristic is exploited during rekeying. -.LP -Some of these routing characteristics are specific to \fBKLIPS\fP, the FreeS/WAN -implementation of IPsec and are not relevant when running pluto on the native -Linux 2.6 IPsec stack. -.SS Using Whack -.LP -\fBwhack\fP is used to command a running \fBpluto\fP. -\fBwhack\fP uses a UNIX domain socket to speak to \fBpluto\fP -(by default, \fI/var/pluto.ctl\fP). -.LP -\fBwhack\fP has an intricate argument syntax. -This syntax allows many different functions to be specified. -The help form shows the usage or version information. -The connection form gives \fBpluto\fP a description of a potential connection. -The public key form informs \fBpluto\fP of the RSA public key for a potential peer. -The delete form deletes a connection description and all SAs corresponding -to it. -The listen form tells \fBpluto\fP to start or stop listening on the public interfaces -for IKE requests from peers. -The route form tells \fBpluto\fP to set up routing for a connection; -the unroute form undoes this. -The initiate form tells \fBpluto\fP to negotiate an SA corresponding to a connection. -The terminate form tells \fBpluto\fP to remove all SAs corresponding to a connection, -including those being negotiated. -The status form displays the \fBpluto\fP's internal state. -The debug form tells \fBpluto\fP to change the selection of debugging output -``on the fly''. The shutdown form tells -\fBpluto\fP to shut down, deleting all SAs. -.LP -Most options are specific to one of the forms, and will be described -with that form. There are three options that apply to all forms. -.TP -\fB\-\-ctlbase\fP\ \fIpath\fP -\fIpath\fP.ctl is used as the UNIX domain socket for talking -to \fBpluto\fP. -This option facilitates debugging. -.TP -\fB\-\-optionsfrom\fP\ \fIfilename\fP -adds the contents of the file to the argument list. -.TP -\fB\-\-label\fP\ \fIstring\fP -adds the string to all error messages generated by \fBwhack\fP. -.LP -The help form of \fBwhack\fP is self-explanatory. -.TP -\fB\-\-help\fP -display the usage message. -.TP -\fB\-\-version\fP -display the version of \fBwhack\fP. -.LP -The connection form describes a potential connection to \fBpluto\fP. -\fBpluto\fP needs to know what connections can and should be negotiated. -When \fBpluto\fP is the initiator, it needs to know what to propose. -When \fBpluto\fP is the responder, it needs to know enough to decide whether -is is willing to set up the proposed connection. -.LP -The description of a potential connection can specify a large number -of details. Each connection has a unique name. This name will appear -in a updown shell command, so it should not contain punctuation -that would make the command ill-formed. -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The topology of -a connection is symmetric, so to save space here is half a picture: - -\ \ \ client_subnet<\-\->host:ikeport<\-\->nexthop<\-\-\- - -A similar trick is used in the flags. The same flag names are used for -both ends. Those before the \fB\-\-to\fP flag describe the left side -and those afterwards describe the right side. When \fBpluto\fP attempts -to use the connection, it decides whether it is the left side or the right -side of the connection, based on the IP numbers of its interfaces. -.TP -\fB\-\-id\fP\ \fIid\fP -the identity of the end. Currently, this can be an IP address (specified -as dotted quad or as a Fully Qualified Domain Name, which will be resolved -immediately) or as a Fully Qualified Domain Name itself (prefixed by ``@'' -to signify that it should not be resolved), or as user@FQDN, or as the -magic value \fB%myid\fP. -\fBPluto\fP only authenticates the identity, and does not use it for -addressing, so, for example, an IP address need not be the one to which -packets are to be sent. If the option is absent, the -identity defaults to the IP address specified by \fB\-\-host\fP. -\fB%myid\fP allows the identity to be separately specified (by the \fBpluto\fP or \fBwhack\fP option \fB\-\-myid\fP -or by the \fBipsec.conf\fP(5) \fBconfig setup\fP parameter \fPmyid\fP). -Otherwise, \fBpluto\fP tries to guess what \fB%myid\fP should stand for: -the IP address of \fB%defaultroute\fP, if it is supported by a suitable TXT record in the reverse domain for that IP address, -or the system's hostname, if it is supported by a suitable TXT record in its forward domain. -.\" The identity is transmitted in the IKE protocol, and is what is authenticated. -.TP -\fB\-\-host\fP\ \fIip\(hyaddress\fP -.TP -\fB\-\-host\fP\ \fB%any\fP -.TP -\fB\-\-host\fP\ \fB%opportunistic\fP -the IP address of the end (generally the public interface). -If \fBpluto\fP is to act as a responder -for IKE negotiations initiated from unknown IP addresses (the -``Road Warrior'' case), the -IP address should be specified as \fB%any\fP (currently, -the obsolete notation \fB0.0.0.0\fP is also accepted for this). -If \fBpluto\fP is to opportunistically initiate the connection, -use \fB%opportunistic\fP -.TP -\fB\-\-ikeport\fP\ \fIport\(hynumber\fP -the UDP port that IKE listens to on that host. The default is 500. -(\fBpluto\fP on this machine uses the port specified by its own command -line argument, so this only affects where \fBpluto\fP sends messages.) -.TP -\fB\-\-nexthop\fP\ \fIip\(hyaddress\fP -where to route packets for the peer's client (presumably for the peer too, -but it will not be used for this). -When \fBpluto\fP installs an IPsec SA, it issues a route command. -It uses the nexthop as the gateway. -The default is the peer's IP address (this can be explicitly written as -\fB%direct\fP; the obsolete notation \fB0.0.0.0\fP is accepted). -This option is necessary if \fBpluto\fP's host's interface used for sending -packets to the peer is neither point-to-point nor directly connected to the -peer. -.TP -\fB\-\-client\fP\ \fIsubnet\fP -the subnet for which the IPsec traffic will be destined. If not specified, -the host will be the client. -The subnet can be specified in any of the forms supported by \fIipsec_atosubnet\fP(3). -The general form is \fIaddress\fP/\fImask\fP. The \fIaddress\fP can be either -a domain name or four decimal numbers (specifying octets) separated by dots. -The most convenient form of the \fImask\fP is a decimal integer, specifying -the number of leading one bits in the mask. So, for example, 10.0.0.0/8 -would specify the class A network ``Net 10''. -.TP -\fB\-\-dnskeyondemand]\fP -specifies that when an RSA public key is needed to authenticate this -host, and it isn't already known, fetch it from DNS. -.TP -\fB\-\-updown\fP\ \fIupdown\fP -specifies an external shell command to be run whenever \fBpluto\fP -brings up or down a connection. -The script is used to build a shell command, so it may contain positional -parameters, but ought not to have punctuation that would cause the -resulting command to be ill-formed. -The default is \fIipsec _updown\fP. -.TP -\fB\-\-to\fP -separates the specification of the left and right ends of the connection. -.LP -The potential connection description also specifies characteristics of -rekeying and security. -.TP -\fB\-\-psk\fP -Propose and allow preshared secret authentication for IKE peers. This authentication -requires that each side use the same secret. May be combined with \fB\-\-rsasig\fP; -at least one must be specified. -.TP -\fB\-\-rsasig\fP -Propose and allow RSA signatures for authentication of IKE peers. This authentication -requires that each side have have a private key of its own and know the -public key of its peer. May be combined with \fB\-\-psk\fP; -at least one must be specified. -.TP -\fB\-\-encrypt\fP -All proposed or accepted IPsec SAs will include non-null ESP. -The actual choices of transforms are wired into \fBpluto\fP. -.TP -\fB\-\-authenticate\fP -All proposed IPsec SAs will include AH. -All accepted IPsec SAs will include AH or ESP with authentication. -The actual choices of transforms are wired into \fBpluto\fP. -Note that this has nothing to do with IKE authentication. -.TP -\fB\-\-compress\fP -All proposed IPsec SAs will include IPCOMP (compression). -This will be ignored if the kernel is not configured with IPCOMP support. -.TP -\fB\-\-tunnel\fP -the IPsec SA should use tunneling. Implicit if the SA is for clients. -Must only be used with \fB\-\-authenticate\fP or \fB\-\-encrypt\fP. -.TP -\fB\-\-ipv4\fP -The host addresses will be interpreted as IPv4 addresses. This is the -default. Note that for a connection, all host addresses must be of -the same Address Family (IPv4 and IPv6 use different Address Families). -.TP -\fB\-\-ipv6\fP -The host addresses (including nexthop) will be interpreted as IPv6 addresses. -Note that for a connection, all host addresses must be of -the same Address Family (IPv4 and IPv6 use different Address Families). -.TP -\fB\-\-tunnelipv4\fP -The client addresses will be interpreted as IPv4 addresses. The default is -to match what the host will be. This does not imply \fB\-\-tunnel\fP so the -flag can be safely used when no tunnel is actually specified. -Note that for a connection, all tunnel addresses must be of the same -Address Family. -.TP -\fB\-\-tunnelipv6\fP -The client addresses will be interpreted as IPv6 addresses. The default is -to match what the host will be. This does not imply \fB\-\-tunnel\fP so the -flag can be safely used when no tunnel is actually specified. -Note that for a connection, all tunnel addresses must be of the same -Address Family. -.TP -\fB\-\-pfs\fP -There should be Perfect Forward Secrecy \- new keying material will -be generated for each IPsec SA rather than being derived from the ISAKMP -SA keying material. -Since the group to be used cannot be negotiated (a dubious feature of the -standard), \fBpluto\fP will propose the same group that was used during Phase 1. -We don't implement a stronger form of PFS which would require that the -ISAKMP SA be deleted after the IPSEC SA is negotiated. -.TP -\fB\-\-disablearrivalcheck\fP -If the connection is a tunnel, allow packets arriving through the tunnel -to have any source and destination addresses. -.LP -If none of the \fB\-\-encrypt\fP, \fB\-\-authenticate\fP, \fB\-\-compress\fP, -or \fB\-\-pfs\fP flags is given, the initiating the connection will -only build an ISAKMP SA. For such a connection, client subnets have -no meaning and must not be specified. -.LP -More work is needed to allow for flexible policies. Currently -policy is hardwired in the source file spdb.c. The ISAKMP SAs may use -Oakley groups MODP1024 and MODP1536; 3DES encryption; SHA1-96 -and MD5-96 authentication. The IPsec SAs may use 3DES and -MD5-96 or SHA1-96 for ESP, or just MD5-96 or SHA1-96 for AH. -IPCOMP Compression is always Deflate. -.TP -\fB\-\-ikelifetime\fP\ \fIseconds\fP -how long \fBpluto\fP will propose that an ISAKMP SA be allowed to live. -The default is 10800 (three hours) and the maximum is 86400 (one day). -This option will not affect what is accepted. -\fBpluto\fP will reject proposals that exceed the maximum. -.TP -\fB\-\-ipseclifetime\fP\ \fIseconds\fP -how long \fBpluto\fP will propose that an IPsec SA be allowed to live. -The default is 3600 (one hour) and the maximum is 86400 (one day). -This option will not affect what is accepted. -\fBpluto\fP will reject proposals that exceed the maximum. -.TP -\fB\-\-rekeymargin\fP\ \fIseconds\fP -how long before an SA's expiration should \fBpluto\fP try to negotiate -a replacement SA. This will only happen if \fBpluto\fP was the initiator. -The default is 540 (nine minutes). -.TP -\fB\-\-rekeyfuzz\fP\ \fIpercentage\fP -maximum size of random component to add to rekeymargin, expressed as -a percentage of rekeymargin. \fBpluto\fP will select a delay uniformly -distributed within this range. By default, the percentage will be 100. -If greater determinism is desired, specify 0. It may be appropriate -for the percentage to be much larger than 100. -.TP -\fB\-\-keyingtries\fP\ \fIcount\fP -how many times \fBpluto\fP should try to negotiate an SA, -either for the first time or for rekeying. -A value of 0 is interpreted as a very large number: never give up. -The default is three. -.TP -\fB\-\-dontrekey\fP -A misnomer. -Only rekey a connection if we were the Initiator and there was recent -traffic on the existing connection. -This applies to Phase 1 and Phase 2. -This is currently the only automatic way for a connection to terminate. -It may be useful with Road Warrior or Opportunistic connections. -.br -Since SA lifetime negotiation is take-it-or-leave it, a Responder -normally uses the shorter of the negotiated or the configured lifetime. -This only works because if the lifetime is shorter than negotiated, -the Responder will rekey in time so that everything works. -This interacts badly with \fB\-\-dontrekey\fP. In this case, -the Responder will end up rekeying to rectify a shortfall in an IPsec SA -lifetime; for an ISAKMP SA, the Responder will accept the negotiated -lifetime. -.TP -\fB\-\-delete\fP -when used in the connection form, it causes any previous connection -with this name to be deleted before this one is added. Unlike a -normal delete, no diagnostic is produced if there was no previous -connection to delete. Any routing in place for the connection is undone. -.LP -The delete form deletes a named connection description and any -SAs established or negotiations initiated using this connection. -Any routing in place for the connection is undone. -.TP -\fB\-\-delete\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The deletestate form deletes the state object with the specified serial number. -This is useful for selectively deleting instances of connections. -.TP -\fB\-\-deletestate\fP\ \fIstate-number\fP -.LP -The route form of the \fBwhack\fP command tells \fBpluto\fP to set up -routing for a connection. -Although like a traditional route, it uses an ipsec device as a -virtual interface. -Once routing is set up, no packets will be -sent ``in the clear'' to the peer's client specified in the connection. -A TRAP shunt eroute will be installed; if outbound traffic is caught, -Pluto will initiate the connection. -An explicit \fBwhack\fP route is not always needed: if it hasn't been -done when an IPsec SA is being installed, one will be automatically attempted. -.LP -When a routing is attempted for a connection, there must not already -be a routing for a different connection with the same subnet but different -interface or destination, or if -there is, it must not be being used by an IPsec SA. Otherwise the -attempt will fail. -.TP -\fB\-\-route\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The unroute form of the \fBwhack\fP command tells \fBpluto\fP to undo -a routing. \fBpluto\fP will refuse if an IPsec SA is using the connection. -If another connection is sharing the same routing, it will be left in place. -Without a routing, packets will be sent without encryption or authentication. -.TP -\fB\-\-unroute\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The initiate form tells \fBpluto\fP to initiate a negotiation with another -\fBpluto\fP (or other IKE daemon) according to the named connection. -Initiation requires a route that \fB\-\-route\fP would provide; -if none is in place at the time an IPsec SA is being installed, -\fBpluto\fP attempts to set one up. -.TP -\fB\-\-initiate\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.TP -\fB\-\-asynchronous -.LP -The initiate form of the \fBwhack\fP command will relay back from -\fBpluto\fP status information via the UNIX domain socket (unless -\-\-asynchronous is specified). The status information is meant to -look a bit like that from \fBFTP\fP. Currently \fBwhack\fP simply -copies this to stderr. When the request is finished (eg. the SAs are -established or \fBpluto\fP gives up), \fBpluto\fP closes the channel, -causing \fBwhack\fP to terminate. -.LP -The opportunistic initiate form is mainly used for debugging. -.TP -\fB\-\-tunnelipv4\fP -.TP -\fB\-\-tunnelipv6\fP -.TP -\fB\-\-oppohere\fP\ \fIip-address\fP -.TP -\fB\-\-oppothere\fP\ \fIip-address\fP -.LP -This will cause \fBpluto\fP to attempt to opportunistically initiate a -connection from here to the there, even if a previous attempt -had been made. -The whack log will show the progress of this attempt. -.LP -The terminate form tells \fBpluto\fP to delete any SAs that use the specified -connection and to stop any negotiations in process. -It does not prevent new negotiations from starting (the delete form -has this effect). -.TP -\fB\-\-terminate\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The public key for informs \fBpluto\fP of the RSA public key for a potential peer. -Private keys must be kept secret, so they are kept in -.IR ipsec.secrets (5). -.TP -\fB\-\-keyid\ \fP\fIid\fP -specififies the identity of the peer for which a public key should be used. -Its form is identical to the identity in the connection. -If no public key is specified, \fBpluto\fP attempts to find KEY records -from DNS for the id (if a FQDN) or through reverse lookup (if an IP address). -Note that there several interesting ways in which this is not secure. -.TP -\fB\-\-addkey\fP -specifies that the new key is added to the collection; otherwise the -new key replaces any old ones. -.TP -\fB\-\-pubkeyrsa\ \fP\fIkey\fP -specifies the value of the RSA public key. It is a sequence of bytes -as described in RFC 2537 ``RSA/MD5 KEYs and SIGs in the Domain Name System (DNS)''. -It is denoted in a way suitable for \fIipsec_ttodata\fP(3). -For example, a base 64 numeral starts with 0s. -.LP -The listen form tells \fBpluto\fP to start listening for IKE requests -on its public interfaces. To avoid race conditions, it is normal to -load the appropriate connections into \fBpluto\fP before allowing it -to listen. If \fBpluto\fP isn't listening, it is pointless to -initiate negotiations, so it will refuse requests to do so. Whenever -the listen form is used, \fBpluto\fP looks for public interfaces and -will notice when new ones have been added and when old ones have been -removed. This is also the trigger for \fBpluto\fP to read the -\fIipsec.secrets\fP file. So listen may useful more than once. -.TP -\fB\-\-listen\fP -start listening for IKE traffic on public interfaces. -.TP -\fB\-\-unlisten\fP -stop listening for IKE traffic on public interfaces. -.LP -The status form will display information about the internal state of -\fBpluto\fP: information about each potential connection, about -each state object, and about each shunt that \fBpluto\fP is managing -without an associated connection. -.TP -\fB\-\-status\fP -.LP -The shutdown form is the proper way to shut down \fBpluto\fP. -It will tear down the SAs on this machine that \fBpluto\fP has negotiated. -It does not inform its peers, so the SAs on their machines remain. -.TP -\fB\-\-shutdown\fP -.SS Examples -.LP -It would be normal to start \fBpluto\fP in one of the system initialization -scripts. It needs to be run by the superuser. Generally, no arguments are needed. -To run in manually, the superuser can simply type - -\ \ \ ipsec pluto - -The command will immediately return, but a \fBpluto\fP process will be left -running, waiting for requests from \fBwhack\fP or a peer. -.LP -Using \fBwhack\fP, several potential connections would be described: -.HP -.na -\ \ \ ipsec whack \-\-name\ silly -\-\-host\ 127.0.0.1 \-\-to \-\-host\ 127.0.0.2 -\-\-ikelifetime\ 900 \-\-ipseclifetime\ 800 \-\-keyingtries\ 3 -.ad -.LP -Since this silly connection description specifies neither encryption, -authentication, nor tunneling, it could only be used to establish -an ISAKMP SA. -.HP -.na -\ \ \ ipsec whack \-\-name\ secret \-\-host\ 10.0.0.1 \-\-client\ 10.0.1.0/24 -\-\-to \-\-host\ 10.0.0.2 \-\-client\ 10.0.2.0/24 -\-\-encrypt -.ad -.LP -This is something that must be done on both sides. If the other -side is \fBpluto\fP, the same \fBwhack\fP command could be used on it -(the command syntax is designed to not distinguish which end is ours). -.LP -Now that the connections are specified, \fBpluto\fP is ready to handle -requests and replies via the public interfaces. We must tell it to discover -those interfaces and start accepting messages from peers: - -\ \ \ ipsec whack \-\-listen -.LP -If we don't immediately wish to bring up a secure connection between -the two clients, we might wish to prevent insecure traffic. -The routing form asks \fBpluto\fP to cause the packets sent from -our client to the peer's client to be routed through the ipsec0 -device; if there is no SA, they will be discarded: - -\ \ \ ipsec whack \-\-route secret -.LP -Finally, we are ready to get \fBpluto\fP to initiate negotiation -for an IPsec SA (and implicitly, an ISAKMP SA): - -\ \ \ ipsec whack \-\-initiate\ \-\-name\ secret - -A small log of interesting events will appear on standard output -(other logging is sent to syslog). -.LP -\fBwhack\fP can also be used to terminate \fBpluto\fP cleanly, tearing down -all SAs that it has negotiated. - -\ \ \ ipsec whack \-\-shutdown - -Notification of any IPSEC SA deletion, but not ISAKMP SA deletion -is sent to the peer. Unfortunately, such Notification is not reliable. -Furthermore, \fBpluto\fP itself ignores Notifications. -.SS The updown command -.LP -Whenever \fBpluto\fP brings a connection up or down, it invokes -the updown command. This command is specified using the \fB\-\-updown\fP -option. This allows for customized control over routing and firewall manipulation. -.LP -The updown is invoked for five different operations. Each of -these operations can be for our client subnet or for our host itself. -.TP -\fBprepare-host\fP or \fBprepare-client\fP -is run before bringing up a new connection if no other connection -with the same clients is up. Generally, this is useful for deleting a -route that might have been set up before \fBpluto\fP was run or -perhaps by some agent not known to \fBpluto\fP. -.TP -\fBroute-host\fP or \fBroute-client\fP -is run when bringing up a connection for a new peer client subnet -(even if \fBprepare-host\fP or \fBprepare-client\fP was run). The -command should install a suitable route. Routing decisions are based -only on the destination (peer's client) subnet address, unlike eroutes -which discriminate based on source too. -.TP -\fBunroute-host\fP or \fBunroute-client\fP -is run when bringing down the last connection for a particular peer -client subnet. It should undo what the \fBroute-host\fP or \fBroute-client\fP -did. -.TP -\fBup-host\fP or \fBup-client\fP -is run when bringing up a tunnel eroute with a pair of client subnets -that does not already have a tunnel eroute. -This command should install firewall rules as appropriate. -It is generally a good idea to allow IKE messages (UDP port 500) -travel between the hosts. -.TP -\fBdown-host\fP or \fBdown-client\fP -is run when bringing down the eroute for a pair of client subnets. -This command should delete firewall rules as appropriate. Note that -there may remain some inbound IPsec SAs with these client subnets. -.LP -The script is passed a large number of environment variables to specify -what needs to be done. -.TP -\fBPLUTO_VERSION\fP -indicates what version of this interface is being used. This document -describes version 1.1. This is upwardly compatible with version 1.0. -.TP -\fBPLUTO_VERB\fP -specifies the name of the operation to be performed -(\fBprepare-host\fP,r \fBprepare-client\fP, -\fBup-host\fP, \fBup-client\fP, -\fBdown-host\fP, or \fBdown-client\fP). If the address family for -security gateway to security gateway communications is IPv6, then -a suffix of \-v6 is added to the verb. -.TP -\fBPLUTO_CONNECTION\fP -is the name of the connection for which we are routing. -.TP -\fBPLUTO_NEXT_HOP\fP -is the next hop to which packets bound for the peer must be sent. -.TP -\fBPLUTO_INTERFACE\fP -is the name of the ipsec interface to be used. -.TP -\fBPLUTO_ME\fP -is the IP address of our host. -.TP -\fBPLUTO_MY_CLIENT\fP -is the IP address / count of our client subnet. -If the client is just the host, this will be the host's own IP address / max -(where max is 32 for IPv4 and 128 for IPv6). -.TP -\fBPLUTO_MY_CLIENT_NET\fP -is the IP address of our client net. -If the client is just the host, this will be the host's own IP address. -.TP -\fBPLUTO_MY_CLIENT_MASK\fP -is the mask for our client net. -If the client is just the host, this will be 255.255.255.255. -.TP -\fBPLUTO_PEER\fP -is the IP address of our peer. -.TP -\fBPLUTO_PEER_CLIENT\fP -is the IP address / count of the peer's client subnet. -If the client is just the peer, this will be the peer's own IP address / max -(where max is 32 for IPv4 and 128 for IPv6). -.TP -\fBPLUTO_PEER_CLIENT_NET\fP -is the IP address of the peer's client net. -If the client is just the peer, this will be the peer's own IP address. -.TP -\fBPLUTO_PEER_CLIENT_MASK\fP -is the mask for the peer's client net. -If the client is just the peer, this will be 255.255.255.255. -.LP -All output sent by the script to stderr or stdout is logged. The -script should return an exit status of 0 if and only if it succeeds. -.LP -\fBPluto\fP waits for the script to finish and will not do any other -processing while it is waiting. -The script may assume that \fBpluto\fP will not change anything -while the script runs. -The script should avoid doing anything that takes much time and it -should not issue any command that requires processing by \fBpluto\fP. -Either of these activities could be performed by a background -subprocess of the script. -.SS Rekeying -.LP -When an SA that was initiated by \fBpluto\fP has only a bit of -lifetime left, -\fBpluto\fP will initiate the creation of a new SA. This applies to -ISAKMP and IPsec SAs. -The rekeying will be initiated when the SA's remaining lifetime is -less than the rekeymargin plus a random percentage, between 0 and -rekeyfuzz, of the rekeymargin. -.LP -Similarly, when an SA that was initiated by the peer has only a bit of -lifetime left, \fBpluto\fP will try to initiate the creation of a -replacement. -To give preference to the initiator, this rekeying will only be initiated -when the SA's remaining lifetime is half of rekeymargin. -If rekeying is done by the responder, the roles will be reversed: the -responder for the old SA will be the initiator for the replacement. -The former initiator might also initiate rekeying, so there may -be redundant SAs created. -To avoid these complications, make sure that rekeymargin is generous. -.LP -One risk of having the former responder initiate is that perhaps -none of its proposals is acceptable to the former initiator -(they have not been used in a successful negotiation). -To reduce the chances of this happening, and to prevent loss of security, -the policy settings are taken from the old SA (this is the case even if -the former initiator is initiating). -These may be stricter than those of the connection. -.LP -\fBpluto\fP will not rekey an SA if that SA is not the most recent of its -type (IPsec or ISAKMP) for its potential connection. -This avoids creating redundant SAs. -.LP -The random component in the rekeying time (rekeyfuzz) is intended to -make certain pathological patterns of rekeying unstable. If both -sides decide to rekey at the same time, twice as many SAs as necessary -are created. This could become a stable pattern without the -randomness. -.LP -Another more important case occurs when a security gateway has SAs -with many other security gateways. Each of these connections might -need to be rekeyed at the same time. This would cause a high peek -requirement for resources (network bandwidth, CPU time, entropy for -random numbers). The rekeyfuzz can be used to stagger the rekeying -times. -.LP -Once a new set of SAs has been negotiated, \fBpluto\fP will never send -traffic on a superseded one. Traffic will be accepted on an old SA -until it expires. -.SS Selecting a Connection When Responding: Road Warrior Support -.LP -When \fBpluto\fP receives an initial Main Mode message, it needs to -decide which connection this message is for. It picks based solely on -the source and destination IP addresses of the message. There might -be several connections with suitable IP addresses, in which case one -of them is arbitrarily chosen. (The ISAKMP SA proposal contained in -the message could be taken into account, but it is not.) -.LP -The ISAKMP SA is negotiated before the parties pass further -identifying information, so all ISAKMP SA characteristics specified in -the connection description should be the same for every connection -with the same two host IP addresses. At the moment, the only -characteristic that might differ is authentication method. -.LP -Up to this point, -all configuring has presumed that the IP addresses -are known to all parties ahead of time. This will not work -when either end is mobile (or assigned a dynamic IP address for other -reasons). We call this situation ``Road Warrior''. It is fairly tricky -and has some important limitations, most of which are features of -the IKE protocol. -.LP -Only the initiator may be mobile: -the initiator may have an IP number unknown to the responder. When -the responder doesn't recognize the IP address on the first Main Mode -packet, it looks for a connection with itself as one end and \fB%any\fP -as the other. -If it cannot find one, it refuses to negotiate. If it -does find one, it creates a temporary connection that is a duplicate -except with the \fB%any\fP replaced by the source IP address from the -packet; if there was no identity specified for the peer, the new IP -address will be used. -.LP -When \fBpluto\fP is using one of these temporary connections and -needs to find the preshared secret or RSA private key in \fIipsec.secrets\fP, -and and the connection specified no identity for the peer, \fB%any\fP -is used as its identity. After all, the real IP address was apparently -unknown to the configuration, so it is unreasonable to require that -it be used in this table. -.LP -Part way into the Phase 1 (Main Mode) negotiation using one of these -temporary connection descriptions, \fBpluto\fP will be receive an -Identity Payload. At this point, \fBpluto\fP checks for a more -appropriate connection, one with an identity for the peer that matches -the payload but which would use the same keys so-far used for -authentication. If it finds one, it will switch to using this better -connection (or a temporary derived from this, if it has \fB%any\fP -for the peer's IP address). It may even turn out that no connection -matches the newly discovered identity, including the current connection; -if so, \fBpluto\fP terminates negotiation. -.LP -Unfortunately, if preshared secret authentication is being used, the -Identity Payload is encrypted using this secret, so the secret must be -selected by the responder without knowing this payload. This -limits there to being at most one preshared secret for all Road Warrior -systems connecting to a host. RSA Signature authentications does not -require that the responder know how to select the initiator's public key -until after the initiator's Identity Payload is decoded (using the -responder's private key, so that must be preselected). -.LP -When \fBpluto\fP is responding to a Quick Mode negotiation via one of these -temporary connection descriptions, it may well find that the subnets -specified by the initiator don't match those in the temporary -connection description. If so, it will look for a connection with -matching subnets, its own host address, a peer address of \fB%any\fP -and matching identities. -If it finds one, a new temporary connection is derived from this one -and used for the Quick Mode negotiation of IPsec SAs. If it does not -find one, \fBpluto\fP terminates negotiation. -.LP -Be sure to specify an appropriate nexthop for the responder -to send a message to the initiator: \fBpluto\fP has no way of guessing -it (if forwarding isn't required, use an explicit \fB%direct\fP as the nexthop -and the IP address of the initiator will be filled in; the obsolete -notation \fB0.0.0.0\fP is still accepted). -.LP -\fBpluto\fP has no special provision for the initiator side. The current -(possibly dynamic) IP address and nexthop must be used in defining -connections. These must be -properly configured each time the initiator's IP address changes. -\fBpluto\fP has no mechanism to do this automatically. -.LP -Although we call this Road Warrior Support, it could also be used to -support encrypted connections with anonymous initiators. The -responder's organization could announce the preshared secret that would be used -with unrecognized initiators and let anyone connect. Of course the initiator's -identity would not be authenticated. -.LP -If any Road Warrior connections are supported, \fBpluto\fP cannot -reject an exchange initiated by an unknown host until it has -determined that the secret is not shared or the signature is invalid. -This must await the -third Main Mode message from the initiator. If no Road Warrior -connection is supported, the first message from an unknown source -would be rejected. This has implications for ease of debugging -configurations and for denial of service attacks. -.LP -Although a Road Warrior connection must be initiated by the mobile -side, the other side can and will rekey using the temporary connection -it has created. If the Road Warrior wishes to be able to disconnect, -it is probably wise to set \fB\-\-keyingtries\fP to 1 in the -connection on the non-mobile side to prevent it trying to rekey the -connection. Unfortunately, there is no mechanism to unroute the -connection automatically. -.SS Debugging -.LP -\fBpluto\fP accepts several optional arguments, useful mostly for debugging. -Except for \fB\-\-interface\fP, each should appear at most once. -.TP -\fB\-\-interface\fP \fIinterfacename\fP -specifies that the named real public network interface should be considered. -The interface name specified should not be \fBipsec\fP\fIN\fP. -If the option doesn't appear, all interfaces are considered. -To specify several interfaces, use the option once for each. -One use of this option is to specify which interface should be used -when two or more share the same IP address. -.TP -\fB\-\-ikeport\fP \fIport-number\fP -changes the UDP port that \fBpluto\fP will use -(default, specified by IANA: 500) -.TP -\fB\-\-ctlbase\fP \fIpath\fP -basename for control files. -\fIpath\fP.ctl is the socket through which \fBwhack\fP communicates with -\fBpluto\fP. -\fIpath\fP.pid is the lockfile to prevent multiple \fBpluto\fP instances. -The default is \fI/var/run/pluto\fP). -.TP -\fB\-\-secretsfile\fP \fIfile\fP -specifies the file for authentication secrets -(default: \fI/etc/ipsec.secrets\fP). -This name is subject to ``globbing'' as in \fIsh\fP(1), -so every file with a matching name is processed. -Quoting is generally needed to prevent the shell from doing the globbing. -.TP -\fB\-\-adns\fP \fIpathname\fP -.TP -\fB\-\-lwdnsq\fP \fIpathname\fP -specifies where to find \fBpluto\fP's helper program for asynchronous DNS lookup. -\fBpluto\fP can be built to use one of two helper programs: \fB_pluto_adns\fP -or \fBlwdnsq\fP. You must use the program for which it was built. -By default, \fBpluto\fP will look for the program in -\fB$IPSEC_DIR\fP (if that environment variable is defined) or, failing that, -in the same directory as \fBpluto\fP. -.TP -\fB\-\-nofork\fP -disable ``daemon fork'' (default is to fork). In addition, after the -lock file and control socket are created, print the line ``Pluto -initialized'' to standard out. -.TP -\fB\-\-uniqueids\fP -if this option has been selected, whenever a new ISAKMP SA is -established, any connection with the same Peer ID but a different -Peer IP address is unoriented (causing all its SAs to be deleted). -This helps clean up dangling SAs when a connection is lost and -then regained at another IP address. -.TP -\fB\-\-stderrlog\fP -log goes to standard out {default is to use \fIsyslogd\fP(8)) -.LP -\fBpluto\fP is willing to produce a prodigious amount of debugging -information. To do so, it must be compiled with \-DDEBUG. There are -several classes of debugging output, and \fBpluto\fP may be directed to -produce a selection of them. All lines of -debugging output are prefixed with ``|\ '' to distinguish them from error -messages. -.LP -When \fBpluto\fP is invoked, it may be given arguments to specify -which classes to output. The current options are: -.TP -\fB\-\-debug-raw\fP -show the raw bytes of messages -.TP -\fB\-\-debug-crypt\fP -show the encryption and decryption of messages -.TP -\fB\-\-debug-parsing\fP -show the structure of input messages -.TP -\fB\-\-debug-emitting\fP -show the structure of output messages -.TP -\fB\-\-debug-control\fP -show \fBpluto\fP's decision making -.TP -\fB\-\-debug-lifecycle\fP -[this option is temporary] log more detail of lifecycle of SAs -.TP -\fB\-\-debug-kernel\fP -show \fBpluto\fP's interaction with the kernel -.TP -\fB\-\-debug-dns\fP -show \fBpluto\fP's interaction with \fBDNS\fP for KEY and TXT records -.TP -\fB\-\-debug-oppo\fP -show why \fBpluto\fP didn't find a suitable DNS TXT record to authorize opportunistic initiation -.TP -\fB\-\-debug-all\fP -all of the above -.TP -\fB\-\-debug-private\fP -allow debugging output with private keys. -.TP -\fB\-\-debug-none\fP -none of the above -.LP -The debug form of the -\fBwhack\fP command will change the selection in a running -\fBpluto\fP. -If a connection name is specified, the flags are added whenever -\fBpluto\fP has identified that it is dealing with that connection. -Unfortunately, this is often part way into the operation being observed. -.LP -For example, to start a \fBpluto\fP with a display of the structure of input -and output: -.IP -pluto \-\-debug-emitting \-\-debug-parsing -.LP -To later change this \fBpluto\fP to only display raw bytes: -.IP -whack \-\-debug-raw -.LP -For testing, SSH's IKE test page is quite useful: -.IP -\fIhttp://isakmp-test.ssh.fi/\fP -.LP -Hint: ISAKMP SAs are often kept alive by IKEs even after the IPsec SA -is established. This allows future IPsec SA's to be negotiated -directly. If one of the IKEs is restarted, the other may try to use -the ISAKMP SA but the new IKE won't know about it. This can lead to -much confusion. \fBpluto\fP is not yet smart enough to get out of such a -mess. -.SS Pluto's Behaviour When Things Go Wrong -.LP -When \fBpluto\fP doesn't understand or accept a message, it just -ignores the message. It is not yet capable of communicating the -problem to the other IKE daemon (in the future it might use -Notifications to accomplish this in many cases). It does log a diagnostic. -.LP -When \fBpluto\fP gets no response from a message, it resends the same -message (a message will be sent at most three times). This is -appropriate: UDP is unreliable. -.LP -When pluto gets a message that it has already seen, there are many -cases when it notices and discards it. This too is appropriate for UDP. -.LP -Combine these three rules, and you can explain many apparently -mysterious behaviours. In a \fBpluto\fP log, retrying isn't usually the -interesting event. The critical thing is either earlier (\fBpluto\fP -got a message which it didn't like and so ignored, so it was still -awaiting an acceptable message and got impatient) or on the other -system (\fBpluto\fP didn't send a reply because it wasn't happy with -the previous message). -.SS Notes -.LP -Each IPsec SA is assigned an SPI, a 32-bit number used to refer to the SA. -The IKE protocol lets the destination of the SA choose the SPI. -The range 0 to 0xFF is reserved for IANA. -\fBPluto\fP also avoids choosing an SPI in the range 0x100 to 0xFFF, -leaving these SPIs free for manual keying. -Remember that the peer, if not \fBpluto\fP, may well chose -SPIs in this range. -.SS Policies -.LP -This catalogue of policies may be of use when trying to configure -\fBPluto\fP and another IKE implementation to interoperate. -.LP -In Phase 1, only Main Mode is supported. We are not sure that -Aggressive Mode is secure. For one thing, it does not support -identity protection. It may allow more severe Denial Of Service -attacks. -.LP -No Informational Exchanges are supported. These are optional and -since their delivery is not assured, they must not matter. -It is the case that some IKE implementations won't interoperate -without Informational Exchanges, but we feel they are broken. -.LP -No Informational Payloads are supported. These are optional, but -useful. It is of concern that these payloads are not authenticated in -Phase 1, nor in those Phase 2 messages authenticated with HASH(3). -.IP \(bu \w'\(bu\ 'u -Diffie Hellman Groups MODP 1024 and MODP 1536 (2 and 5) -are supported. -Group MODP768 (1) is not supported because it is too weak. -.IP \(bu -Host authetication can be done by RSA Signatures or Pre-Shared -Secrets. -.IP \(bu -3DES CBC (Cypher Block Chaining mode) is the only encryption -supported, both for ISAKMP SAs and IPSEC SAs. -.IP \(bu -MD5 and SHA1 hashing are supported for packet authentication in both -kinds of SAs. -.IP \(bu -The ESP, AH, or AH plus ESP are supported. If, and only if, AH and -ESP are combined, the ESP need not have its own authentication -component. The selection is controlled by the \-\-encrypt and -\-\-authenticate flags. -.IP \(bu -Each of these may be combined with IPCOMP Deflate compression, -but only if the potential connection specifies compression and only -if the kernel is configured with IPCOMP support. -.IP \(bu -The IPSEC SAs may be tunnel or transport mode, where appropriate. -The \-\-tunnel flag controls this when \fBpluto\fP is initiating. -.IP \(bu -When responding to an ISAKMP SA proposal, the maximum acceptable -lifetime is eight hours. The default is one hour. There is no -minimum. The \-\-ikelifetime flag controls this when \fBpluto\fP -is initiating. -.IP \(bu -When responding to an IPSEC SA proposal, the maximum acceptable -lifetime is one day. The default is eight hours. There is no -minimum. The \-\-ipseclifetime flag controls this when \fBpluto\fP -is initiating. -.IP \(bu -PFS is acceptable, and will be proposed if the \-\-pfs flag was -specified. The DH group proposed will be the same as negotiated for -Phase 1. -.SH SIGNALS -.LP -\fBPluto\fP responds to \fBSIGHUP\fP by issuing a suggestion that ``\fBwhack\fP -\-\-listen'' might have been intended. -.LP -\fBPluto\fP exits when it receives \fBSIGTERM\fP. -.SH EXIT STATUS -.LP -\fBpluto\fP normally forks a daemon process, so the exit status is -normally a very preliminary result. -.TP -0 -means that all is OK so far. -.TP -1 -means that something was wrong. -.TP -10 -means that the lock file already exists. -.LP -If \fBwhack\fP detects a problem, it will return an exit status of 1. -If it received progress messages from \fBpluto\fP, it returns as status -the value of the numeric prefix from the last such message -that was not a message sent to syslog or a comment -(but the prefix for success is treated as 0). -Otherwise, the exit status is 0. -.SH FILES -\fI/var/run/pluto.pid\fP -.br -\fI/var/run/pluto.ctl\fP -.br -\fI/etc/ipsec.secrets\fP -.br -\fI$IPSEC_LIBDIR/_pluto_adns\fP -.br -\fI$IPSEC_EXECDIR/lwdnsq\fP -.br -\fI/dev/urandom\fP -.SH ENVIRONMENT -\fIIPSEC_LIBDIR\fP -.br -\fIIPSEC_EXECDIR\fP -.br -\fIIPSECmyid\fP -.SH SEE ALSO -.LP -The rest of the FreeS/WAN distribution, in particular \fIipsec\fP(8). -.LP -\fIipsec_auto\fP(8) is designed to make using \fBpluto\fP more pleasant. -Use it! -.LP -.IR ipsec.secrets (5) -describes the format of the secrets file. -.LP -\fIipsec_atoaddr\fP(3), part of the FreeS/WAN distribution, describes the -forms that IP addresses may take. -\fIipsec_atosubnet\fP(3), part of the FreeS/WAN distribution, describes the -forms that subnet specifications. -.LP -For more information on IPsec, the mailing list, and the relevant -documents, see: -.IP -.nh -\fIhttp://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html\fP -.hy -.LP -At the time of writing, the most relevant IETF RFCs are: -.IP -RFC2409 The Internet Key Exchange (IKE) -.IP -RFC2408 Internet Security Association and Key Management Protocol (ISAKMP) -.IP -RFC2407 The Internet IP Security Domain of Interpretation for ISAKMP -.LP -The FreeS/WAN web site <htp://www.freeswan.org> -and the mailing lists described there. -.SH HISTORY -This code is released under the GPL terms. -See the accompanying file COPYING-2.0 for more details. -The GPL does NOT apply to those pieces of code written by others -which are included in this distribution, except as noted by the -individual authors. -.LP -This software was originally written -for the FreeS/WAN project -<http://www.freeswan.org> -by Angelos D. Keromytis -(angelos@dsl.cis.upenn.edu), in May/June 1997, in Athens, Greece. -Thanks go to John Ioannidis for his help. -.LP -It is currently (2000) -being developed and maintained by D. Hugh Redelmeier -(hugh@mimosa.com), in Canada. The regulations of Greece and Canada -allow us to make the code freely redistributable. -.LP -Kai Martius (admin@imib.med.tu-dresden.de) contributed the initial -version of the code supporting PFS. -.LP -Richard Guy Briggs <rgb@conscoop.ottawa.on.ca> and Peter Onion -<ponion@srd.bt.co.uk> added the PFKEY2 support. -.LP -We gratefully acknowledge that we use parts of Eric Young's \fIlibdes\fP -package; see \fI../libdes/COPYRIGHT\fP. -.SH BUGS -.BR pluto -is a work-in-progress. It currently has many limitations. -For example, it ignores notification messages that it receives, and -it generates only Delete Notifications and those only for IPSEC SAs. -.LP -\fBpluto\fP does not support the Commit Flag. -The Commit Flag is a bad feature of the IKE protocol. -It isn't protected -- neither encrypted nor authenticated. -A man in the middle could turn it on, leading to DoS. -We just ignore it, with a warning. -This should let us interoperate with -implementations that insist on it, with minor damage. -.LP -\fBpluto\fP does not check that the SA returned by the Responder -is actually one that was proposed. It only checks that the SA is -acceptable. The difference is not large, but can show up in attributes -such as SA lifetime. -.LP -There is no good way for a connection to be automatically terminated. -This is a problem for Road Warrior and Opportunistic connections. -The \fB\-\-dontrekey\fP option does prevent the SAs from -being rekeyed on expiry. -Additionally, if a Road Warrior connection has a client subnet with a fixed IP -address, a negotiation with that subnet will cause any other -connection instantiations with that same subnet to be unoriented -(deleted, in effect). -See also the \-\-uniqueids option for an extension of this. -.LP -When \fBpluto\fP sends a message to a peer that has disappeared, -\fBpluto\fP receives incomplete information from the kernel, so it -logs the unsatisfactory message ``some IKE message we sent has been -rejected with ECONNREFUSED (kernel supplied no details)''. John -Denker suggests that this command is useful for tracking down the -source of these problems: -.br - tcpdump \-i eth0 icmp[0] != 8 and icmp[0] != 0 -.br -Substitute your public interface for eth0 if it is different. -.LP -The word ``authenticate'' is used for two different features. We must -authenticate each IKE peer to the other. This is an important task of -Phase 1. Each packet must be authenticated, both in IKE and in IPsec, -and the method for IPsec is negotiated as an AH SA or part of an ESP SA. -Unfortunately, the protocol has no mechanism for authenticating the Phase 2 -identities. -.LP -Bugs should be reported to the <users@lists.freeswan.org> mailing list. -Caution: we cannot accept -actual code from US residents, or even US citizens living outside the -US, because that would bring FreeS/WAN under US export law. Some -other countries cause similar problems. In general, we would prefer -that you send detailed problem reports rather than code: we want -FreeS/WAN to be unquestionably freely exportable, which means being -very careful about where the code comes from, and for a small bug fix, -that is often more time-consuming than just reinventing the fix -ourselves. diff --git a/src/pluto/pluto.c b/src/pluto/pluto.c deleted file mode 100644 index 66fdb30b9..000000000 --- a/src/pluto/pluto.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "pluto.h" - -#include <debug.h> - -typedef struct private_pluto_t private_pluto_t; - -/** - * Private additions to pluto_t. - */ -struct private_pluto_t { - - /** - * Public members of pluto_t. - */ - pluto_t public; -}; - -/** - * Single instance of pluto_t. - */ -pluto_t *pluto; - -/** - * Described in header. - */ -void pluto_deinit() -{ - private_pluto_t *this = (private_pluto_t*)pluto; - this->public.events->destroy(this->public.events); - this->public.xauth->destroy(this->public.xauth); - free(this); - pluto = NULL; -} - -/** - * Described in header. - */ -bool pluto_init(char *file) -{ - private_pluto_t *this; - - INIT(this, - .public = { - .events = event_queue_create(), - .xauth = xauth_manager_create(), - }, - ); - pluto = &this->public; - - if (lib->integrity && - !lib->integrity->check_file(lib->integrity, "pluto", file)) - { - DBG1(DBG_LIB, "integrity check of pluto failed"); - return FALSE; - } - return TRUE; -} - diff --git a/src/pluto/pluto.h b/src/pluto/pluto.h deleted file mode 100644 index 2440093ca..000000000 --- a/src/pluto/pluto.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup pluto pluto - * - * @defgroup xauth xauth - * @ingroup pluto - * - * @defgroup pplugins plugins - * @ingroup pluto - * - * @addtogroup pluto - * @{ - */ - -#ifndef PLUTO_H_ -#define PLUTO_H_ - -typedef struct pluto_t pluto_t; - -#include <event_queue.h> -#include <xauth/xauth_manager.h> - -#include <library.h> - -/** - * Pluto daemon support object. - */ -struct pluto_t { - - /** - * event queue (callbacks, executed by the pluto main thread) - */ - event_queue_t *events; - - /** - * manager for payload attributes - */ - xauth_manager_t *xauth; - -}; - -/** - * The single instance of pluto_t. - * - * Set between calls to pluto_init() and pluto_deinit() calls. - */ -extern pluto_t *pluto; - -/** - * Initialize pluto. - * - * @return FALSE if integrity check failed - */ -bool pluto_init(char *file); - -/** - * Deinitialize pluto. - */ -void pluto_deinit(void); - -#endif /** PLUTO_H_ @}*/ - diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c deleted file mode 100644 index dbc857ce2..000000000 --- a/src/pluto/plutomain.c +++ /dev/null @@ -1,852 +0,0 @@ -/* Pluto main program - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <ctype.h> -#include <errno.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <fcntl.h> -#include <getopt.h> -#include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ -#include <sys/queue.h> -#include <sys/prctl.h> -#include <signal.h> -#include <pwd.h> -#include <grp.h> - -#ifdef CAPABILITIES -#ifdef HAVE_SYS_CAPABILITY_H -#include <sys/capability.h> -#endif /* HAVE_SYS_CAPABILITY_H */ -#endif /* CAPABILITIES */ - -#include <freeswan.h> - -#include <hydra.h> -#include <library.h> -#include <debug.h> -#include <utils/enumerator.h> -#include <utils/optionsfrom.h> - -#include <pfkeyv2.h> -#include <pfkey.h> - -#include "constants.h" -#include "defs.h" -#include "myid.h" -#include "ca.h" -#include "certs.h" -#include "ac.h" -#include "connections.h" -#include "foodgroups.h" -#include "packet.h" -#include "demux.h" /* needs packet.h */ -#include "server.h" -#include "kernel.h" -#include "log.h" -#include "keys.h" -#include "adns.h" /* needs <resolv.h> */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "state.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "ocsp.h" -#include "crl.h" -#include "fetch.h" -#include "crypto.h" -#include "nat_traversal.h" -#include "virtual.h" -#include "timer.h" -#include "vendor.h" -#include "builder.h" -#include "whack_attribute.h" -#include "pluto.h" - -#ifdef ANDROID -#include <private/android_filesystem_config.h> /* for AID_VPN */ -#endif - -/** - * Number of threads in the thread pool, if not specified in config. - */ -#define DEFAULT_THREADS 4 - -/** - * PID file, in which pluto stores its process id - */ -static char pluto_lock[sizeof(ctl_addr.sun_path)] = DEFAULT_CTLBASE LOCK_SUFFIX; - -/** - * TRUE if the lock has been checked. This helps to avoid any unintended - * deletion of the lock or control socket. - */ -static bool pluto_lock_checked = FALSE; - -/** - * Global reference to PID file (required to truncate, if undeletable) - */ -static FILE *pidfile = NULL; - - -static void usage(const char *mess) -{ - if (mess != NULL && *mess != '\0') - fprintf(stderr, "%s\n", mess); - fprintf(stderr - , "Usage: pluto" - " [--help]" - " [--version]" - " [--optionsfrom <filename>]" - " \\\n\t" - "[--nofork]" - " [--stderrlog]" - " [--nocrsend]" - " \\\n\t" - "[--strictcrlpolicy]" - " [--crlcheckinterval <interval>]" - " [--cachecrls]" - " [--uniqueids]" - " \\\n\t" - "[--interface <ifname>]" - " [--ikeport <port-number>]" - " \\\n\t" - "[--ctlbase <path>]" - " \\\n\t" - "[--perpeerlogbase <path>] [--perpeerlog]" - " \\\n\t" - "[--secretsfile <secrets-file>]" - " [--policygroupsdir <policygroups-dir>]" - " \\\n\t" - "[--adns <pathname>]" - "[--pkcs11module <path>]" - "[--pkcs11keepstate]" - "[--pkcs11initargs <string>]" -#ifdef DEBUG - " \\\n\t" - "[--debug-none]" - " [--debug-all]" - " \\\n\t" - "[--debug-raw]" - " [--debug-crypt]" - " [--debug-parsing]" - " [--debug-emitting]" - " \\\n\t" - "[--debug-control]" - " [--debug-lifecycle]" - " [--debug-kernel]" - " [--debug-dns]" - " \\\n\t" - "[--debug-oppo]" - " [--debug-controlmore]" - " [--debug-private]" - " [--debug-natt]" -#endif - " \\\n\t" - "[--nat_traversal] [--keep_alive <delay_sec>]" - " \\\n\t" - "[--force_keepalive] [--disable_port_floating]" - " \\\n\t" - "[--virtual_private <network_list>]" - "\n" - "strongSwan "VERSION"\n"); - exit_pluto(mess == NULL? 0 : 1); -} - -static bool check_lock() -{ - struct stat stb; - FILE *fpid; - - if (stat(pluto_lock, &stb) == 0) - { - fpid = fopen(pluto_lock, "r"); - if (fpid) - { - char buf[64]; - pid_t pid = 0; - - memset(buf, 0, sizeof(buf)); - if (fread(buf, 1, sizeof(buf), fpid)) - { - buf[sizeof(buf) - 1] = '\0'; - pid = atoi(buf); - } - fclose(fpid); - if (pid && kill(pid, 0) == 0) - { /* such a process is running */ - return TRUE; - } - } - fprintf(stderr, "pluto: removing lock file \"%s\", process not " - "running\n", pluto_lock); - unlink(pluto_lock); - } - pluto_lock_checked = TRUE; - return FALSE; -} - -static void fill_lock(void) -{ - pidfile = fopen(pluto_lock, "w"); - if (pidfile) - { - fprintf(pidfile, "%u\n", (u_int)getpid()); - fflush(pidfile); - } - /* keep pidfile open so we can truncate it, if we cannot delete it */ -} - -static void delete_lock(void) -{ - /* because unlinking the PID file may fail, we truncate it to ensure the - * daemon can be properly restarted. one probable cause for this is the - * combination of not running as root and the effective user lacking - * permissions on the parent dir(s) of the PID file */ - if (pluto_lock_checked) - { - if (pidfile) - { - ignore_result(ftruncate(fileno(pidfile), 0)); - fclose(pidfile); - } - unlink(pluto_lock); - /* delete this here to avoid that exit_pluto calls delete the socket */ - delete_ctl_socket(); - } -} - - -/* by default pluto sends certificate requests to its peers */ -bool no_cr_send = FALSE; - -/* by default the CRL policy is lenient */ -bool strict_crl_policy = FALSE; - -/* by default CRLs are cached locally as files */ -bool cache_crls = FALSE; - -/* by default pluto does not check crls dynamically */ -long crl_check_interval = 0; - -/* path to the PKCS#11 module */ -char *pkcs11_module_path = NULL; - -/* by default pluto logs out after every smartcard use */ -bool pkcs11_keep_state = FALSE; - -/* by default pluto does not allow pkcs11 proxy access via whack */ -bool pkcs11_proxy = FALSE; - -/* argument string to pass to PKCS#11 module. - * Not used for compliant modules, just for NSS softoken - */ -static const char *pkcs11_init_args = NULL; - -/* options read by optionsfrom */ -options_t *options; - -int main(int argc, char **argv) -{ - bool fork_desired = TRUE; - bool log_to_stderr_desired = FALSE; - bool nat_traversal = FALSE; - bool nat_t_spf = TRUE; /* support port floating */ - unsigned int keep_alive = 0; - bool force_keepalive = FALSE; - char *virtual_private = NULL; -#ifdef CAPABILITIES - int keep[] = { - CAP_NET_ADMIN, - CAP_NET_BIND_SERVICE, -#ifdef ANDROID - CAP_NET_RAW, -#endif - }; -#endif /* CAPABILITIES */ - - /* initialize library and optionsfrom */ - if (!library_init(NULL)) - { - library_deinit(); - exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); - } - if (!libhydra_init("pluto")) - { - libhydra_deinit(); - library_deinit(); - exit(SS_RC_INITIALIZATION_FAILED); - } - if (!pluto_init(argv[0])) - { - pluto_deinit(); - libhydra_deinit(); - library_deinit(); - exit(SS_RC_DAEMON_INTEGRITY); - } - options = options_create(); - - /* handle arguments */ - for (;;) - { -# define DBG_OFFSET 256 - static const struct option long_opts[] = { - /* name, has_arg, flag, val */ - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'v' }, - { "optionsfrom", required_argument, NULL, '+' }, - { "nofork", no_argument, NULL, 'd' }, - { "stderrlog", no_argument, NULL, 'e' }, - { "nocrsend", no_argument, NULL, 'c' }, - { "strictcrlpolicy", no_argument, NULL, 'r' }, - { "crlcheckinterval", required_argument, NULL, 'x'}, - { "cachecrls", no_argument, NULL, 'C' }, - { "uniqueids", no_argument, NULL, 'u' }, - { "interface", required_argument, NULL, 'i' }, - { "ikeport", required_argument, NULL, 'p' }, - { "ctlbase", required_argument, NULL, 'b' }, - { "secretsfile", required_argument, NULL, 's' }, - { "foodgroupsdir", required_argument, NULL, 'f' }, - { "perpeerlogbase", required_argument, NULL, 'P' }, - { "perpeerlog", no_argument, NULL, 'l' }, - { "policygroupsdir", required_argument, NULL, 'f' }, - { "adns", required_argument, NULL, 'a' }, - { "pkcs11module", required_argument, NULL, 'm' }, - { "pkcs11keepstate", no_argument, NULL, 'k' }, - { "pkcs11initargs", required_argument, NULL, 'z' }, - { "pkcs11proxy", no_argument, NULL, 'y' }, - { "nat_traversal", no_argument, NULL, '1' }, - { "keep_alive", required_argument, NULL, '2' }, - { "force_keepalive", no_argument, NULL, '3' }, - { "disable_port_floating", no_argument, NULL, '4' }, - { "debug-natt", no_argument, NULL, '5' }, - { "virtual_private", required_argument, NULL, '6' }, -#ifdef DEBUG - { "debug-none", no_argument, NULL, 'N' }, - { "debug-all", no_argument, NULL, 'A' }, - { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET }, - { "debug-crypt", no_argument, NULL, DBG_CRYPT + DBG_OFFSET }, - { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET }, - { "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET }, - { "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET }, - { "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET }, - { "debug-klips", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, - { "debug-kernel", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, - { "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET }, - { "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET }, - { "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET }, - { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET }, - - { "impair-delay-adns-key-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_KEY_ANSWER + DBG_OFFSET }, - { "impair-delay-adns-txt-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_TXT_ANSWER + DBG_OFFSET }, - { "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET }, - { "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET }, -#endif - { 0,0,0,0 } - }; - /* Note: we don't like the way short options get parsed - * by getopt_long, so we simply pass an empty string as - * the list. It could be "hvdenp:l:s:" "NARXPECK". - */ - int c = getopt_long(argc, argv, "", long_opts, NULL); - - /* Note: "breaking" from case terminates loop */ - switch (c) - { - case EOF: /* end of flags */ - break; - - case 0: /* long option already handled */ - continue; - - case ':': /* diagnostic already printed by getopt_long */ - case '?': /* diagnostic already printed by getopt_long */ - usage(""); - break; /* not actually reached */ - - case 'h': /* --help */ - usage(NULL); - break; /* not actually reached */ - - case 'v': /* --version */ - { - const char **sp = ipsec_copyright_notice(); - - printf("strongSwan "VERSION"%s\n", compile_time_interop_options); - for (; *sp != NULL; sp++) - puts(*sp); - } - exit_pluto(0); - break; /* not actually reached */ - - case '+': /* --optionsfrom <filename> */ - if (!options->from(options, optarg, &argc, &argv, optind)) - { - exit_pluto(1); - } - continue; - - case 'd': /* --nofork*/ - fork_desired = FALSE; - continue; - - case 'e': /* --stderrlog */ - log_to_stderr_desired = TRUE; - continue; - - case 'c': /* --nocrsend */ - no_cr_send = TRUE; - continue; - - case 'r': /* --strictcrlpolicy */ - strict_crl_policy = TRUE; - continue; - - case 'x': /* --crlcheckinterval <time>*/ - if (optarg == NULL || !isdigit(optarg[0])) - usage("missing interval time"); - - { - char *endptr; - long interval = strtol(optarg, &endptr, 0); - - if (*endptr != '\0' || endptr == optarg - || interval <= 0) - usage("<interval-time> must be a positive number"); - crl_check_interval = interval; - } - continue; - - case 'C': /* --cachecrls */ - cache_crls = TRUE; - continue; - - case 'u': /* --uniqueids */ - uniqueIDs = TRUE; - continue; - - case 'i': /* --interface <ifname> */ - if (!use_interface(optarg)) - usage("too many --interface specifications"); - continue; - - case 'p': /* --port <portnumber> */ - if (optarg == NULL || !isdigit(optarg[0])) - usage("missing port number"); - - { - char *endptr; - long port = strtol(optarg, &endptr, 0); - - if (*endptr != '\0' || endptr == optarg - || port <= 0 || port > 0x10000) - usage("<port-number> must be a number between 1 and 65535"); - pluto_port = port; - } - continue; - - case 'b': /* --ctlbase <path> */ - if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path) - , "%s%s", optarg, CTL_SUFFIX) == -1) - usage("<path>" CTL_SUFFIX " too long for sun_path"); - if (snprintf(info_addr.sun_path, sizeof(info_addr.sun_path) - , "%s%s", optarg, INFO_SUFFIX) == -1) - usage("<path>" INFO_SUFFIX " too long for sun_path"); - if (snprintf(pluto_lock, sizeof(pluto_lock) - , "%s%s", optarg, LOCK_SUFFIX) == -1) - usage("<path>" LOCK_SUFFIX " must fit"); - continue; - - case 's': /* --secretsfile <secrets-file> */ - shared_secrets_file = optarg; - continue; - - case 'f': /* --policygroupsdir <policygroups-dir> */ - policygroups_dir = optarg; - continue; -#ifdef ADNS - case 'a': /* --adns <pathname> */ - pluto_adns_option = optarg; - continue; -#endif - case 'm': /* --pkcs11module <pathname> */ - pkcs11_module_path = optarg; - continue; - - case 'k': /* --pkcs11keepstate */ - pkcs11_keep_state = TRUE; - continue; - - case 'y': /* --pkcs11proxy */ - pkcs11_proxy = TRUE; - continue; - - case 'z': /* --pkcs11initargs */ - pkcs11_init_args = optarg; - continue; - -#ifdef DEBUG - case 'N': /* --debug-none */ - base_debugging = DBG_NONE; - continue; - - case 'A': /* --debug-all */ - base_debugging = DBG_ALL; - continue; -#endif - - case 'P': /* --perpeerlogbase */ - base_perpeer_logdir = optarg; - continue; - - case 'l': - log_to_perpeer = TRUE; - continue; - - case '1': /* --nat_traversal */ - nat_traversal = TRUE; - continue; - case '2': /* --keep_alive */ - keep_alive = atoi(optarg); - continue; - case '3': /* --force_keepalive */ - force_keepalive = TRUE; - continue; - case '4': /* --disable_port_floating */ - nat_t_spf = FALSE; - continue; - case '5': /* --debug-nat_t */ - base_debugging |= DBG_NATT; - continue; - case '6': /* --virtual_private */ - virtual_private = optarg; - continue; - - default: -#ifdef DEBUG - if (c >= DBG_OFFSET) - { - base_debugging |= c - DBG_OFFSET; - continue; - } -# undef DBG_OFFSET -#endif - bad_case(c); - } - break; - } - if (optind != argc) - usage("unexpected argument"); - reset_debugging(); - - if (check_lock()) - { - fprintf(stderr, "pluto: lock file \"%s\" already exists\n", pluto_lock); - exit_pluto(10); - } - - /* select between logging methods */ - - if (log_to_stderr_desired) - { - log_to_syslog = FALSE; - } - else - { - log_to_stderr = FALSE; - } - - /* set the logging function of pfkey debugging */ -#ifdef DEBUG - pfkey_debug_func = DBG_log; -#else - pfkey_debug_func = NULL; -#endif - - /* create control socket. - * We must create it before the parent process returns so that - * there will be no race condition in using it. The easiest - * place to do this is before the daemon fork. - */ - { - err_t ugh = init_ctl_socket(); - - if (ugh != NULL) - { - fprintf(stderr, "pluto: %s", ugh); - exit_pluto(1); - } - } - - /* If not suppressed, do daemon fork */ - - if (fork_desired) - { - { - pid_t pid = fork(); - - if (pid < 0) - { - int e = errno; - - fprintf(stderr, "pluto: fork failed (%d %s)\n", - errno, strerror(e)); - exit_pluto(1); - } - - if (pid != 0) - { - /* parent: die - * must not use exit_pluto: lock would be removed! - */ - exit(0); - } - /* child: fill PID into lock file */ - fill_lock(); - } - - if (setsid() < 0) - { - int e = errno; - - fprintf(stderr, "setsid() failed in main(). Errno %d: %s\n", - errno, strerror(e)); - exit_pluto(1); - } - } - else - { - /* no daemon fork: we have to fill in lock file */ - fill_lock(); - fprintf(stdout, "Pluto initialized\n"); - fflush(stdout); - } - - /* Redirect stdin, stdout and stderr to /dev/null - */ - { - int fd; - if ((fd = open("/dev/null", O_RDWR)) == -1) - abort(); - if (dup2(fd, 0) != 0) - abort(); - if (dup2(fd, 1) != 1) - abort(); - if (!log_to_stderr && dup2(fd, 2) != 2) - abort(); - close(fd); - } - - /* for uncritical pseudo random numbers */ - srand(time(NULL) + getpid()); - - init_constants(); - init_log("pluto"); - - /* Note: some scripts may look for this exact message -- don't change - * ipsec barf was one, but it no longer does. - */ - plog("Starting IKEv1 pluto daemon (strongSwan "VERSION")%s", - compile_time_interop_options); - - if (lib->integrity) - { - plog("integrity tests enabled:"); - plog("lib 'libstrongswan': passed file and segment integrity tests"); - plog("lib 'libhydra': passed file and segment integrity tests"); - plog("daemon 'pluto': passed file integrity test"); - } - - /* load plugins, further infrastructure may need it */ - if (!lib->plugins->load(lib->plugins, NULL, - lib->settings->get_str(lib->settings, "pluto.load", PLUGINS))) - { - exit(SS_RC_INITIALIZATION_FAILED); - } - DBG1(DBG_DMN, "loaded plugins: %s", - lib->plugins->loaded_plugins(lib->plugins)); - - init_builder(); - if (!init_secret() || !init_crypto()) - { - plog("initialization failed - aborting pluto"); - exit_pluto(SS_RC_INITIALIZATION_FAILED); - } - init_nat_traversal(nat_traversal, keep_alive, force_keepalive, nat_t_spf); - init_virtual_ip(virtual_private); - scx_init(pkcs11_module_path, pkcs11_init_args); - init_states(); - init_demux(); - init_kernel(); -#ifdef ADNS - init_adns(); -#endif - init_myid(); - fetch_initialize(); - ac_initialize(); - whack_attribute_initialize(); - - /* drop unneeded capabilities and change UID/GID */ - prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); - -#ifdef IPSEC_GROUP - { - struct group group, *grp; - char buf[1024]; - - if (getgrnam_r(IPSEC_GROUP, &group, buf, sizeof(buf), &grp) != 0 || - grp == NULL || setgid(grp->gr_gid) != 0) - { - plog("unable to change daemon group"); - abort(); - } - } -#endif -#ifdef IPSEC_USER - { - struct passwd passwd, *pwp; - char buf[1024]; - - if (getpwnam_r(IPSEC_USER, &passwd, buf, sizeof(buf), &pwp) != 0 || - pwp == NULL || setuid(pwp->pw_uid) != 0) - { - plog("unable to change daemon user"); - abort(); - } - } -#endif -#ifdef ANDROID - if (setuid(AID_VPN) != 0) - { - plog("unable to change daemon user"); - abort(); - } -#endif - -#ifdef CAPABILITIES_LIBCAP - { - cap_t caps; - caps = cap_init(); - cap_set_flag(caps, CAP_EFFECTIVE, countof(keep), keep, CAP_SET); - cap_set_flag(caps, CAP_INHERITABLE, countof(keep), keep, CAP_SET); - cap_set_flag(caps, CAP_PERMITTED, countof(keep), keep, CAP_SET); - if (cap_set_proc(caps) != 0) - { - plog("unable to drop daemon capabilities"); - abort(); - } - cap_free(caps); - } -#endif /* CAPABILITIES_LIBCAP */ -#ifdef CAPABILITIES_NATIVE - { - struct __user_cap_data_struct caps = { .effective = 0 }; - struct __user_cap_header_struct header = { - .version = _LINUX_CAPABILITY_VERSION, - }; - int i; - for (i = 0; i < countof(keep); i++) - { - caps.effective |= 1 << keep[i]; - caps.permitted |= 1 << keep[i]; - caps.inheritable |= 1 << keep[i]; - } - if (capset(&header, &caps) != 0) - { - plog("unable to drop daemon capabilities"); - abort(); - } - } -#endif /* CAPABILITIES_NATIVE */ - - /* loading X.509 CA certificates */ - load_authcerts("ca", CA_CERT_PATH, X509_CA); - /* loading X.509 AA certificates */ - load_authcerts("aa", AA_CERT_PATH, X509_AA); - /* loading X.509 OCSP certificates */ - load_authcerts("ocsp", OCSP_CERT_PATH, X509_OCSP_SIGNER); - /* loading X.509 CRLs */ - load_crls(); - /* loading attribute certificates (experimental) */ - ac_load_certs(); - - lib->processor->set_threads(lib->processor, - lib->settings->get_int(lib->settings, "pluto.threads", - DEFAULT_THREADS)); - - daily_log_event(); - call_server(); - return -1; /* Shouldn't ever reach this */ -} - -/* leave pluto, with status. - * Once child is launched, parent must not exit this way because - * the lock would be released. - * - * 0 OK - * 1 general discomfort - * 10 lock file exists - */ -void exit_pluto(int status) -{ - lib->processor->set_threads(lib->processor, 0); - reset_globals(); /* needed because we may be called in odd state */ - free_preshared_secrets(); - free_remembered_public_keys(); - delete_every_connection(); - whack_attribute_finalize(); /* free in-memory pools */ - kernel_finalize(); - fetch_finalize(); /* stop fetching thread */ - free_crl_fetch(); /* free chain of crl fetch requests */ - free_ocsp_fetch(); /* free chain of ocsp fetch requests */ - free_authcerts(); /* free chain of X.509 authority certificates */ - free_crls(); /* free chain of X.509 CRLs */ - free_ca_infos(); /* free chain of X.509 CA information records */ - free_ocsp(); /* free ocsp cache */ - free_ifaces(); - ac_finalize(); /* free X.509 attribute certificates */ - scx_finalize(); /* finalize and unload PKCS #11 module */ -#ifdef ADNS - stop_adns(); -#endif - free_md_pool(); - free_crypto(); - free_myid(); /* free myids */ - free_events(); /* free remaining events */ - free_vendorid(); /* free all vendor id records */ - free_builder(); - delete_lock(); - options->destroy(options); - pluto_deinit(); - lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); - lib->plugins->unload(lib->plugins); - libhydra_deinit(); - library_deinit(); - close_log(); - exit(status); -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/rcv_whack.c b/src/pluto/rcv_whack.c deleted file mode 100644 index 0a7b33ab5..000000000 --- a/src/pluto/rcv_whack.c +++ /dev/null @@ -1,728 +0,0 @@ -/* whack communicating routines - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ -#include <sys/queue.h> -#include <fcntl.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "ca.h" -#include "certs.h" -#include "ac.h" -#include "smartcard.h" -#include "connections.h" -#include "foodgroups.h" -#include "whack.h" /* needs connections.h */ -#include "packet.h" -#include "demux.h" /* needs packet.h */ -#include "state.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "kernel.h" -#include "rcv_whack.h" -#include "log.h" -#include "keys.h" -#include "adns.h" /* needs <resolv.h> */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "server.h" -#include "fetch.h" -#include "ocsp.h" -#include "crl.h" -#include "myid.h" -#include "kernel_alg.h" -#include "ike_alg.h" -#include "plugin_list.h" -#include "whack_attribute.h" - -/* helper variables and function to decode strings from whack message */ - -static char *next_str - , *str_roof; - -static bool unpack_str(char **p) -{ - char *end = memchr(next_str, '\0', str_roof - next_str); - - if (end == NULL) - { - return FALSE; /* fishy: no end found */ - } - else - { - *p = next_str == end? NULL : next_str; - next_str = end + 1; - return TRUE; - } -} - -/* bits loading keys from asynchronous DNS */ - -enum key_add_attempt { - ka_TXT, -#ifdef USE_KEYRR - ka_KEY, -#endif - ka_roof /* largest value + 1 */ -}; - -struct key_add_common { - int refCount; - char *diag[ka_roof]; - int whack_fd; - bool success; -}; - -struct key_add_continuation { - struct adns_continuation ac; /* common prefix */ - struct key_add_common *common; /* common data */ - enum key_add_attempt lookingfor; -}; - -static void key_add_ugh(identification_t *keyid, err_t ugh) -{ - loglog(RC_NOKEY, "failure to fetch key for %'Y' from DNS: %s", keyid, ugh); -} - -/* last one out: turn out the lights */ -static void key_add_merge(struct key_add_common *oc, identification_t *keyid) -{ - if (oc->refCount == 0) - { - enum key_add_attempt kaa; - - /* if no success, print all diagnostics */ - if (!oc->success) - { - for (kaa = ka_TXT; kaa != ka_roof; kaa++) - { - key_add_ugh(keyid, oc->diag[kaa]); - } - } - for (kaa = ka_TXT; kaa != ka_roof; kaa++) - { - free(oc->diag[kaa]); - } - close(oc->whack_fd); - free(oc); - } -} - -#ifdef ADNS - -static void key_add_continue(struct adns_continuation *ac, err_t ugh) -{ - struct key_add_continuation *kc = (void *) ac; - struct key_add_common *oc = kc->common; - - passert(whack_log_fd == NULL_FD); - whack_log_fd = oc->whack_fd; - - if (ugh != NULL) - { - oc->diag[kc->lookingfor] = clone_str(ugh); - } - else - { - oc->success = TRUE; - transfer_to_public_keys(kc->ac.gateways_from_dns -#ifdef USE_KEYRR - , &kc->ac.keys_from_dns -#endif /* USE_KEYRR */ - ); - } - - oc->refCount--; - key_add_merge(oc, ac->id); - whack_log_fd = NULL_FD; -} - -#endif /* ADNS */ - -static void key_add_request(const whack_message_t *msg) -{ - identification_t *key_id; - - key_id = identification_create_from_string(msg->keyid); - - if (!msg->whack_addkey) - { - delete_public_keys(key_id, msg->pubkey_alg, NULL, chunk_empty); - } - if (msg->keyval.len == 0) - { - struct key_add_common *oc = malloc_thing(struct key_add_common); - enum key_add_attempt kaa; - err_t ugh; - - /* initialize state shared by queries */ - oc->refCount = 0; - oc->whack_fd = dup_any(whack_log_fd); - oc->success = FALSE; - - for (kaa = ka_TXT; kaa != ka_roof; kaa++) - { - struct key_add_continuation *kc; - - oc->diag[kaa] = NULL; - oc->refCount++; - kc = malloc_thing(struct key_add_continuation); - kc->common = oc; - kc->lookingfor = kaa; - ugh = NULL; - - switch (kaa) - { -#ifdef ADNS - case ka_TXT: - ugh = start_adns_query(key_id - , key_id /* same */ - , T_TXT - , key_add_continue - , &kc->ac); - break; -#endif /* ADNS */ -#ifdef USE_KEYRR - case ka_KEY: - ugh = start_adns_query(key_id - , NULL - , T_KEY - , key_add_continue - , &kc->ac); - break; -#endif /* USE_KEYRR */ - default: - bad_case(kaa); /* suppress gcc warning */ - } - if (ugh) - { - oc->diag[kaa] = clone_str(ugh); - oc->refCount--; - } - } - - /* Done launching queries. Handle total failure case. */ - key_add_merge(oc, key_id); - } - else - { - if (!add_public_key(key_id, DAL_LOCAL, msg->pubkey_alg, msg->keyval, - &pubkeys)) - { - loglog(RC_LOG_SERIOUS, "failed to add public key"); - } - } - key_id->destroy(key_id); -} - -/* Handle a kernel request. Supposedly, there's a message in - * the kernelsock socket. - */ -void whack_handle(int whackctlfd) -{ - whack_message_t msg; - struct sockaddr_un whackaddr; - int whackaddrlen = sizeof(whackaddr); - int whackfd = accept(whackctlfd, (struct sockaddr *)&whackaddr, &whackaddrlen); - /* Note: actual value in n should fit in int. To print, cast to int. */ - ssize_t n; - - if (whackfd < 0) - { - log_errno((e, "accept() failed in whack_handle()")); - return; - } - if (fcntl(whackfd, F_SETFD, FD_CLOEXEC) < 0) - { - log_errno((e, "failed to set CLOEXEC in whack_handle()")); - close(whackfd); - return; - } - - n = read(whackfd, &msg, sizeof(msg)); - - if (n == -1) - { - log_errno((e, "read() failed in whack_handle()")); - close(whackfd); - return; - } - - whack_log_fd = whackfd; - - /* sanity check message */ - { - err_t ugh = NULL; - - next_str = msg.string; - str_roof = (char *)&msg + n; - - if ((size_t)n < offsetof(whack_message_t, whack_shutdown) + sizeof(msg.whack_shutdown)) - { - ugh = builddiag("ignoring runt message from whack: got %d bytes", (int)n); - } - else if (msg.magic != WHACK_MAGIC) - { - if (msg.magic == WHACK_BASIC_MAGIC) - { - /* Only shutdown command. Simpler inter-version compatibility. */ - if (msg.whack_shutdown) - { - plog("shutting down"); - exit_pluto(0); /* delete lock and leave, with 0 status */ - } - ugh = ""; /* bail early, but without complaint */ - } - else - { - ugh = builddiag("ignoring message from whack with bad magic %d; should be %d; probably wrong version" - , msg.magic, WHACK_MAGIC); - } - } - else if (next_str > str_roof) - { - ugh = builddiag("ignoring truncated message from whack: got %d bytes; expected %u" - , (int) n, (unsigned) sizeof(msg)); - } - else if (!unpack_str(&msg.name) /* string 1 */ - || !unpack_str(&msg.left.id) /* string 2 */ - || !unpack_str(&msg.left.cert) /* string 3 */ - || !unpack_str(&msg.left.ca) /* string 4 */ - || !unpack_str(&msg.left.groups) /* string 5 */ - || !unpack_str(&msg.left.updown) /* string 6 */ - || !unpack_str(&msg.left.sourceip) /* string 7 */ - || !unpack_str(&msg.left.virt) /* string 8 */ - || !unpack_str(&msg.right.id) /* string 9 */ - || !unpack_str(&msg.right.cert) /* string 10 */ - || !unpack_str(&msg.right.ca) /* string 11 */ - || !unpack_str(&msg.right.groups) /* string 12 */ - || !unpack_str(&msg.right.updown) /* string 13 */ - || !unpack_str(&msg.right.sourceip) /* string 14 */ - || !unpack_str(&msg.right.virt) /* string 15 */ - || !unpack_str(&msg.keyid) /* string 16 */ - || !unpack_str(&msg.myid) /* string 17 */ - || !unpack_str(&msg.cacert) /* string 18 */ - || !unpack_str(&msg.ldaphost) /* string 19 */ - || !unpack_str(&msg.ldapbase) /* string 20 */ - || !unpack_str(&msg.crluri) /* string 21 */ - || !unpack_str(&msg.crluri2) /* string 22 */ - || !unpack_str(&msg.ocspuri) /* string 23 */ - || !unpack_str(&msg.ike) /* string 24 */ - || !unpack_str(&msg.esp) /* string 25 */ - || !unpack_str(&msg.sc_data) /* string 26 */ - || !unpack_str(&msg.whack_lease_ip) /* string 27 */ - || !unpack_str(&msg.whack_lease_id) /* string 28 */ - || !unpack_str(&msg.xauth_identity) /* string 29 */ - || str_roof - next_str != (ptrdiff_t)msg.keyval.len) /* check chunk */ - { - ugh = "message from whack contains bad string"; - } - else - { - msg.keyval.ptr = next_str; /* grab chunk */ - } - - if (ugh != NULL) - { - if (*ugh != '\0') - loglog(RC_BADWHACKMESSAGE, "%s", ugh); - whack_log_fd = NULL_FD; - close(whackfd); - return; - } - } - - if (msg.whack_options) - { -#ifdef DEBUG - if (msg.name == NULL) - { - /* we do a two-step so that if either old or new would - * cause the message to print, it will be printed. - */ - cur_debugging |= msg.debugging; - DBG(DBG_CONTROL - , DBG_log("base debugging = %s" - , bitnamesof(debug_bit_names, msg.debugging))); - cur_debugging = base_debugging = msg.debugging; - } - else if (!msg.whack_connection) - { - connection_t *c = con_by_name(msg.name, TRUE); - - if (c != NULL) - { - c->extra_debugging = msg.debugging; - DBG(DBG_CONTROL - , DBG_log("\"%s\" extra_debugging = %s" - , c->name - , bitnamesof(debug_bit_names, c->extra_debugging))); - } - } -#endif - } - - if (msg.whack_myid) - { - set_myid(MYID_SPECIFIED, msg.myid); - } - - /* Deleting combined with adding a connection works as replace. - * To make this more useful, in only this combination, - * delete will silently ignore the lack of the connection. - */ - if (msg.whack_delete) - { - if (msg.whack_ca) - { - find_ca_info_by_name(msg.name, TRUE); - } - else - { - delete_connections_by_name(msg.name, !msg.whack_connection); - } - } - - if (msg.whack_deletestate) - { - struct state *st = state_with_serialno(msg.whack_deletestateno); - - if (st == NULL) - { - loglog(RC_UNKNOWN_NAME, "no state #%lu to delete" - , msg.whack_deletestateno); - } - else - { - delete_state(st); - } - } - - if (msg.whack_crash) - { - delete_states_by_peer(&msg.whack_crash_peer); - } - - if (msg.whack_connection) - { - add_connection(&msg); - } - - if (msg.whack_ca && msg.cacert != NULL) - { - add_ca_info(&msg); - } - - /* process "listen" before any operation that could require it */ - if (msg.whack_listen) - { - close_peerlog(); /* close any open per-peer logs */ - plog("listening for IKE messages"); - listening = TRUE; - daily_log_reset(); -#ifdef ADNS - reset_adns_restart_count(); -#endif - set_myFQDN(); - find_ifaces(); - load_preshared_secrets(NULL_FD); - load_groups(); - } - if (msg.whack_unlisten) - { - plog("no longer listening for IKE messages"); - listening = FALSE; - } - - if (msg.whack_reread & REREAD_SECRETS) - { - load_preshared_secrets(whackfd); - } - - if (msg.whack_reread & REREAD_CACERTS) - { - load_authcerts("ca", CA_CERT_PATH, X509_CA); - } - - if (msg.whack_reread & REREAD_AACERTS) - { - load_authcerts("aa", AA_CERT_PATH, X509_AA); - } - - if (msg.whack_reread & REREAD_OCSPCERTS) - { - load_authcerts("ocsp", OCSP_CERT_PATH, X509_OCSP_SIGNER); - } - - if (msg.whack_reread & REREAD_ACERTS) - { - ac_load_certs(); - } - - if (msg.whack_reread & REREAD_CRLS) - { - load_crls(); - } - - if (msg.whack_purgeocsp) - { - free_ocsp_fetch(); - free_ocsp_cache(); - } - - if (msg.whack_leases) - { - list_leases(msg.name, msg.whack_lease_ip, msg.whack_lease_id); - } - - if (msg.whack_list & LIST_PUBKEYS) - { - list_public_keys(msg.whack_utc); - } - - if (msg.whack_list & LIST_CERTS) - { - cert_list(msg.whack_utc); - } - - if (msg.whack_list & LIST_CACERTS) - { - list_authcerts("CA", X509_CA, msg.whack_utc); - } - - if (msg.whack_list & LIST_AACERTS) - { - list_authcerts("AA", X509_AA, msg.whack_utc); - } - - if (msg.whack_list & LIST_OCSPCERTS) - { - list_authcerts("OCSP", X509_OCSP_SIGNER, msg.whack_utc); - } - - if (msg.whack_list & LIST_ACERTS) - { - ac_list_certs(msg.whack_utc); - } - - if (msg.whack_list & LIST_CAINFOS) - { - list_ca_infos(msg.whack_utc); - } - - if (msg.whack_list & LIST_CRLS) - { - list_crls(msg.whack_utc, strict_crl_policy); - list_crl_fetch_requests(msg.whack_utc); - } - - if (msg.whack_list & LIST_OCSP) - { - list_ocsp_cache(msg.whack_utc, strict_crl_policy); - list_ocsp_fetch_requests(msg.whack_utc); - } - - if (msg.whack_list & LIST_CARDS) - { - scx_list(msg.whack_utc); - } - - if (msg.whack_list & LIST_ALGS) - { - ike_alg_list(); - kernel_alg_list(); - } - - if (msg.whack_list & LIST_PLUGINS) - { - plugin_list(); - } - - if (msg.whack_key) - { - /* add a public key */ - key_add_request(&msg); - } - - if (msg.whack_route) - { - if (!listening) - { - whack_log(RC_DEAF, "need --listen before --route"); - } - if (msg.name == NULL) - { - whack_log(RC_UNKNOWN_NAME - , "whack --route requires a connection name"); - } - else - { - connection_t *c = con_by_name(msg.name, TRUE); - - if (c != NULL && c->ikev1) - { - set_cur_connection(c); - if (!oriented(*c)) - { - whack_log(RC_ORIENT - , "we have no ipsecN interface for either end of this connection"); - } - else if (c->policy & POLICY_GROUP) - { - route_group(c); - } - else if (!trap_connection(c)) - { - whack_log(RC_ROUTE, "could not route"); - } - reset_cur_connection(); - } - } - } - - if (msg.whack_unroute) - { - if (msg.name == NULL) - { - whack_log(RC_UNKNOWN_NAME - , "whack --unroute requires a connection name"); - } - else - { - connection_t *c = con_by_name(msg.name, TRUE); - - if (c != NULL && c->ikev1) - { - struct spd_route *sr; - int fail = 0; - - set_cur_connection(c); - - for (sr = &c->spd; sr != NULL; sr = sr->next) - { - if (sr->routing >= RT_ROUTED_TUNNEL) - { - fail++; - } - } - if (fail > 0) - { - whack_log(RC_RTBUSY, "cannot unroute: route busy"); - } - else if (c->policy & POLICY_GROUP) - { - unroute_group(c); - } - else - { - unroute_connection(c); - } - reset_cur_connection(); - } - } - } - - if (msg.whack_initiate) - { - if (!listening) - { - whack_log(RC_DEAF, "need --listen before --initiate"); - } - else if (msg.name == NULL) - { - whack_log(RC_UNKNOWN_NAME - , "whack --initiate requires a connection name"); - } - else - { - initiate_connection(msg.name - , msg.whack_async? NULL_FD : dup_any(whackfd)); - } - } - - if (msg.whack_oppo_initiate) - { - if (!listening) - { - whack_log(RC_DEAF, "need --listen before opportunistic initiation"); - } - else - { - initiate_opportunistic(&msg.oppo_my_client, &msg.oppo_peer_client, 0 - , FALSE - , msg.whack_async? NULL_FD : dup_any(whackfd)); - } - } - - if (msg.whack_terminate) - { - if (msg.name == NULL) - { - whack_log(RC_UNKNOWN_NAME - , "whack --terminate requires a connection name"); - } - else - { - terminate_connection(msg.name); - } - } - - if (msg.whack_status) - { - show_status(msg.whack_statusall, msg.name); - } - - if (msg.whack_shutdown) - { - plog("shutting down"); - exit_pluto(0); /* delete lock and leave, with 0 status */ - } - - if (msg.whack_sc_op != SC_OP_NONE) - { - if (pkcs11_proxy) - { - scx_op_via_whack(msg.sc_data, msg.inbase, msg.outbase - , msg.whack_sc_op, msg.keyid, whackfd); - } - else - { - plog("pkcs11 access to smartcard not allowed (set pkcs11proxy=yes)"); - } - } - - whack_log_fd = NULL_FD; - close(whackfd); -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/rcv_whack.h b/src/pluto/rcv_whack.h deleted file mode 100644 index 66edaaf80..000000000 --- a/src/pluto/rcv_whack.h +++ /dev/null @@ -1,15 +0,0 @@ -/* whack communicating routines - * Copyright (C) 1998, 1999 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -extern void whack_handle(int kernelfd); diff --git a/src/pluto/rsaref/pkcs11.h b/src/pluto/rsaref/pkcs11.h deleted file mode 100644 index 3283bdc89..000000000 --- a/src/pluto/rsaref/pkcs11.h +++ /dev/null @@ -1,299 +0,0 @@ -/* pkcs11.h include file for PKCS #11. */ -/* $Revision: 1.2 $ */ - -/* License to copy and use this software is granted provided that it is - * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface - * (Cryptoki)" in all material mentioning or referencing this software. - - * License is also granted to make and use derivative works provided that - * such works are identified as "derived from the RSA Security Inc. PKCS #11 - * Cryptographic Token Interface (Cryptoki)" in all material mentioning or - * referencing the derived work. - - * RSA 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. - */ - -#ifndef _PKCS11_H_ -#define _PKCS11_H_ 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* Before including this file (pkcs11.h) (or pkcs11t.h by - * itself), 6 platform-specific macros must be defined. These - * macros are described below, and typical definitions for them - * are also given. Be advised that these definitions can depend - * on both the platform and the compiler used (and possibly also - * on whether a Cryptoki library is linked statically or - * dynamically). - * - * In addition to defining these 6 macros, the packing convention - * for Cryptoki structures should be set. The Cryptoki - * convention on packing is that structures should be 1-byte - * aligned. - * - * If you're using Microsoft Developer Studio 5.0 to produce - * Win32 stuff, this might be done by using the following - * preprocessor directive before including pkcs11.h or pkcs11t.h: - * - * #pragma pack(push, cryptoki, 1) - * - * and using the following preprocessor directive after including - * pkcs11.h or pkcs11t.h: - * - * #pragma pack(pop, cryptoki) - * - * If you're using an earlier version of Microsoft Developer - * Studio to produce Win16 stuff, this might be done by using - * the following preprocessor directive before including - * pkcs11.h or pkcs11t.h: - * - * #pragma pack(1) - * - * In a UNIX environment, you're on your own for this. You might - * not need to do (or be able to do!) anything. - * - * - * Now for the macros: - * - * - * 1. CK_PTR: The indirection string for making a pointer to an - * object. It can be used like this: - * - * typedef CK_BYTE CK_PTR CK_BYTE_PTR; - * - * If you're using Microsoft Developer Studio 5.0 to produce - * Win32 stuff, it might be defined by: - * - * #define CK_PTR * - * - * If you're using an earlier version of Microsoft Developer - * Studio to produce Win16 stuff, it might be defined by: - * - * #define CK_PTR far * - * - * In a typical UNIX environment, it might be defined by: - * - * #define CK_PTR * - * - * - * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes - * an exportable Cryptoki library function definition out of a - * return type and a function name. It should be used in the - * following fashion to define the exposed Cryptoki functions in - * a Cryptoki library: - * - * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)( - * CK_VOID_PTR pReserved - * ) - * { - * ... - * } - * - * If you're using Microsoft Developer Studio 5.0 to define a - * function in a Win32 Cryptoki .dll, it might be defined by: - * - * #define CK_DEFINE_FUNCTION(returnType, name) \ - * returnType __declspec(dllexport) name - * - * If you're using an earlier version of Microsoft Developer - * Studio to define a function in a Win16 Cryptoki .dll, it - * might be defined by: - * - * #define CK_DEFINE_FUNCTION(returnType, name) \ - * returnType __export _far _pascal name - * - * In a UNIX environment, it might be defined by: - * - * #define CK_DEFINE_FUNCTION(returnType, name) \ - * returnType name - * - * - * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes - * an importable Cryptoki library function declaration out of a - * return type and a function name. It should be used in the - * following fashion: - * - * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)( - * CK_VOID_PTR pReserved - * ); - * - * If you're using Microsoft Developer Studio 5.0 to declare a - * function in a Win32 Cryptoki .dll, it might be defined by: - * - * #define CK_DECLARE_FUNCTION(returnType, name) \ - * returnType __declspec(dllimport) name - * - * If you're using an earlier version of Microsoft Developer - * Studio to declare a function in a Win16 Cryptoki .dll, it - * might be defined by: - * - * #define CK_DECLARE_FUNCTION(returnType, name) \ - * returnType __export _far _pascal name - * - * In a UNIX environment, it might be defined by: - * - * #define CK_DECLARE_FUNCTION(returnType, name) \ - * returnType name - * - * - * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro - * which makes a Cryptoki API function pointer declaration or - * function pointer type declaration out of a return type and a - * function name. It should be used in the following fashion: - * - * // Define funcPtr to be a pointer to a Cryptoki API function - * // taking arguments args and returning CK_RV. - * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args); - * - * or - * - * // Define funcPtrType to be the type of a pointer to a - * // Cryptoki API function taking arguments args and returning - * // CK_RV, and then define funcPtr to be a variable of type - * // funcPtrType. - * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args); - * funcPtrType funcPtr; - * - * If you're using Microsoft Developer Studio 5.0 to access - * functions in a Win32 Cryptoki .dll, in might be defined by: - * - * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ - * returnType __declspec(dllimport) (* name) - * - * If you're using an earlier version of Microsoft Developer - * Studio to access functions in a Win16 Cryptoki .dll, it might - * be defined by: - * - * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ - * returnType __export _far _pascal (* name) - * - * In a UNIX environment, it might be defined by: - * - * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ - * returnType (* name) - * - * - * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes - * a function pointer type for an application callback out of - * a return type for the callback and a name for the callback. - * It should be used in the following fashion: - * - * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args); - * - * to declare a function pointer, myCallback, to a callback - * which takes arguments args and returns a CK_RV. It can also - * be used like this: - * - * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args); - * myCallbackType myCallback; - * - * If you're using Microsoft Developer Studio 5.0 to do Win32 - * Cryptoki development, it might be defined by: - * - * #define CK_CALLBACK_FUNCTION(returnType, name) \ - * returnType (* name) - * - * If you're using an earlier version of Microsoft Developer - * Studio to do Win16 development, it might be defined by: - * - * #define CK_CALLBACK_FUNCTION(returnType, name) \ - * returnType _far _pascal (* name) - * - * In a UNIX environment, it might be defined by: - * - * #define CK_CALLBACK_FUNCTION(returnType, name) \ - * returnType (* name) - * - * - * 6. NULL_PTR: This macro is the value of a NULL pointer. - * - * In any ANSI/ISO C environment (and in many others as well), - * this should best be defined by - * - * #ifndef NULL_PTR - * #define NULL_PTR 0 - * #endif - */ - - -/* All the various Cryptoki types and #define'd values are in the - * file pkcs11t.h. */ -#include "pkcs11t.h" - -#define __PASTE(x,y) x##y - - -/* ============================================================== - * Define the "extern" form of all the entry points. - * ============================================================== - */ - -#define CK_NEED_ARG_LIST 1 -#define CK_PKCS11_FUNCTION_INFO(name) \ - extern CK_DECLARE_FUNCTION(CK_RV, name) - -/* pkcs11f.h has all the information about the Cryptoki - * function prototypes. */ -#include "pkcs11f.h" - -#undef CK_NEED_ARG_LIST -#undef CK_PKCS11_FUNCTION_INFO - - -/* ============================================================== - * Define the typedef form of all the entry points. That is, for - * each Cryptoki function C_XXX, define a type CK_C_XXX which is - * a pointer to that kind of function. - * ============================================================== - */ - -#define CK_NEED_ARG_LIST 1 -#define CK_PKCS11_FUNCTION_INFO(name) \ - typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name)) - -/* pkcs11f.h has all the information about the Cryptoki - * function prototypes. */ -#include "pkcs11f.h" - -#undef CK_NEED_ARG_LIST -#undef CK_PKCS11_FUNCTION_INFO - - -/* ============================================================== - * Define structed vector of entry points. A CK_FUNCTION_LIST - * contains a CK_VERSION indicating a library's Cryptoki version - * and then a whole slew of function pointers to the routines in - * the library. This type was declared, but not defined, in - * pkcs11t.h. - * ============================================================== - */ - -#define CK_PKCS11_FUNCTION_INFO(name) \ - __PASTE(CK_,name) name; - -struct CK_FUNCTION_LIST { - - CK_VERSION version; /* Cryptoki version */ - -/* Pile all the function pointers into the CK_FUNCTION_LIST. */ -/* pkcs11f.h has all the information about the Cryptoki - * function prototypes. */ -#include "pkcs11f.h" - -}; - -#undef CK_PKCS11_FUNCTION_INFO - - -#undef __PASTE - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/pluto/rsaref/pkcs11f.h b/src/pluto/rsaref/pkcs11f.h deleted file mode 100644 index 54b884aed..000000000 --- a/src/pluto/rsaref/pkcs11f.h +++ /dev/null @@ -1,912 +0,0 @@ -/* pkcs11f.h include file for PKCS #11. */ -/* $Revision: 1.2 $ */ - -/* License to copy and use this software is granted provided that it is - * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface - * (Cryptoki)" in all material mentioning or referencing this software. - - * License is also granted to make and use derivative works provided that - * such works are identified as "derived from the RSA Security Inc. PKCS #11 - * Cryptographic Token Interface (Cryptoki)" in all material mentioning or - * referencing the derived work. - - * RSA 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. - */ - -/* This header file contains pretty much everything about all the */ -/* Cryptoki function prototypes. Because this information is */ -/* used for more than just declaring function prototypes, the */ -/* order of the functions appearing herein is important, and */ -/* should not be altered. */ - -/* General-purpose */ - -/* C_Initialize initializes the Cryptoki library. */ -CK_PKCS11_FUNCTION_INFO(C_Initialize) -#ifdef CK_NEED_ARG_LIST -( - CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets - * cast to CK_C_INITIALIZE_ARGS_PTR - * and dereferenced */ -); -#endif - - -/* C_Finalize indicates that an application is done with the - * Cryptoki library. */ -CK_PKCS11_FUNCTION_INFO(C_Finalize) -#ifdef CK_NEED_ARG_LIST -( - CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */ -); -#endif - - -/* C_GetInfo returns general information about Cryptoki. */ -CK_PKCS11_FUNCTION_INFO(C_GetInfo) -#ifdef CK_NEED_ARG_LIST -( - CK_INFO_PTR pInfo /* location that receives information */ -); -#endif - - -/* C_GetFunctionList returns the function list. */ -CK_PKCS11_FUNCTION_INFO(C_GetFunctionList) -#ifdef CK_NEED_ARG_LIST -( - CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to - * function list */ -); -#endif - - - -/* Slot and token management */ - -/* C_GetSlotList obtains a list of slots in the system. */ -CK_PKCS11_FUNCTION_INFO(C_GetSlotList) -#ifdef CK_NEED_ARG_LIST -( - CK_BBOOL tokenPresent, /* only slots with tokens? */ - CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */ - CK_ULONG_PTR pulCount /* receives number of slots */ -); -#endif - - -/* C_GetSlotInfo obtains information about a particular slot in - * the system. */ -CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo) -#ifdef CK_NEED_ARG_LIST -( - CK_SLOT_ID slotID, /* the ID of the slot */ - CK_SLOT_INFO_PTR pInfo /* receives the slot information */ -); -#endif - - -/* C_GetTokenInfo obtains information about a particular token - * in the system. */ -CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo) -#ifdef CK_NEED_ARG_LIST -( - CK_SLOT_ID slotID, /* ID of the token's slot */ - CK_TOKEN_INFO_PTR pInfo /* receives the token information */ -); -#endif - - -/* C_GetMechanismList obtains a list of mechanism types - * supported by a token. */ -CK_PKCS11_FUNCTION_INFO(C_GetMechanismList) -#ifdef CK_NEED_ARG_LIST -( - CK_SLOT_ID slotID, /* ID of token's slot */ - CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */ - CK_ULONG_PTR pulCount /* gets # of mechs. */ -); -#endif - - -/* C_GetMechanismInfo obtains information about a particular - * mechanism possibly supported by a token. */ -CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo) -#ifdef CK_NEED_ARG_LIST -( - CK_SLOT_ID slotID, /* ID of the token's slot */ - CK_MECHANISM_TYPE type, /* type of mechanism */ - CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */ -); -#endif - - -/* C_InitToken initializes a token. */ -CK_PKCS11_FUNCTION_INFO(C_InitToken) -#ifdef CK_NEED_ARG_LIST -/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */ -( - CK_SLOT_ID slotID, /* ID of the token's slot */ - CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */ - CK_ULONG ulPinLen, /* length in bytes of the PIN */ - CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */ -); -#endif - - -/* C_InitPIN initializes the normal user's PIN. */ -CK_PKCS11_FUNCTION_INFO(C_InitPIN) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */ - CK_ULONG ulPinLen /* length in bytes of the PIN */ -); -#endif - - -/* C_SetPIN modifies the PIN of the user who is logged in. */ -CK_PKCS11_FUNCTION_INFO(C_SetPIN) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_UTF8CHAR_PTR pOldPin, /* the old PIN */ - CK_ULONG ulOldLen, /* length of the old PIN */ - CK_UTF8CHAR_PTR pNewPin, /* the new PIN */ - CK_ULONG ulNewLen /* length of the new PIN */ -); -#endif - - - -/* Session management */ - -/* C_OpenSession opens a session between an application and a - * token. */ -CK_PKCS11_FUNCTION_INFO(C_OpenSession) -#ifdef CK_NEED_ARG_LIST -( - CK_SLOT_ID slotID, /* the slot's ID */ - CK_FLAGS flags, /* from CK_SESSION_INFO */ - CK_VOID_PTR pApplication, /* passed to callback */ - CK_NOTIFY Notify, /* callback function */ - CK_SESSION_HANDLE_PTR phSession /* gets session handle */ -); -#endif - - -/* C_CloseSession closes a session between an application and a - * token. */ -CK_PKCS11_FUNCTION_INFO(C_CloseSession) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession /* the session's handle */ -); -#endif - - -/* C_CloseAllSessions closes all sessions with a token. */ -CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions) -#ifdef CK_NEED_ARG_LIST -( - CK_SLOT_ID slotID /* the token's slot */ -); -#endif - - -/* C_GetSessionInfo obtains information about the session. */ -CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_SESSION_INFO_PTR pInfo /* receives session info */ -); -#endif - - -/* C_GetOperationState obtains the state of the cryptographic operation - * in a session. */ -CK_PKCS11_FUNCTION_INFO(C_GetOperationState) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_BYTE_PTR pOperationState, /* gets state */ - CK_ULONG_PTR pulOperationStateLen /* gets state length */ -); -#endif - - -/* C_SetOperationState restores the state of the cryptographic - * operation in a session. */ -CK_PKCS11_FUNCTION_INFO(C_SetOperationState) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_BYTE_PTR pOperationState, /* holds state */ - CK_ULONG ulOperationStateLen, /* holds state length */ - CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */ - CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */ -); -#endif - - -/* C_Login logs a user into a token. */ -CK_PKCS11_FUNCTION_INFO(C_Login) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_USER_TYPE userType, /* the user type */ - CK_UTF8CHAR_PTR pPin, /* the user's PIN */ - CK_ULONG ulPinLen /* the length of the PIN */ -); -#endif - - -/* C_Logout logs a user out from a token. */ -CK_PKCS11_FUNCTION_INFO(C_Logout) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession /* the session's handle */ -); -#endif - - - -/* Object management */ - -/* C_CreateObject creates a new object. */ -CK_PKCS11_FUNCTION_INFO(C_CreateObject) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_ATTRIBUTE_PTR pTemplate, /* the object's template */ - CK_ULONG ulCount, /* attributes in template */ - CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */ -); -#endif - - -/* C_CopyObject copies an object, creating a new object for the - * copy. */ -CK_PKCS11_FUNCTION_INFO(C_CopyObject) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_OBJECT_HANDLE hObject, /* the object's handle */ - CK_ATTRIBUTE_PTR pTemplate, /* template for new object */ - CK_ULONG ulCount, /* attributes in template */ - CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */ -); -#endif - - -/* C_DestroyObject destroys an object. */ -CK_PKCS11_FUNCTION_INFO(C_DestroyObject) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_OBJECT_HANDLE hObject /* the object's handle */ -); -#endif - - -/* C_GetObjectSize gets the size of an object in bytes. */ -CK_PKCS11_FUNCTION_INFO(C_GetObjectSize) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_OBJECT_HANDLE hObject, /* the object's handle */ - CK_ULONG_PTR pulSize /* receives size of object */ -); -#endif - - -/* C_GetAttributeValue obtains the value of one or more object - * attributes. */ -CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_OBJECT_HANDLE hObject, /* the object's handle */ - CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */ - CK_ULONG ulCount /* attributes in template */ -); -#endif - - -/* C_SetAttributeValue modifies the value of one or more object - * attributes */ -CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_OBJECT_HANDLE hObject, /* the object's handle */ - CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */ - CK_ULONG ulCount /* attributes in template */ -); -#endif - - -/* C_FindObjectsInit initializes a search for token and session - * objects that match a template. */ -CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */ - CK_ULONG ulCount /* attrs in search template */ -); -#endif - - -/* C_FindObjects continues a search for token and session - * objects that match a template, obtaining additional object - * handles. */ -CK_PKCS11_FUNCTION_INFO(C_FindObjects) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */ - CK_ULONG ulMaxObjectCount, /* max handles to get */ - CK_ULONG_PTR pulObjectCount /* actual # returned */ -); -#endif - - -/* C_FindObjectsFinal finishes a search for token and session - * objects. */ -CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession /* the session's handle */ -); -#endif - - - -/* Encryption and decryption */ - -/* C_EncryptInit initializes an encryption operation. */ -CK_PKCS11_FUNCTION_INFO(C_EncryptInit) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */ - CK_OBJECT_HANDLE hKey /* handle of encryption key */ -); -#endif - - -/* C_Encrypt encrypts single-part data. */ -CK_PKCS11_FUNCTION_INFO(C_Encrypt) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_BYTE_PTR pData, /* the plaintext data */ - CK_ULONG ulDataLen, /* bytes of plaintext */ - CK_BYTE_PTR pEncryptedData, /* gets ciphertext */ - CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */ -); -#endif - - -/* C_EncryptUpdate continues a multiple-part encryption - * operation. */ -CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_BYTE_PTR pPart, /* the plaintext data */ - CK_ULONG ulPartLen, /* plaintext data len */ - CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ - CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */ -); -#endif - - -/* C_EncryptFinal finishes a multiple-part encryption - * operation. */ -CK_PKCS11_FUNCTION_INFO(C_EncryptFinal) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session handle */ - CK_BYTE_PTR pLastEncryptedPart, /* last c-text */ - CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */ -); -#endif - - -/* C_DecryptInit initializes a decryption operation. */ -CK_PKCS11_FUNCTION_INFO(C_DecryptInit) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */ - CK_OBJECT_HANDLE hKey /* handle of decryption key */ -); -#endif - - -/* C_Decrypt decrypts encrypted data in a single part. */ -CK_PKCS11_FUNCTION_INFO(C_Decrypt) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_BYTE_PTR pEncryptedData, /* ciphertext */ - CK_ULONG ulEncryptedDataLen, /* ciphertext length */ - CK_BYTE_PTR pData, /* gets plaintext */ - CK_ULONG_PTR pulDataLen /* gets p-text size */ -); -#endif - - -/* C_DecryptUpdate continues a multiple-part decryption - * operation. */ -CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_BYTE_PTR pEncryptedPart, /* encrypted data */ - CK_ULONG ulEncryptedPartLen, /* input length */ - CK_BYTE_PTR pPart, /* gets plaintext */ - CK_ULONG_PTR pulPartLen /* p-text size */ -); -#endif - - -/* C_DecryptFinal finishes a multiple-part decryption - * operation. */ -CK_PKCS11_FUNCTION_INFO(C_DecryptFinal) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pLastPart, /* gets plaintext */ - CK_ULONG_PTR pulLastPartLen /* p-text size */ -); -#endif - - - -/* Message digesting */ - -/* C_DigestInit initializes a message-digesting operation. */ -CK_PKCS11_FUNCTION_INFO(C_DigestInit) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_MECHANISM_PTR pMechanism /* the digesting mechanism */ -); -#endif - - -/* C_Digest digests data in a single part. */ -CK_PKCS11_FUNCTION_INFO(C_Digest) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pData, /* data to be digested */ - CK_ULONG ulDataLen, /* bytes of data to digest */ - CK_BYTE_PTR pDigest, /* gets the message digest */ - CK_ULONG_PTR pulDigestLen /* gets digest length */ -); -#endif - - -/* C_DigestUpdate continues a multiple-part message-digesting - * operation. */ -CK_PKCS11_FUNCTION_INFO(C_DigestUpdate) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pPart, /* data to be digested */ - CK_ULONG ulPartLen /* bytes of data to be digested */ -); -#endif - - -/* C_DigestKey continues a multi-part message-digesting - * operation, by digesting the value of a secret key as part of - * the data already digested. */ -CK_PKCS11_FUNCTION_INFO(C_DigestKey) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_OBJECT_HANDLE hKey /* secret key to digest */ -); -#endif - - -/* C_DigestFinal finishes a multiple-part message-digesting - * operation. */ -CK_PKCS11_FUNCTION_INFO(C_DigestFinal) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pDigest, /* gets the message digest */ - CK_ULONG_PTR pulDigestLen /* gets byte count of digest */ -); -#endif - - - -/* Signing and MACing */ - -/* C_SignInit initializes a signature (private key encryption) - * operation, where the signature is (will be) an appendix to - * the data, and plaintext cannot be recovered from the - *signature. */ -CK_PKCS11_FUNCTION_INFO(C_SignInit) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_MECHANISM_PTR pMechanism, /* the signature mechanism */ - CK_OBJECT_HANDLE hKey /* handle of signature key */ -); -#endif - - -/* C_Sign signs (encrypts with private key) data in a single - * part, where the signature is (will be) an appendix to the - * data, and plaintext cannot be recovered from the signature. */ -CK_PKCS11_FUNCTION_INFO(C_Sign) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pData, /* the data to sign */ - CK_ULONG ulDataLen, /* count of bytes to sign */ - CK_BYTE_PTR pSignature, /* gets the signature */ - CK_ULONG_PTR pulSignatureLen /* gets signature length */ -); -#endif - - -/* C_SignUpdate continues a multiple-part signature operation, - * where the signature is (will be) an appendix to the data, - * and plaintext cannot be recovered from the signature. */ -CK_PKCS11_FUNCTION_INFO(C_SignUpdate) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pPart, /* the data to sign */ - CK_ULONG ulPartLen /* count of bytes to sign */ -); -#endif - - -/* C_SignFinal finishes a multiple-part signature operation, - * returning the signature. */ -CK_PKCS11_FUNCTION_INFO(C_SignFinal) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pSignature, /* gets the signature */ - CK_ULONG_PTR pulSignatureLen /* gets signature length */ -); -#endif - - -/* C_SignRecoverInit initializes a signature operation, where - * the data can be recovered from the signature. */ -CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_MECHANISM_PTR pMechanism, /* the signature mechanism */ - CK_OBJECT_HANDLE hKey /* handle of the signature key */ -); -#endif - - -/* C_SignRecover signs data in a single operation, where the - * data can be recovered from the signature. */ -CK_PKCS11_FUNCTION_INFO(C_SignRecover) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pData, /* the data to sign */ - CK_ULONG ulDataLen, /* count of bytes to sign */ - CK_BYTE_PTR pSignature, /* gets the signature */ - CK_ULONG_PTR pulSignatureLen /* gets signature length */ -); -#endif - - - -/* Verifying signatures and MACs */ - -/* C_VerifyInit initializes a verification operation, where the - * signature is an appendix to the data, and plaintext cannot - * cannot be recovered from the signature (e.g. DSA). */ -CK_PKCS11_FUNCTION_INFO(C_VerifyInit) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_MECHANISM_PTR pMechanism, /* the verification mechanism */ - CK_OBJECT_HANDLE hKey /* verification key */ -); -#endif - - -/* C_Verify verifies a signature in a single-part operation, - * where the signature is an appendix to the data, and plaintext - * cannot be recovered from the signature. */ -CK_PKCS11_FUNCTION_INFO(C_Verify) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pData, /* signed data */ - CK_ULONG ulDataLen, /* length of signed data */ - CK_BYTE_PTR pSignature, /* signature */ - CK_ULONG ulSignatureLen /* signature length*/ -); -#endif - - -/* C_VerifyUpdate continues a multiple-part verification - * operation, where the signature is an appendix to the data, - * and plaintext cannot be recovered from the signature. */ -CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pPart, /* signed data */ - CK_ULONG ulPartLen /* length of signed data */ -); -#endif - - -/* C_VerifyFinal finishes a multiple-part verification - * operation, checking the signature. */ -CK_PKCS11_FUNCTION_INFO(C_VerifyFinal) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pSignature, /* signature to verify */ - CK_ULONG ulSignatureLen /* signature length */ -); -#endif - - -/* C_VerifyRecoverInit initializes a signature verification - * operation, where the data is recovered from the signature. */ -CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_MECHANISM_PTR pMechanism, /* the verification mechanism */ - CK_OBJECT_HANDLE hKey /* verification key */ -); -#endif - - -/* C_VerifyRecover verifies a signature in a single-part - * operation, where the data is recovered from the signature. */ -CK_PKCS11_FUNCTION_INFO(C_VerifyRecover) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pSignature, /* signature to verify */ - CK_ULONG ulSignatureLen, /* signature length */ - CK_BYTE_PTR pData, /* gets signed data */ - CK_ULONG_PTR pulDataLen /* gets signed data len */ -); -#endif - - - -/* Dual-function cryptographic operations */ - -/* C_DigestEncryptUpdate continues a multiple-part digesting - * and encryption operation. */ -CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_BYTE_PTR pPart, /* the plaintext data */ - CK_ULONG ulPartLen, /* plaintext length */ - CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ - CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */ -); -#endif - - -/* C_DecryptDigestUpdate continues a multiple-part decryption and - * digesting operation. */ -CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_BYTE_PTR pEncryptedPart, /* ciphertext */ - CK_ULONG ulEncryptedPartLen, /* ciphertext length */ - CK_BYTE_PTR pPart, /* gets plaintext */ - CK_ULONG_PTR pulPartLen /* gets plaintext len */ -); -#endif - - -/* C_SignEncryptUpdate continues a multiple-part signing and - * encryption operation. */ -CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_BYTE_PTR pPart, /* the plaintext data */ - CK_ULONG ulPartLen, /* plaintext length */ - CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ - CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */ -); -#endif - - -/* C_DecryptVerifyUpdate continues a multiple-part decryption and - * verify operation. */ -CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_BYTE_PTR pEncryptedPart, /* ciphertext */ - CK_ULONG ulEncryptedPartLen, /* ciphertext length */ - CK_BYTE_PTR pPart, /* gets plaintext */ - CK_ULONG_PTR pulPartLen /* gets p-text length */ -); -#endif - - - -/* Key management */ - -/* C_GenerateKey generates a secret key, creating a new key - * object. */ -CK_PKCS11_FUNCTION_INFO(C_GenerateKey) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_MECHANISM_PTR pMechanism, /* key generation mech. */ - CK_ATTRIBUTE_PTR pTemplate, /* template for new key */ - CK_ULONG ulCount, /* # of attrs in template */ - CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */ -); -#endif - - -/* C_GenerateKeyPair generates a public-key/private-key pair, - * creating new key objects. */ -CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session - * handle */ - CK_MECHANISM_PTR pMechanism, /* key-gen - * mech. */ - CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template - * for pub. - * key */ - CK_ULONG ulPublicKeyAttributeCount, /* # pub. - * attrs. */ - CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template - * for priv. - * key */ - CK_ULONG ulPrivateKeyAttributeCount, /* # priv. - * attrs. */ - CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub. - * key - * handle */ - CK_OBJECT_HANDLE_PTR phPrivateKey /* gets - * priv. key - * handle */ -); -#endif - - -/* C_WrapKey wraps (i.e., encrypts) a key. */ -CK_PKCS11_FUNCTION_INFO(C_WrapKey) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */ - CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */ - CK_OBJECT_HANDLE hKey, /* key to be wrapped */ - CK_BYTE_PTR pWrappedKey, /* gets wrapped key */ - CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */ -); -#endif - - -/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new - * key object. */ -CK_PKCS11_FUNCTION_INFO(C_UnwrapKey) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */ - CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */ - CK_BYTE_PTR pWrappedKey, /* the wrapped key */ - CK_ULONG ulWrappedKeyLen, /* wrapped key len */ - CK_ATTRIBUTE_PTR pTemplate, /* new key template */ - CK_ULONG ulAttributeCount, /* template length */ - CK_OBJECT_HANDLE_PTR phKey /* gets new handle */ -); -#endif - - -/* C_DeriveKey derives a key from a base key, creating a new key - * object. */ -CK_PKCS11_FUNCTION_INFO(C_DeriveKey) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* session's handle */ - CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */ - CK_OBJECT_HANDLE hBaseKey, /* base key */ - CK_ATTRIBUTE_PTR pTemplate, /* new key template */ - CK_ULONG ulAttributeCount, /* template length */ - CK_OBJECT_HANDLE_PTR phKey /* gets new handle */ -); -#endif - - - -/* Random number generation */ - -/* C_SeedRandom mixes additional seed material into the token's - * random number generator. */ -CK_PKCS11_FUNCTION_INFO(C_SeedRandom) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR pSeed, /* the seed material */ - CK_ULONG ulSeedLen /* length of seed material */ -); -#endif - - -/* C_GenerateRandom generates random data. */ -CK_PKCS11_FUNCTION_INFO(C_GenerateRandom) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_BYTE_PTR RandomData, /* receives the random data */ - CK_ULONG ulRandomLen /* # of bytes to generate */ -); -#endif - - - -/* Parallel function management */ - -/* C_GetFunctionStatus is a legacy function; it obtains an - * updated status of a function running in parallel with an - * application. */ -CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession /* the session's handle */ -); -#endif - - -/* C_CancelFunction is a legacy function; it cancels a function - * running in parallel. */ -CK_PKCS11_FUNCTION_INFO(C_CancelFunction) -#ifdef CK_NEED_ARG_LIST -( - CK_SESSION_HANDLE hSession /* the session's handle */ -); -#endif - - - -/* Functions added in for Cryptoki Version 2.01 or later */ - -/* C_WaitForSlotEvent waits for a slot event (token insertion, - * removal, etc.) to occur. */ -CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent) -#ifdef CK_NEED_ARG_LIST -( - CK_FLAGS flags, /* blocking/nonblocking flag */ - CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */ - CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */ -); -#endif diff --git a/src/pluto/rsaref/pkcs11t.h b/src/pluto/rsaref/pkcs11t.h deleted file mode 100644 index 3da20b215..000000000 --- a/src/pluto/rsaref/pkcs11t.h +++ /dev/null @@ -1,1685 +0,0 @@ -/* pkcs11t.h include file for PKCS #11. */ -/* $Revision: 1.2 $ */ - -/* License to copy and use this software is granted provided that it is - * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface - * (Cryptoki)" in all material mentioning or referencing this software. - - * License is also granted to make and use derivative works provided that - * such works are identified as "derived from the RSA Security Inc. PKCS #11 - * Cryptographic Token Interface (Cryptoki)" in all material mentioning or - * referencing the derived work. - - * RSA 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. - */ - -/* See top of pkcs11.h for information about the macros that - * must be defined and the structure-packing conventions that - * must be set before including this file. */ - -#ifndef _PKCS11T_H_ -#define _PKCS11T_H_ 1 - -#define CK_TRUE 1 -#define CK_FALSE 0 - -#ifndef CK_DISABLE_TRUE_FALSE -#ifndef FALSE -#define FALSE CK_FALSE -#endif - -#ifndef TRUE -#define TRUE CK_TRUE -#endif -#endif - -/* an unsigned 8-bit value */ -typedef unsigned char CK_BYTE; - -/* an unsigned 8-bit character */ -typedef CK_BYTE CK_CHAR; - -/* an 8-bit UTF-8 character */ -typedef CK_BYTE CK_UTF8CHAR; - -/* a BYTE-sized Boolean flag */ -typedef CK_BYTE CK_BBOOL; - -/* an unsigned value, at least 32 bits long */ -typedef unsigned long int CK_ULONG; - -/* a signed value, the same size as a CK_ULONG */ -/* CK_LONG is new for v2.0 */ -typedef long int CK_LONG; - -/* at least 32 bits; each bit is a Boolean flag */ -typedef CK_ULONG CK_FLAGS; - - -/* some special values for certain CK_ULONG variables */ -#define CK_UNAVAILABLE_INFORMATION (~0UL) -#define CK_EFFECTIVELY_INFINITE 0 - - -typedef CK_BYTE CK_PTR CK_BYTE_PTR; -typedef CK_CHAR CK_PTR CK_CHAR_PTR; -typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR; -typedef CK_ULONG CK_PTR CK_ULONG_PTR; -typedef void CK_PTR CK_VOID_PTR; - -/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */ -typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR; - - -/* The following value is always invalid if used as a session */ -/* handle or object handle */ -#define CK_INVALID_HANDLE 0 - - -typedef struct CK_VERSION { - CK_BYTE major; /* integer portion of version number */ - CK_BYTE minor; /* 1/100ths portion of version number */ -} CK_VERSION; - -typedef CK_VERSION CK_PTR CK_VERSION_PTR; - - -typedef struct CK_INFO { - /* manufacturerID and libraryDecription have been changed from - * CK_CHAR to CK_UTF8CHAR for v2.10 */ - CK_VERSION cryptokiVersion; /* Cryptoki interface ver */ - CK_UTF8CHAR manufacturerID[32]; /* blank padded */ - CK_FLAGS flags; /* must be zero */ - - /* libraryDescription and libraryVersion are new for v2.0 */ - CK_UTF8CHAR libraryDescription[32]; /* blank padded */ - CK_VERSION libraryVersion; /* version of library */ -} CK_INFO; - -typedef CK_INFO CK_PTR CK_INFO_PTR; - - -/* CK_NOTIFICATION enumerates the types of notifications that - * Cryptoki provides to an application */ -/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG - * for v2.0 */ -typedef CK_ULONG CK_NOTIFICATION; -#define CKN_SURRENDER 0 - - -typedef CK_ULONG CK_SLOT_ID; - -typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR; - - -/* CK_SLOT_INFO provides information about a slot */ -typedef struct CK_SLOT_INFO { - /* slotDescription and manufacturerID have been changed from - * CK_CHAR to CK_UTF8CHAR for v2.10 */ - CK_UTF8CHAR slotDescription[64]; /* blank padded */ - CK_UTF8CHAR manufacturerID[32]; /* blank padded */ - CK_FLAGS flags; - - /* hardwareVersion and firmwareVersion are new for v2.0 */ - CK_VERSION hardwareVersion; /* version of hardware */ - CK_VERSION firmwareVersion; /* version of firmware */ -} CK_SLOT_INFO; - -/* flags: bit flags that provide capabilities of the slot - * Bit Flag Mask Meaning - */ -#define CKF_TOKEN_PRESENT 0x00000001 /* a token is there */ -#define CKF_REMOVABLE_DEVICE 0x00000002 /* removable devices*/ -#define CKF_HW_SLOT 0x00000004 /* hardware slot */ - -typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR; - - -/* CK_TOKEN_INFO provides information about a token */ -typedef struct CK_TOKEN_INFO { - /* label, manufacturerID, and model have been changed from - * CK_CHAR to CK_UTF8CHAR for v2.10 */ - CK_UTF8CHAR label[32]; /* blank padded */ - CK_UTF8CHAR manufacturerID[32]; /* blank padded */ - CK_UTF8CHAR model[16]; /* blank padded */ - CK_CHAR serialNumber[16]; /* blank padded */ - CK_FLAGS flags; /* see below */ - - /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount, - * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been - * changed from CK_USHORT to CK_ULONG for v2.0 */ - CK_ULONG ulMaxSessionCount; /* max open sessions */ - CK_ULONG ulSessionCount; /* sess. now open */ - CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */ - CK_ULONG ulRwSessionCount; /* R/W sess. now open */ - CK_ULONG ulMaxPinLen; /* in bytes */ - CK_ULONG ulMinPinLen; /* in bytes */ - CK_ULONG ulTotalPublicMemory; /* in bytes */ - CK_ULONG ulFreePublicMemory; /* in bytes */ - CK_ULONG ulTotalPrivateMemory; /* in bytes */ - CK_ULONG ulFreePrivateMemory; /* in bytes */ - - /* hardwareVersion, firmwareVersion, and time are new for - * v2.0 */ - CK_VERSION hardwareVersion; /* version of hardware */ - CK_VERSION firmwareVersion; /* version of firmware */ - CK_CHAR utcTime[16]; /* time */ -} CK_TOKEN_INFO; - -/* The flags parameter is defined as follows: - * Bit Flag Mask Meaning - */ -#define CKF_RNG 0x00000001 /* has random # - * generator */ -#define CKF_WRITE_PROTECTED 0x00000002 /* token is - * write- - * protected */ -#define CKF_LOGIN_REQUIRED 0x00000004 /* user must - * login */ -#define CKF_USER_PIN_INITIALIZED 0x00000008 /* normal user's - * PIN is set */ - -/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0. If it is set, - * that means that *every* time the state of cryptographic - * operations of a session is successfully saved, all keys - * needed to continue those operations are stored in the state */ -#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020 - -/* CKF_CLOCK_ON_TOKEN is new for v2.0. If it is set, that means - * that the token has some sort of clock. The time on that - * clock is returned in the token info structure */ -#define CKF_CLOCK_ON_TOKEN 0x00000040 - -/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0. If it is - * set, that means that there is some way for the user to login - * without sending a PIN through the Cryptoki library itself */ -#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100 - -/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0. If it is true, - * that means that a single session with the token can perform - * dual simultaneous cryptographic operations (digest and - * encrypt; decrypt and digest; sign and encrypt; and decrypt - * and sign) */ -#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200 - -/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the - * token has been initialized using C_InitializeToken or an - * equivalent mechanism outside the scope of PKCS #11. - * Calling C_InitializeToken when this flag is set will cause - * the token to be reinitialized. */ -#define CKF_TOKEN_INITIALIZED 0x00000400 - -/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is - * true, the token supports secondary authentication for - * private key objects. This flag is deprecated in v2.11 and - onwards. */ -#define CKF_SECONDARY_AUTHENTICATION 0x00000800 - -/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an - * incorrect user login PIN has been entered at least once - * since the last successful authentication. */ -#define CKF_USER_PIN_COUNT_LOW 0x00010000 - -/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true, - * supplying an incorrect user PIN will it to become locked. */ -#define CKF_USER_PIN_FINAL_TRY 0x00020000 - -/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the - * user PIN has been locked. User login to the token is not - * possible. */ -#define CKF_USER_PIN_LOCKED 0x00040000 - -/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true, - * the user PIN value is the default value set by token - * initialization or manufacturing, or the PIN has been - * expired by the card. */ -#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000 - -/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an - * incorrect SO login PIN has been entered at least once since - * the last successful authentication. */ -#define CKF_SO_PIN_COUNT_LOW 0x00100000 - -/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true, - * supplying an incorrect SO PIN will it to become locked. */ -#define CKF_SO_PIN_FINAL_TRY 0x00200000 - -/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO - * PIN has been locked. SO login to the token is not possible. - */ -#define CKF_SO_PIN_LOCKED 0x00400000 - -/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true, - * the SO PIN value is the default value set by token - * initialization or manufacturing, or the PIN has been - * expired by the card. */ -#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000 - -typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR; - - -/* CK_SESSION_HANDLE is a Cryptoki-assigned value that - * identifies a session */ -typedef CK_ULONG CK_SESSION_HANDLE; - -typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR; - - -/* CK_USER_TYPE enumerates the types of Cryptoki users */ -/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for - * v2.0 */ -typedef CK_ULONG CK_USER_TYPE; -/* Security Officer */ -#define CKU_SO 0 -/* Normal user */ -#define CKU_USER 1 -/* Context specific (added in v2.20) */ -#define CKU_CONTEXT_SPECIFIC 2 - -/* CK_STATE enumerates the session states */ -/* CK_STATE has been changed from an enum to a CK_ULONG for - * v2.0 */ -typedef CK_ULONG CK_STATE; -#define CKS_RO_PUBLIC_SESSION 0 -#define CKS_RO_USER_FUNCTIONS 1 -#define CKS_RW_PUBLIC_SESSION 2 -#define CKS_RW_USER_FUNCTIONS 3 -#define CKS_RW_SO_FUNCTIONS 4 - - -/* CK_SESSION_INFO provides information about a session */ -typedef struct CK_SESSION_INFO { - CK_SLOT_ID slotID; - CK_STATE state; - CK_FLAGS flags; /* see below */ - - /* ulDeviceError was changed from CK_USHORT to CK_ULONG for - * v2.0 */ - CK_ULONG ulDeviceError; /* device-dependent error code */ -} CK_SESSION_INFO; - -/* The flags are defined in the following table: - * Bit Flag Mask Meaning - */ -#define CKF_RW_SESSION 0x00000002 /* session is r/w */ -#define CKF_SERIAL_SESSION 0x00000004 /* no parallel */ - -typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR; - - -/* CK_OBJECT_HANDLE is a token-specific identifier for an - * object */ -typedef CK_ULONG CK_OBJECT_HANDLE; - -typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR; - - -/* CK_OBJECT_CLASS is a value that identifies the classes (or - * types) of objects that Cryptoki recognizes. It is defined - * as follows: */ -/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for - * v2.0 */ -typedef CK_ULONG CK_OBJECT_CLASS; - -/* The following classes of objects are defined: */ -/* CKO_HW_FEATURE is new for v2.10 */ -/* CKO_DOMAIN_PARAMETERS is new for v2.11 */ -/* CKO_MECHANISM is new for v2.20 */ -#define CKO_DATA 0x00000000 -#define CKO_CERTIFICATE 0x00000001 -#define CKO_PUBLIC_KEY 0x00000002 -#define CKO_PRIVATE_KEY 0x00000003 -#define CKO_SECRET_KEY 0x00000004 -#define CKO_HW_FEATURE 0x00000005 -#define CKO_DOMAIN_PARAMETERS 0x00000006 -#define CKO_MECHANISM 0x00000007 -#define CKO_VENDOR_DEFINED 0x80000000 - -typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR; - -/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a - * value that identifies the hardware feature type of an object - * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */ -typedef CK_ULONG CK_HW_FEATURE_TYPE; - -/* The following hardware feature types are defined */ -/* CKH_USER_INTERFACE is new for v2.20 */ -#define CKH_MONOTONIC_COUNTER 0x00000001 -#define CKH_CLOCK 0x00000002 -#define CKH_USER_INTERFACE 0x00000003 -#define CKH_VENDOR_DEFINED 0x80000000 - -/* CK_KEY_TYPE is a value that identifies a key type */ -/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */ -typedef CK_ULONG CK_KEY_TYPE; - -/* the following key types are defined: */ -#define CKK_RSA 0x00000000 -#define CKK_DSA 0x00000001 -#define CKK_DH 0x00000002 - -/* CKK_ECDSA and CKK_KEA are new for v2.0 */ -/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */ -#define CKK_ECDSA 0x00000003 -#define CKK_EC 0x00000003 -#define CKK_X9_42_DH 0x00000004 -#define CKK_KEA 0x00000005 - -#define CKK_GENERIC_SECRET 0x00000010 -#define CKK_RC2 0x00000011 -#define CKK_RC4 0x00000012 -#define CKK_DES 0x00000013 -#define CKK_DES2 0x00000014 -#define CKK_DES3 0x00000015 - -/* all these key types are new for v2.0 */ -#define CKK_CAST 0x00000016 -#define CKK_CAST3 0x00000017 -/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */ -#define CKK_CAST5 0x00000018 -#define CKK_CAST128 0x00000018 -#define CKK_RC5 0x00000019 -#define CKK_IDEA 0x0000001A -#define CKK_SKIPJACK 0x0000001B -#define CKK_BATON 0x0000001C -#define CKK_JUNIPER 0x0000001D -#define CKK_CDMF 0x0000001E -#define CKK_AES 0x0000001F - -/* BlowFish and TwoFish are new for v2.20 */ -#define CKK_BLOWFISH 0x00000020 -#define CKK_TWOFISH 0x00000021 - -#define CKK_VENDOR_DEFINED 0x80000000 - - -/* CK_CERTIFICATE_TYPE is a value that identifies a certificate - * type */ -/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG - * for v2.0 */ -typedef CK_ULONG CK_CERTIFICATE_TYPE; - -/* The following certificate types are defined: */ -/* CKC_X_509_ATTR_CERT is new for v2.10 */ -/* CKC_WTLS is new for v2.20 */ -#define CKC_X_509 0x00000000 -#define CKC_X_509_ATTR_CERT 0x00000001 -#define CKC_WTLS 0x00000002 -#define CKC_VENDOR_DEFINED 0x80000000 - - -/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute - * type */ -/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for - * v2.0 */ -typedef CK_ULONG CK_ATTRIBUTE_TYPE; - -/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which - consists of an array of values. */ -#define CKF_ARRAY_ATTRIBUTE 0x40000000 - -/* The following attribute types are defined: */ -#define CKA_CLASS 0x00000000 -#define CKA_TOKEN 0x00000001 -#define CKA_PRIVATE 0x00000002 -#define CKA_LABEL 0x00000003 -#define CKA_APPLICATION 0x00000010 -#define CKA_VALUE 0x00000011 - -/* CKA_OBJECT_ID is new for v2.10 */ -#define CKA_OBJECT_ID 0x00000012 - -#define CKA_CERTIFICATE_TYPE 0x00000080 -#define CKA_ISSUER 0x00000081 -#define CKA_SERIAL_NUMBER 0x00000082 - -/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new - * for v2.10 */ -#define CKA_AC_ISSUER 0x00000083 -#define CKA_OWNER 0x00000084 -#define CKA_ATTR_TYPES 0x00000085 - -/* CKA_TRUSTED is new for v2.11 */ -#define CKA_TRUSTED 0x00000086 - -/* CKA_CERTIFICATE_CATEGORY ... - * CKA_CHECK_VALUE are new for v2.20 */ -#define CKA_CERTIFICATE_CATEGORY 0x00000087 -#define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088 -#define CKA_URL 0x00000089 -#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008A -#define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008B -#define CKA_CHECK_VALUE 0x00000090 - -#define CKA_KEY_TYPE 0x00000100 -#define CKA_SUBJECT 0x00000101 -#define CKA_ID 0x00000102 -#define CKA_SENSITIVE 0x00000103 -#define CKA_ENCRYPT 0x00000104 -#define CKA_DECRYPT 0x00000105 -#define CKA_WRAP 0x00000106 -#define CKA_UNWRAP 0x00000107 -#define CKA_SIGN 0x00000108 -#define CKA_SIGN_RECOVER 0x00000109 -#define CKA_VERIFY 0x0000010A -#define CKA_VERIFY_RECOVER 0x0000010B -#define CKA_DERIVE 0x0000010C -#define CKA_START_DATE 0x00000110 -#define CKA_END_DATE 0x00000111 -#define CKA_MODULUS 0x00000120 -#define CKA_MODULUS_BITS 0x00000121 -#define CKA_PUBLIC_EXPONENT 0x00000122 -#define CKA_PRIVATE_EXPONENT 0x00000123 -#define CKA_PRIME_1 0x00000124 -#define CKA_PRIME_2 0x00000125 -#define CKA_EXPONENT_1 0x00000126 -#define CKA_EXPONENT_2 0x00000127 -#define CKA_COEFFICIENT 0x00000128 -#define CKA_PRIME 0x00000130 -#define CKA_SUBPRIME 0x00000131 -#define CKA_BASE 0x00000132 - -/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */ -#define CKA_PRIME_BITS 0x00000133 -#define CKA_SUBPRIME_BITS 0x00000134 -#define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS -/* (To retain backwards-compatibility) */ - -#define CKA_VALUE_BITS 0x00000160 -#define CKA_VALUE_LEN 0x00000161 - -/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE, - * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS, - * and CKA_EC_POINT are new for v2.0 */ -#define CKA_EXTRACTABLE 0x00000162 -#define CKA_LOCAL 0x00000163 -#define CKA_NEVER_EXTRACTABLE 0x00000164 -#define CKA_ALWAYS_SENSITIVE 0x00000165 - -/* CKA_KEY_GEN_MECHANISM is new for v2.11 */ -#define CKA_KEY_GEN_MECHANISM 0x00000166 - -#define CKA_MODIFIABLE 0x00000170 - -/* CKA_ECDSA_PARAMS is deprecated in v2.11, - * CKA_EC_PARAMS is preferred. */ -#define CKA_ECDSA_PARAMS 0x00000180 -#define CKA_EC_PARAMS 0x00000180 - -#define CKA_EC_POINT 0x00000181 - -/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, - * are new for v2.10. Deprecated in v2.11 and onwards. */ -#define CKA_SECONDARY_AUTH 0x00000200 -#define CKA_AUTH_PIN_FLAGS 0x00000201 - -/* CKA_ALWAYS_AUTHENTICATE ... - * CKA_UNWRAP_TEMPLATE are new for v2.20 */ -#define CKA_ALWAYS_AUTHENTICATE 0x00000202 - -#define CKA_WRAP_WITH_TRUSTED 0x00000210 -#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211) -#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212) - -/* CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET - * are new for v2.10 */ -#define CKA_HW_FEATURE_TYPE 0x00000300 -#define CKA_RESET_ON_INIT 0x00000301 -#define CKA_HAS_RESET 0x00000302 - -/* The following attributes are new for v2.20 */ -#define CKA_PIXEL_X 0x00000400 -#define CKA_PIXEL_Y 0x00000401 -#define CKA_RESOLUTION 0x00000402 -#define CKA_CHAR_ROWS 0x00000403 -#define CKA_CHAR_COLUMNS 0x00000404 -#define CKA_COLOR 0x00000405 -#define CKA_BITS_PER_PIXEL 0x00000406 -#define CKA_CHAR_SETS 0x00000480 -#define CKA_ENCODING_METHODS 0x00000481 -#define CKA_MIME_TYPES 0x00000482 -#define CKA_MECHANISM_TYPE 0x00000500 -#define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501 -#define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502 -#define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503 -#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600) - -#define CKA_VENDOR_DEFINED 0x80000000 - - -/* CK_ATTRIBUTE is a structure that includes the type, length - * and value of an attribute */ -typedef struct CK_ATTRIBUTE { - CK_ATTRIBUTE_TYPE type; - CK_VOID_PTR pValue; - - /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */ - CK_ULONG ulValueLen; /* in bytes */ -} CK_ATTRIBUTE; - -typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR; - - -/* CK_DATE is a structure that defines a date */ -typedef struct CK_DATE{ - CK_CHAR year[4]; /* the year ("1900" - "9999") */ - CK_CHAR month[2]; /* the month ("01" - "12") */ - CK_CHAR day[2]; /* the day ("01" - "31") */ -} CK_DATE; - - -/* CK_MECHANISM_TYPE is a value that identifies a mechanism - * type */ -/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for - * v2.0 */ -typedef CK_ULONG CK_MECHANISM_TYPE; - -/* the following mechanism types are defined: */ -#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000 -#define CKM_RSA_PKCS 0x00000001 -#define CKM_RSA_9796 0x00000002 -#define CKM_RSA_X_509 0x00000003 - -/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS - * are new for v2.0. They are mechanisms which hash and sign */ -#define CKM_MD2_RSA_PKCS 0x00000004 -#define CKM_MD5_RSA_PKCS 0x00000005 -#define CKM_SHA1_RSA_PKCS 0x00000006 - -/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and - * CKM_RSA_PKCS_OAEP are new for v2.10 */ -#define CKM_RIPEMD128_RSA_PKCS 0x00000007 -#define CKM_RIPEMD160_RSA_PKCS 0x00000008 -#define CKM_RSA_PKCS_OAEP 0x00000009 - -/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31, - * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */ -#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A -#define CKM_RSA_X9_31 0x0000000B -#define CKM_SHA1_RSA_X9_31 0x0000000C -#define CKM_RSA_PKCS_PSS 0x0000000D -#define CKM_SHA1_RSA_PKCS_PSS 0x0000000E - -#define CKM_DSA_KEY_PAIR_GEN 0x00000010 -#define CKM_DSA 0x00000011 -#define CKM_DSA_SHA1 0x00000012 -#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020 -#define CKM_DH_PKCS_DERIVE 0x00000021 - -/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE, - * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for - * v2.11 */ -#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030 -#define CKM_X9_42_DH_DERIVE 0x00000031 -#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032 -#define CKM_X9_42_MQV_DERIVE 0x00000033 - -/* CKM_SHA256/384/512 are new for v2.20 */ -#define CKM_SHA256_RSA_PKCS 0x00000040 -#define CKM_SHA384_RSA_PKCS 0x00000041 -#define CKM_SHA512_RSA_PKCS 0x00000042 -#define CKM_SHA256_RSA_PKCS_PSS 0x00000043 -#define CKM_SHA384_RSA_PKCS_PSS 0x00000044 -#define CKM_SHA512_RSA_PKCS_PSS 0x00000045 - -#define CKM_RC2_KEY_GEN 0x00000100 -#define CKM_RC2_ECB 0x00000101 -#define CKM_RC2_CBC 0x00000102 -#define CKM_RC2_MAC 0x00000103 - -/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */ -#define CKM_RC2_MAC_GENERAL 0x00000104 -#define CKM_RC2_CBC_PAD 0x00000105 - -#define CKM_RC4_KEY_GEN 0x00000110 -#define CKM_RC4 0x00000111 -#define CKM_DES_KEY_GEN 0x00000120 -#define CKM_DES_ECB 0x00000121 -#define CKM_DES_CBC 0x00000122 -#define CKM_DES_MAC 0x00000123 - -/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */ -#define CKM_DES_MAC_GENERAL 0x00000124 -#define CKM_DES_CBC_PAD 0x00000125 - -#define CKM_DES2_KEY_GEN 0x00000130 -#define CKM_DES3_KEY_GEN 0x00000131 -#define CKM_DES3_ECB 0x00000132 -#define CKM_DES3_CBC 0x00000133 -#define CKM_DES3_MAC 0x00000134 - -/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN, - * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC, - * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */ -#define CKM_DES3_MAC_GENERAL 0x00000135 -#define CKM_DES3_CBC_PAD 0x00000136 -#define CKM_CDMF_KEY_GEN 0x00000140 -#define CKM_CDMF_ECB 0x00000141 -#define CKM_CDMF_CBC 0x00000142 -#define CKM_CDMF_MAC 0x00000143 -#define CKM_CDMF_MAC_GENERAL 0x00000144 -#define CKM_CDMF_CBC_PAD 0x00000145 - -/* the following four DES mechanisms are new for v2.20 */ -#define CKM_DES_OFB64 0x00000150 -#define CKM_DES_OFB8 0x00000151 -#define CKM_DES_CFB64 0x00000152 -#define CKM_DES_CFB8 0x00000153 - -#define CKM_MD2 0x00000200 - -/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */ -#define CKM_MD2_HMAC 0x00000201 -#define CKM_MD2_HMAC_GENERAL 0x00000202 - -#define CKM_MD5 0x00000210 - -/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */ -#define CKM_MD5_HMAC 0x00000211 -#define CKM_MD5_HMAC_GENERAL 0x00000212 - -#define CKM_SHA_1 0x00000220 - -/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */ -#define CKM_SHA_1_HMAC 0x00000221 -#define CKM_SHA_1_HMAC_GENERAL 0x00000222 - -/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC, - * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC, - * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */ -#define CKM_RIPEMD128 0x00000230 -#define CKM_RIPEMD128_HMAC 0x00000231 -#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232 -#define CKM_RIPEMD160 0x00000240 -#define CKM_RIPEMD160_HMAC 0x00000241 -#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242 - -/* CKM_SHA256/384/512 are new for v2.20 */ -#define CKM_SHA256 0x00000250 -#define CKM_SHA256_HMAC 0x00000251 -#define CKM_SHA256_HMAC_GENERAL 0x00000252 -#define CKM_SHA384 0x00000260 -#define CKM_SHA384_HMAC 0x00000261 -#define CKM_SHA384_HMAC_GENERAL 0x00000262 -#define CKM_SHA512 0x00000270 -#define CKM_SHA512_HMAC 0x00000271 -#define CKM_SHA512_HMAC_GENERAL 0x00000272 - -/* All of the following mechanisms are new for v2.0 */ -/* Note that CAST128 and CAST5 are the same algorithm */ -#define CKM_CAST_KEY_GEN 0x00000300 -#define CKM_CAST_ECB 0x00000301 -#define CKM_CAST_CBC 0x00000302 -#define CKM_CAST_MAC 0x00000303 -#define CKM_CAST_MAC_GENERAL 0x00000304 -#define CKM_CAST_CBC_PAD 0x00000305 -#define CKM_CAST3_KEY_GEN 0x00000310 -#define CKM_CAST3_ECB 0x00000311 -#define CKM_CAST3_CBC 0x00000312 -#define CKM_CAST3_MAC 0x00000313 -#define CKM_CAST3_MAC_GENERAL 0x00000314 -#define CKM_CAST3_CBC_PAD 0x00000315 -#define CKM_CAST5_KEY_GEN 0x00000320 -#define CKM_CAST128_KEY_GEN 0x00000320 -#define CKM_CAST5_ECB 0x00000321 -#define CKM_CAST128_ECB 0x00000321 -#define CKM_CAST5_CBC 0x00000322 -#define CKM_CAST128_CBC 0x00000322 -#define CKM_CAST5_MAC 0x00000323 -#define CKM_CAST128_MAC 0x00000323 -#define CKM_CAST5_MAC_GENERAL 0x00000324 -#define CKM_CAST128_MAC_GENERAL 0x00000324 -#define CKM_CAST5_CBC_PAD 0x00000325 -#define CKM_CAST128_CBC_PAD 0x00000325 -#define CKM_RC5_KEY_GEN 0x00000330 -#define CKM_RC5_ECB 0x00000331 -#define CKM_RC5_CBC 0x00000332 -#define CKM_RC5_MAC 0x00000333 -#define CKM_RC5_MAC_GENERAL 0x00000334 -#define CKM_RC5_CBC_PAD 0x00000335 -#define CKM_IDEA_KEY_GEN 0x00000340 -#define CKM_IDEA_ECB 0x00000341 -#define CKM_IDEA_CBC 0x00000342 -#define CKM_IDEA_MAC 0x00000343 -#define CKM_IDEA_MAC_GENERAL 0x00000344 -#define CKM_IDEA_CBC_PAD 0x00000345 -#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350 -#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360 -#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362 -#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363 -#define CKM_XOR_BASE_AND_DATA 0x00000364 -#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365 -#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370 -#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371 -#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372 - -/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN, - * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and - * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */ -#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373 -#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374 -#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375 -#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376 -#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377 - -/* CKM_TLS_PRF is new for v2.20 */ -#define CKM_TLS_PRF 0x00000378 - -#define CKM_SSL3_MD5_MAC 0x00000380 -#define CKM_SSL3_SHA1_MAC 0x00000381 -#define CKM_MD5_KEY_DERIVATION 0x00000390 -#define CKM_MD2_KEY_DERIVATION 0x00000391 -#define CKM_SHA1_KEY_DERIVATION 0x00000392 - -/* CKM_SHA256/384/512 are new for v2.20 */ -#define CKM_SHA256_KEY_DERIVATION 0x00000393 -#define CKM_SHA384_KEY_DERIVATION 0x00000394 -#define CKM_SHA512_KEY_DERIVATION 0x00000395 - -#define CKM_PBE_MD2_DES_CBC 0x000003A0 -#define CKM_PBE_MD5_DES_CBC 0x000003A1 -#define CKM_PBE_MD5_CAST_CBC 0x000003A2 -#define CKM_PBE_MD5_CAST3_CBC 0x000003A3 -#define CKM_PBE_MD5_CAST5_CBC 0x000003A4 -#define CKM_PBE_MD5_CAST128_CBC 0x000003A4 -#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5 -#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5 -#define CKM_PBE_SHA1_RC4_128 0x000003A6 -#define CKM_PBE_SHA1_RC4_40 0x000003A7 -#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8 -#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9 -#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA -#define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB - -/* CKM_PKCS5_PBKD2 is new for v2.10 */ -#define CKM_PKCS5_PBKD2 0x000003B0 - -#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0 - -/* WTLS mechanisms are new for v2.20 */ -#define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003D0 -#define CKM_WTLS_MASTER_KEY_DERIVE 0x000003D1 -#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003D2 -#define CKM_WTLS_PRF 0x000003D3 -#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003D4 -#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003D5 - -#define CKM_KEY_WRAP_LYNKS 0x00000400 -#define CKM_KEY_WRAP_SET_OAEP 0x00000401 - -/* CKM_CMS_SIG is new for v2.20 */ -#define CKM_CMS_SIG 0x00000500 - -/* Fortezza mechanisms */ -#define CKM_SKIPJACK_KEY_GEN 0x00001000 -#define CKM_SKIPJACK_ECB64 0x00001001 -#define CKM_SKIPJACK_CBC64 0x00001002 -#define CKM_SKIPJACK_OFB64 0x00001003 -#define CKM_SKIPJACK_CFB64 0x00001004 -#define CKM_SKIPJACK_CFB32 0x00001005 -#define CKM_SKIPJACK_CFB16 0x00001006 -#define CKM_SKIPJACK_CFB8 0x00001007 -#define CKM_SKIPJACK_WRAP 0x00001008 -#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009 -#define CKM_SKIPJACK_RELAYX 0x0000100a -#define CKM_KEA_KEY_PAIR_GEN 0x00001010 -#define CKM_KEA_KEY_DERIVE 0x00001011 -#define CKM_FORTEZZA_TIMESTAMP 0x00001020 -#define CKM_BATON_KEY_GEN 0x00001030 -#define CKM_BATON_ECB128 0x00001031 -#define CKM_BATON_ECB96 0x00001032 -#define CKM_BATON_CBC128 0x00001033 -#define CKM_BATON_COUNTER 0x00001034 -#define CKM_BATON_SHUFFLE 0x00001035 -#define CKM_BATON_WRAP 0x00001036 - -/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11, - * CKM_EC_KEY_PAIR_GEN is preferred */ -#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040 -#define CKM_EC_KEY_PAIR_GEN 0x00001040 - -#define CKM_ECDSA 0x00001041 -#define CKM_ECDSA_SHA1 0x00001042 - -/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE - * are new for v2.11 */ -#define CKM_ECDH1_DERIVE 0x00001050 -#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051 -#define CKM_ECMQV_DERIVE 0x00001052 - -#define CKM_JUNIPER_KEY_GEN 0x00001060 -#define CKM_JUNIPER_ECB128 0x00001061 -#define CKM_JUNIPER_CBC128 0x00001062 -#define CKM_JUNIPER_COUNTER 0x00001063 -#define CKM_JUNIPER_SHUFFLE 0x00001064 -#define CKM_JUNIPER_WRAP 0x00001065 -#define CKM_FASTHASH 0x00001070 - -/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC, - * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN, - * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are - * new for v2.11 */ -#define CKM_AES_KEY_GEN 0x00001080 -#define CKM_AES_ECB 0x00001081 -#define CKM_AES_CBC 0x00001082 -#define CKM_AES_MAC 0x00001083 -#define CKM_AES_MAC_GENERAL 0x00001084 -#define CKM_AES_CBC_PAD 0x00001085 - -/* BlowFish and TwoFish are new for v2.20 */ -#define CKM_BLOWFISH_KEY_GEN 0x00001090 -#define CKM_BLOWFISH_CBC 0x00001091 -#define CKM_TWOFISH_KEY_GEN 0x00001092 -#define CKM_TWOFISH_CBC 0x00001093 - - -/* CKM_xxx_ENCRYPT_DATA mechanisms are new for v2.20 */ -#define CKM_DES_ECB_ENCRYPT_DATA 0x00001100 -#define CKM_DES_CBC_ENCRYPT_DATA 0x00001101 -#define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102 -#define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103 -#define CKM_AES_ECB_ENCRYPT_DATA 0x00001104 -#define CKM_AES_CBC_ENCRYPT_DATA 0x00001105 - -#define CKM_DSA_PARAMETER_GEN 0x00002000 -#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001 -#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002 - -#define CKM_VENDOR_DEFINED 0x80000000 - -typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR; - - -/* CK_MECHANISM is a structure that specifies a particular - * mechanism */ -typedef struct CK_MECHANISM { - CK_MECHANISM_TYPE mechanism; - CK_VOID_PTR pParameter; - - /* ulParameterLen was changed from CK_USHORT to CK_ULONG for - * v2.0 */ - CK_ULONG ulParameterLen; /* in bytes */ -} CK_MECHANISM; - -typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR; - - -/* CK_MECHANISM_INFO provides information about a particular - * mechanism */ -typedef struct CK_MECHANISM_INFO { - CK_ULONG ulMinKeySize; - CK_ULONG ulMaxKeySize; - CK_FLAGS flags; -} CK_MECHANISM_INFO; - -/* The flags are defined as follows: - * Bit Flag Mask Meaning */ -#define CKF_HW 0x00000001 /* performed by HW */ - -/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN, - * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER, - * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP, - * and CKF_DERIVE are new for v2.0. They specify whether or not - * a mechanism can be used for a particular task */ -#define CKF_ENCRYPT 0x00000100 -#define CKF_DECRYPT 0x00000200 -#define CKF_DIGEST 0x00000400 -#define CKF_SIGN 0x00000800 -#define CKF_SIGN_RECOVER 0x00001000 -#define CKF_VERIFY 0x00002000 -#define CKF_VERIFY_RECOVER 0x00004000 -#define CKF_GENERATE 0x00008000 -#define CKF_GENERATE_KEY_PAIR 0x00010000 -#define CKF_WRAP 0x00020000 -#define CKF_UNWRAP 0x00040000 -#define CKF_DERIVE 0x00080000 - -/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE, - * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They - * describe a token's EC capabilities not available in mechanism - * information. */ -#define CKF_EC_F_P 0x00100000 -#define CKF_EC_F_2M 0x00200000 -#define CKF_EC_ECPARAMETERS 0x00400000 -#define CKF_EC_NAMEDCURVE 0x00800000 -#define CKF_EC_UNCOMPRESS 0x01000000 -#define CKF_EC_COMPRESS 0x02000000 - -#define CKF_EXTENSION 0x80000000 /* FALSE for this version */ - -typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR; - - -/* CK_RV is a value that identifies the return value of a - * Cryptoki function */ -/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */ -typedef CK_ULONG CK_RV; - -#define CKR_OK 0x00000000 -#define CKR_CANCEL 0x00000001 -#define CKR_HOST_MEMORY 0x00000002 -#define CKR_SLOT_ID_INVALID 0x00000003 - -/* CKR_FLAGS_INVALID was removed for v2.0 */ - -/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */ -#define CKR_GENERAL_ERROR 0x00000005 -#define CKR_FUNCTION_FAILED 0x00000006 - -/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS, - * and CKR_CANT_LOCK are new for v2.01 */ -#define CKR_ARGUMENTS_BAD 0x00000007 -#define CKR_NO_EVENT 0x00000008 -#define CKR_NEED_TO_CREATE_THREADS 0x00000009 -#define CKR_CANT_LOCK 0x0000000A - -#define CKR_ATTRIBUTE_READ_ONLY 0x00000010 -#define CKR_ATTRIBUTE_SENSITIVE 0x00000011 -#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012 -#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013 -#define CKR_DATA_INVALID 0x00000020 -#define CKR_DATA_LEN_RANGE 0x00000021 -#define CKR_DEVICE_ERROR 0x00000030 -#define CKR_DEVICE_MEMORY 0x00000031 -#define CKR_DEVICE_REMOVED 0x00000032 -#define CKR_ENCRYPTED_DATA_INVALID 0x00000040 -#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041 -#define CKR_FUNCTION_CANCELED 0x00000050 -#define CKR_FUNCTION_NOT_PARALLEL 0x00000051 - -/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */ -#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054 - -#define CKR_KEY_HANDLE_INVALID 0x00000060 - -/* CKR_KEY_SENSITIVE was removed for v2.0 */ - -#define CKR_KEY_SIZE_RANGE 0x00000062 -#define CKR_KEY_TYPE_INCONSISTENT 0x00000063 - -/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED, - * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED, - * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for - * v2.0 */ -#define CKR_KEY_NOT_NEEDED 0x00000064 -#define CKR_KEY_CHANGED 0x00000065 -#define CKR_KEY_NEEDED 0x00000066 -#define CKR_KEY_INDIGESTIBLE 0x00000067 -#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068 -#define CKR_KEY_NOT_WRAPPABLE 0x00000069 -#define CKR_KEY_UNEXTRACTABLE 0x0000006A - -#define CKR_MECHANISM_INVALID 0x00000070 -#define CKR_MECHANISM_PARAM_INVALID 0x00000071 - -/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID - * were removed for v2.0 */ -#define CKR_OBJECT_HANDLE_INVALID 0x00000082 -#define CKR_OPERATION_ACTIVE 0x00000090 -#define CKR_OPERATION_NOT_INITIALIZED 0x00000091 -#define CKR_PIN_INCORRECT 0x000000A0 -#define CKR_PIN_INVALID 0x000000A1 -#define CKR_PIN_LEN_RANGE 0x000000A2 - -/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */ -#define CKR_PIN_EXPIRED 0x000000A3 -#define CKR_PIN_LOCKED 0x000000A4 - -#define CKR_SESSION_CLOSED 0x000000B0 -#define CKR_SESSION_COUNT 0x000000B1 -#define CKR_SESSION_HANDLE_INVALID 0x000000B3 -#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4 -#define CKR_SESSION_READ_ONLY 0x000000B5 -#define CKR_SESSION_EXISTS 0x000000B6 - -/* CKR_SESSION_READ_ONLY_EXISTS and - * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */ -#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7 -#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8 - -#define CKR_SIGNATURE_INVALID 0x000000C0 -#define CKR_SIGNATURE_LEN_RANGE 0x000000C1 -#define CKR_TEMPLATE_INCOMPLETE 0x000000D0 -#define CKR_TEMPLATE_INCONSISTENT 0x000000D1 -#define CKR_TOKEN_NOT_PRESENT 0x000000E0 -#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1 -#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2 -#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0 -#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1 -#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2 -#define CKR_USER_ALREADY_LOGGED_IN 0x00000100 -#define CKR_USER_NOT_LOGGED_IN 0x00000101 -#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102 -#define CKR_USER_TYPE_INVALID 0x00000103 - -/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES - * are new to v2.01 */ -#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104 -#define CKR_USER_TOO_MANY_TYPES 0x00000105 - -#define CKR_WRAPPED_KEY_INVALID 0x00000110 -#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112 -#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113 -#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114 -#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115 -#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120 - -/* These are new to v2.0 */ -#define CKR_RANDOM_NO_RNG 0x00000121 - -/* These are new to v2.11 */ -#define CKR_DOMAIN_PARAMS_INVALID 0x00000130 - -/* These are new to v2.0 */ -#define CKR_BUFFER_TOO_SMALL 0x00000150 -#define CKR_SAVED_STATE_INVALID 0x00000160 -#define CKR_INFORMATION_SENSITIVE 0x00000170 -#define CKR_STATE_UNSAVEABLE 0x00000180 - -/* These are new to v2.01 */ -#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190 -#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191 -#define CKR_MUTEX_BAD 0x000001A0 -#define CKR_MUTEX_NOT_LOCKED 0x000001A1 - -/* This is new to v2.20 */ -#define CKR_FUNCTION_REJECTED 0x00000200 - -#define CKR_VENDOR_DEFINED 0x80000000 - - -/* CK_NOTIFY is an application callback that processes events */ -typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)( - CK_SESSION_HANDLE hSession, /* the session's handle */ - CK_NOTIFICATION event, - CK_VOID_PTR pApplication /* passed to C_OpenSession */ -); - - -/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec - * version and pointers of appropriate types to all the - * Cryptoki functions */ -/* CK_FUNCTION_LIST is new for v2.0 */ -typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST; - -typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR; - -typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR; - - -/* CK_CREATEMUTEX is an application callback for creating a - * mutex object */ -typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)( - CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */ -); - - -/* CK_DESTROYMUTEX is an application callback for destroying a - * mutex object */ -typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)( - CK_VOID_PTR pMutex /* pointer to mutex */ -); - - -/* CK_LOCKMUTEX is an application callback for locking a mutex */ -typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)( - CK_VOID_PTR pMutex /* pointer to mutex */ -); - - -/* CK_UNLOCKMUTEX is an application callback for unlocking a - * mutex */ -typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)( - CK_VOID_PTR pMutex /* pointer to mutex */ -); - - -/* CK_C_INITIALIZE_ARGS provides the optional arguments to - * C_Initialize */ -typedef struct CK_C_INITIALIZE_ARGS { - CK_CREATEMUTEX CreateMutex; - CK_DESTROYMUTEX DestroyMutex; - CK_LOCKMUTEX LockMutex; - CK_UNLOCKMUTEX UnlockMutex; - CK_FLAGS flags; - CK_VOID_PTR pReserved; -} CK_C_INITIALIZE_ARGS; - -/* flags: bit flags that provide capabilities of the slot - * Bit Flag Mask Meaning - */ -#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001 -#define CKF_OS_LOCKING_OK 0x00000002 - -typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR; - - -/* additional flags for parameters to functions */ - -/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */ -#define CKF_DONT_BLOCK 1 - -/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10. - * CK_RSA_PKCS_OAEP_MGF_TYPE is used to indicate the Message - * Generation Function (MGF) applied to a message block when - * formatting a message block for the PKCS #1 OAEP encryption - * scheme. */ -typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE; - -typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR; - -/* The following MGFs are defined */ -/* CKG_MGF1_SHA256, CKG_MGF1_SHA384, and CKG_MGF1_SHA512 - * are new for v2.20 */ -#define CKG_MGF1_SHA1 0x00000001 -#define CKG_MGF1_SHA256 0x00000002 -#define CKG_MGF1_SHA384 0x00000003 -#define CKG_MGF1_SHA512 0x00000004 - -/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10. - * CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source - * of the encoding parameter when formatting a message block - * for the PKCS #1 OAEP encryption scheme. */ -typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE; - -typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR; - -/* The following encoding parameter sources are defined */ -#define CKZ_DATA_SPECIFIED 0x00000001 - -/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10. - * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the - * CKM_RSA_PKCS_OAEP mechanism. */ -typedef struct CK_RSA_PKCS_OAEP_PARAMS { - CK_MECHANISM_TYPE hashAlg; - CK_RSA_PKCS_MGF_TYPE mgf; - CK_RSA_PKCS_OAEP_SOURCE_TYPE source; - CK_VOID_PTR pSourceData; - CK_ULONG ulSourceDataLen; -} CK_RSA_PKCS_OAEP_PARAMS; - -typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR; - -/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11. - * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the - * CKM_RSA_PKCS_PSS mechanism(s). */ -typedef struct CK_RSA_PKCS_PSS_PARAMS { - CK_MECHANISM_TYPE hashAlg; - CK_RSA_PKCS_MGF_TYPE mgf; - CK_ULONG sLen; -} CK_RSA_PKCS_PSS_PARAMS; - -typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR; - -/* CK_EC_KDF_TYPE is new for v2.11. */ -typedef CK_ULONG CK_EC_KDF_TYPE; - -/* The following EC Key Derivation Functions are defined */ -#define CKD_NULL 0x00000001 -#define CKD_SHA1_KDF 0x00000002 - -/* CK_ECDH1_DERIVE_PARAMS is new for v2.11. - * CK_ECDH1_DERIVE_PARAMS provides the parameters to the - * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms, - * where each party contributes one key pair. - */ -typedef struct CK_ECDH1_DERIVE_PARAMS { - CK_EC_KDF_TYPE kdf; - CK_ULONG ulSharedDataLen; - CK_BYTE_PTR pSharedData; - CK_ULONG ulPublicDataLen; - CK_BYTE_PTR pPublicData; -} CK_ECDH1_DERIVE_PARAMS; - -typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR; - - -/* CK_ECDH2_DERIVE_PARAMS is new for v2.11. - * CK_ECDH2_DERIVE_PARAMS provides the parameters to the - * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */ -typedef struct CK_ECDH2_DERIVE_PARAMS { - CK_EC_KDF_TYPE kdf; - CK_ULONG ulSharedDataLen; - CK_BYTE_PTR pSharedData; - CK_ULONG ulPublicDataLen; - CK_BYTE_PTR pPublicData; - CK_ULONG ulPrivateDataLen; - CK_OBJECT_HANDLE hPrivateData; - CK_ULONG ulPublicDataLen2; - CK_BYTE_PTR pPublicData2; -} CK_ECDH2_DERIVE_PARAMS; - -typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR; - -typedef struct CK_ECMQV_DERIVE_PARAMS { - CK_EC_KDF_TYPE kdf; - CK_ULONG ulSharedDataLen; - CK_BYTE_PTR pSharedData; - CK_ULONG ulPublicDataLen; - CK_BYTE_PTR pPublicData; - CK_ULONG ulPrivateDataLen; - CK_OBJECT_HANDLE hPrivateData; - CK_ULONG ulPublicDataLen2; - CK_BYTE_PTR pPublicData2; - CK_OBJECT_HANDLE publicKey; -} CK_ECMQV_DERIVE_PARAMS; - -typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR; - -/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the - * CKM_X9_42_DH_PARAMETER_GEN mechanisms (new for PKCS #11 v2.11) */ -typedef CK_ULONG CK_X9_42_DH_KDF_TYPE; -typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR; - -/* The following X9.42 DH key derivation functions are defined - (besides CKD_NULL already defined : */ -#define CKD_SHA1_KDF_ASN1 0x00000003 -#define CKD_SHA1_KDF_CONCATENATE 0x00000004 - -/* CK_X9_42_DH1_DERIVE_PARAMS is new for v2.11. - * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the - * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party - * contributes one key pair */ -typedef struct CK_X9_42_DH1_DERIVE_PARAMS { - CK_X9_42_DH_KDF_TYPE kdf; - CK_ULONG ulOtherInfoLen; - CK_BYTE_PTR pOtherInfo; - CK_ULONG ulPublicDataLen; - CK_BYTE_PTR pPublicData; -} CK_X9_42_DH1_DERIVE_PARAMS; - -typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR; - -/* CK_X9_42_DH2_DERIVE_PARAMS is new for v2.11. - * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the - * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation - * mechanisms, where each party contributes two key pairs */ -typedef struct CK_X9_42_DH2_DERIVE_PARAMS { - CK_X9_42_DH_KDF_TYPE kdf; - CK_ULONG ulOtherInfoLen; - CK_BYTE_PTR pOtherInfo; - CK_ULONG ulPublicDataLen; - CK_BYTE_PTR pPublicData; - CK_ULONG ulPrivateDataLen; - CK_OBJECT_HANDLE hPrivateData; - CK_ULONG ulPublicDataLen2; - CK_BYTE_PTR pPublicData2; -} CK_X9_42_DH2_DERIVE_PARAMS; - -typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR; - -typedef struct CK_X9_42_MQV_DERIVE_PARAMS { - CK_X9_42_DH_KDF_TYPE kdf; - CK_ULONG ulOtherInfoLen; - CK_BYTE_PTR pOtherInfo; - CK_ULONG ulPublicDataLen; - CK_BYTE_PTR pPublicData; - CK_ULONG ulPrivateDataLen; - CK_OBJECT_HANDLE hPrivateData; - CK_ULONG ulPublicDataLen2; - CK_BYTE_PTR pPublicData2; - CK_OBJECT_HANDLE publicKey; -} CK_X9_42_MQV_DERIVE_PARAMS; - -typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR; - -/* CK_KEA_DERIVE_PARAMS provides the parameters to the - * CKM_KEA_DERIVE mechanism */ -/* CK_KEA_DERIVE_PARAMS is new for v2.0 */ -typedef struct CK_KEA_DERIVE_PARAMS { - CK_BBOOL isSender; - CK_ULONG ulRandomLen; - CK_BYTE_PTR pRandomA; - CK_BYTE_PTR pRandomB; - CK_ULONG ulPublicDataLen; - CK_BYTE_PTR pPublicData; -} CK_KEA_DERIVE_PARAMS; - -typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR; - - -/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and - * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just - * holds the effective keysize */ -typedef CK_ULONG CK_RC2_PARAMS; - -typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR; - - -/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC - * mechanism */ -typedef struct CK_RC2_CBC_PARAMS { - /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for - * v2.0 */ - CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ - - CK_BYTE iv[8]; /* IV for CBC mode */ -} CK_RC2_CBC_PARAMS; - -typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR; - - -/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the - * CKM_RC2_MAC_GENERAL mechanism */ -/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */ -typedef struct CK_RC2_MAC_GENERAL_PARAMS { - CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ - CK_ULONG ulMacLength; /* Length of MAC in bytes */ -} CK_RC2_MAC_GENERAL_PARAMS; - -typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \ - CK_RC2_MAC_GENERAL_PARAMS_PTR; - - -/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and - * CKM_RC5_MAC mechanisms */ -/* CK_RC5_PARAMS is new for v2.0 */ -typedef struct CK_RC5_PARAMS { - CK_ULONG ulWordsize; /* wordsize in bits */ - CK_ULONG ulRounds; /* number of rounds */ -} CK_RC5_PARAMS; - -typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR; - - -/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC - * mechanism */ -/* CK_RC5_CBC_PARAMS is new for v2.0 */ -typedef struct CK_RC5_CBC_PARAMS { - CK_ULONG ulWordsize; /* wordsize in bits */ - CK_ULONG ulRounds; /* number of rounds */ - CK_BYTE_PTR pIv; /* pointer to IV */ - CK_ULONG ulIvLen; /* length of IV in bytes */ -} CK_RC5_CBC_PARAMS; - -typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR; - - -/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the - * CKM_RC5_MAC_GENERAL mechanism */ -/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */ -typedef struct CK_RC5_MAC_GENERAL_PARAMS { - CK_ULONG ulWordsize; /* wordsize in bits */ - CK_ULONG ulRounds; /* number of rounds */ - CK_ULONG ulMacLength; /* Length of MAC in bytes */ -} CK_RC5_MAC_GENERAL_PARAMS; - -typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \ - CK_RC5_MAC_GENERAL_PARAMS_PTR; - - -/* CK_MAC_GENERAL_PARAMS provides the parameters to most block - * ciphers' MAC_GENERAL mechanisms. Its value is the length of - * the MAC */ -/* CK_MAC_GENERAL_PARAMS is new for v2.0 */ -typedef CK_ULONG CK_MAC_GENERAL_PARAMS; - -typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR; - -/* CK_DES/AES_ECB/CBC_ENCRYPT_DATA_PARAMS are new for v2.20 */ -typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS { - CK_BYTE iv[8]; - CK_BYTE_PTR pData; - CK_ULONG length; -} CK_DES_CBC_ENCRYPT_DATA_PARAMS; - -typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR; - -typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS { - CK_BYTE iv[16]; - CK_BYTE_PTR pData; - CK_ULONG length; -} CK_AES_CBC_ENCRYPT_DATA_PARAMS; - -typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR; - -/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the - * CKM_SKIPJACK_PRIVATE_WRAP mechanism */ -/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */ -typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS { - CK_ULONG ulPasswordLen; - CK_BYTE_PTR pPassword; - CK_ULONG ulPublicDataLen; - CK_BYTE_PTR pPublicData; - CK_ULONG ulPAndGLen; - CK_ULONG ulQLen; - CK_ULONG ulRandomLen; - CK_BYTE_PTR pRandomA; - CK_BYTE_PTR pPrimeP; - CK_BYTE_PTR pBaseG; - CK_BYTE_PTR pSubprimeQ; -} CK_SKIPJACK_PRIVATE_WRAP_PARAMS; - -typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \ - CK_SKIPJACK_PRIVATE_WRAP_PTR; - - -/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the - * CKM_SKIPJACK_RELAYX mechanism */ -/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */ -typedef struct CK_SKIPJACK_RELAYX_PARAMS { - CK_ULONG ulOldWrappedXLen; - CK_BYTE_PTR pOldWrappedX; - CK_ULONG ulOldPasswordLen; - CK_BYTE_PTR pOldPassword; - CK_ULONG ulOldPublicDataLen; - CK_BYTE_PTR pOldPublicData; - CK_ULONG ulOldRandomLen; - CK_BYTE_PTR pOldRandomA; - CK_ULONG ulNewPasswordLen; - CK_BYTE_PTR pNewPassword; - CK_ULONG ulNewPublicDataLen; - CK_BYTE_PTR pNewPublicData; - CK_ULONG ulNewRandomLen; - CK_BYTE_PTR pNewRandomA; -} CK_SKIPJACK_RELAYX_PARAMS; - -typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \ - CK_SKIPJACK_RELAYX_PARAMS_PTR; - - -typedef struct CK_PBE_PARAMS { - CK_BYTE_PTR pInitVector; - CK_UTF8CHAR_PTR pPassword; - CK_ULONG ulPasswordLen; - CK_BYTE_PTR pSalt; - CK_ULONG ulSaltLen; - CK_ULONG ulIteration; -} CK_PBE_PARAMS; - -typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR; - - -/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the - * CKM_KEY_WRAP_SET_OAEP mechanism */ -/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */ -typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS { - CK_BYTE bBC; /* block contents byte */ - CK_BYTE_PTR pX; /* extra data */ - CK_ULONG ulXLen; /* length of extra data in bytes */ -} CK_KEY_WRAP_SET_OAEP_PARAMS; - -typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \ - CK_KEY_WRAP_SET_OAEP_PARAMS_PTR; - - -typedef struct CK_SSL3_RANDOM_DATA { - CK_BYTE_PTR pClientRandom; - CK_ULONG ulClientRandomLen; - CK_BYTE_PTR pServerRandom; - CK_ULONG ulServerRandomLen; -} CK_SSL3_RANDOM_DATA; - - -typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS { - CK_SSL3_RANDOM_DATA RandomInfo; - CK_VERSION_PTR pVersion; -} CK_SSL3_MASTER_KEY_DERIVE_PARAMS; - -typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \ - CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR; - - -typedef struct CK_SSL3_KEY_MAT_OUT { - CK_OBJECT_HANDLE hClientMacSecret; - CK_OBJECT_HANDLE hServerMacSecret; - CK_OBJECT_HANDLE hClientKey; - CK_OBJECT_HANDLE hServerKey; - CK_BYTE_PTR pIVClient; - CK_BYTE_PTR pIVServer; -} CK_SSL3_KEY_MAT_OUT; - -typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR; - - -typedef struct CK_SSL3_KEY_MAT_PARAMS { - CK_ULONG ulMacSizeInBits; - CK_ULONG ulKeySizeInBits; - CK_ULONG ulIVSizeInBits; - CK_BBOOL bIsExport; - CK_SSL3_RANDOM_DATA RandomInfo; - CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial; -} CK_SSL3_KEY_MAT_PARAMS; - -typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR; - -/* CK_TLS_PRF_PARAMS is new for version 2.20 */ -typedef struct CK_TLS_PRF_PARAMS { - CK_BYTE_PTR pSeed; - CK_ULONG ulSeedLen; - CK_BYTE_PTR pLabel; - CK_ULONG ulLabelLen; - CK_BYTE_PTR pOutput; - CK_ULONG_PTR pulOutputLen; -} CK_TLS_PRF_PARAMS; - -typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR; - -/* WTLS is new for version 2.20 */ -typedef struct CK_WTLS_RANDOM_DATA { - CK_BYTE_PTR pClientRandom; - CK_ULONG ulClientRandomLen; - CK_BYTE_PTR pServerRandom; - CK_ULONG ulServerRandomLen; -} CK_WTLS_RANDOM_DATA; - -typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR; - -typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS { - CK_MECHANISM_TYPE DigestMechanism; - CK_WTLS_RANDOM_DATA RandomInfo; - CK_BYTE_PTR pVersion; -} CK_WTLS_MASTER_KEY_DERIVE_PARAMS; - -typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \ - CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR; - -typedef struct CK_WTLS_PRF_PARAMS { - CK_MECHANISM_TYPE DigestMechanism; - CK_BYTE_PTR pSeed; - CK_ULONG ulSeedLen; - CK_BYTE_PTR pLabel; - CK_ULONG ulLabelLen; - CK_BYTE_PTR pOutput; - CK_ULONG_PTR pulOutputLen; -} CK_WTLS_PRF_PARAMS; - -typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR; - -typedef struct CK_WTLS_KEY_MAT_OUT { - CK_OBJECT_HANDLE hMacSecret; - CK_OBJECT_HANDLE hKey; - CK_BYTE_PTR pIV; -} CK_WTLS_KEY_MAT_OUT; - -typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR; - -typedef struct CK_WTLS_KEY_MAT_PARAMS { - CK_MECHANISM_TYPE DigestMechanism; - CK_ULONG ulMacSizeInBits; - CK_ULONG ulKeySizeInBits; - CK_ULONG ulIVSizeInBits; - CK_ULONG ulSequenceNumber; - CK_BBOOL bIsExport; - CK_WTLS_RANDOM_DATA RandomInfo; - CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial; -} CK_WTLS_KEY_MAT_PARAMS; - -typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR; - -/* CMS is new for version 2.20 */ -typedef struct CK_CMS_SIG_PARAMS { - CK_OBJECT_HANDLE certificateHandle; - CK_MECHANISM_PTR pSigningMechanism; - CK_MECHANISM_PTR pDigestMechanism; - CK_UTF8CHAR_PTR pContentType; - CK_BYTE_PTR pRequestedAttributes; - CK_ULONG ulRequestedAttributesLen; - CK_BYTE_PTR pRequiredAttributes; - CK_ULONG ulRequiredAttributesLen; -} CK_CMS_SIG_PARAMS; - -typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR; - -typedef struct CK_KEY_DERIVATION_STRING_DATA { - CK_BYTE_PTR pData; - CK_ULONG ulLen; -} CK_KEY_DERIVATION_STRING_DATA; - -typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \ - CK_KEY_DERIVATION_STRING_DATA_PTR; - - -/* The CK_EXTRACT_PARAMS is used for the - * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit - * of the base key should be used as the first bit of the - * derived key */ -/* CK_EXTRACT_PARAMS is new for v2.0 */ -typedef CK_ULONG CK_EXTRACT_PARAMS; - -typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR; - -/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10. - * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to - * indicate the Pseudo-Random Function (PRF) used to generate - * key bits using PKCS #5 PBKDF2. */ -typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE; - -typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR; - -/* The following PRFs are defined in PKCS #5 v2.0. */ -#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001 - - -/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10. - * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the - * source of the salt value when deriving a key using PKCS #5 - * PBKDF2. */ -typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE; - -typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR; - -/* The following salt value sources are defined in PKCS #5 v2.0. */ -#define CKZ_SALT_SPECIFIED 0x00000001 - -/* CK_PKCS5_PBKD2_PARAMS is new for v2.10. - * CK_PKCS5_PBKD2_PARAMS is a structure that provides the - * parameters to the CKM_PKCS5_PBKD2 mechanism. */ -typedef struct CK_PKCS5_PBKD2_PARAMS { - CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource; - CK_VOID_PTR pSaltSourceData; - CK_ULONG ulSaltSourceDataLen; - CK_ULONG iterations; - CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf; - CK_VOID_PTR pPrfData; - CK_ULONG ulPrfDataLen; - CK_UTF8CHAR_PTR pPassword; - CK_ULONG_PTR ulPasswordLen; -} CK_PKCS5_PBKD2_PARAMS; - -typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR; - -#endif diff --git a/src/pluto/rsaref/unix.h b/src/pluto/rsaref/unix.h deleted file mode 100644 index 2e7eb6663..000000000 --- a/src/pluto/rsaref/unix.h +++ /dev/null @@ -1,24 +0,0 @@ - - -#ifndef UNIX_H -#define UNIX_H - -#define CK_PTR * - -#define CK_DEFINE_FUNCTION(returnType, name) \ - returnType name - -#define CK_DECLARE_FUNCTION(returnType, name) \ - returnType name - -#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ - returnType (* name) - -#define CK_CALLBACK_FUNCTION(returnType, name) \ - returnType (* name) - -#ifndef NULL_PTR -#define NULL_PTR 0 -#endif - -#endif diff --git a/src/pluto/server.c b/src/pluto/server.c deleted file mode 100644 index 167b1d4c7..000000000 --- a/src/pluto/server.c +++ /dev/null @@ -1,910 +0,0 @@ -/* get-next-event loop - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <errno.h> -#include <signal.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/un.h> -#ifdef SOLARIS -# include <sys/sockio.h> /* for Solaris 2.6: defines SIOCGIFCONF */ -#endif -#include <netinet/in.h> -#include <arpa/inet.h> -#include <sys/time.h> -#include <netdb.h> -#include <unistd.h> -#include <fcntl.h> -#include <net/if.h> -#include <sys/ioctl.h> -#include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ -#include <sys/queue.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "state.h" -#include "connections.h" -#include "kernel.h" -#include "log.h" -#include "server.h" -#include "timer.h" -#include "packet.h" -#include "demux.h" /* needs packet.h */ -#include "rcv_whack.h" -#include "keys.h" -#include "adns.h" /* needs <resolv.h> */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "pluto.h" - -#include <pfkeyv2.h> -#include <pfkey.h> -#include "kameipsec.h" -#include "nat_traversal.h" - -/* - * Server main loop and socket initialization routines. - */ - -static const int on = TRUE; /* by-reference parameter; constant, we hope */ - -/* control (whack) socket */ -int ctl_fd = NULL_FD; /* file descriptor of control (whack) socket */ -struct sockaddr_un ctl_addr = { AF_UNIX, DEFAULT_CTLBASE CTL_SUFFIX }; - -/* info (showpolicy) socket */ -int policy_fd = NULL_FD; -struct sockaddr_un info_addr= { AF_UNIX, DEFAULT_CTLBASE INFO_SUFFIX }; - -/* Initialize the control socket. - * Note: this is called very early, so little infrastructure is available. - * It is important that the socket is created before the original - * Pluto process returns. - */ -err_t -init_ctl_socket(void) -{ - err_t failed = NULL; - - delete_ctl_socket(); /* preventative medicine */ - ctl_fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (ctl_fd == -1) - failed = "create"; - else if (fcntl(ctl_fd, F_SETFD, FD_CLOEXEC) == -1) - failed = "fcntl FD+CLOEXEC"; - else if (setsockopt(ctl_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) < 0) - failed = "setsockopt"; - else - { - /* to keep control socket secure, use umask */ - mode_t ou = umask(~S_IRWXU); - - if (bind(ctl_fd, (struct sockaddr *)&ctl_addr - , offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0) - failed = "bind"; - umask(ou); - } - - /* 5 is a haphazardly chosen limit for the backlog. - * Rumour has it that this is the max on BSD systems. - */ - if (failed == NULL && listen(ctl_fd, 5) < 0) - failed = "listen() on"; - - return failed == NULL? NULL : builddiag("could not %s control socket: %d %s" - , failed, errno, strerror(errno)); -} - -void -delete_ctl_socket(void) -{ - /* Is noting failure useful? Not when used as preventative medicine. */ - unlink(ctl_addr.sun_path); -} - -bool listening = FALSE; /* should we pay attention to IKE messages? */ - -struct iface *interfaces = NULL; /* public interfaces */ - -/* Initialize the interface sockets. */ - -static void -mark_ifaces_dead(void) -{ - struct iface *p; - - for (p = interfaces; p != NULL; p = p->next) - p->change = IFN_DELETE; -} - -static void -free_dead_ifaces(void) -{ - struct iface *p; - bool some_dead = FALSE - , some_new = FALSE; - - for (p = interfaces; p != NULL; p = p->next) - { - if (p->change == IFN_DELETE) - { - plog("shutting down interface %s/%s %s" - , p->vname, p->rname, ip_str(&p->addr)); - some_dead = TRUE; - } - else if (p->change == IFN_ADD) - { - some_new = TRUE; - } - } - - if (some_dead) - { - struct iface **pp; - - release_dead_interfaces(); - for (pp = &interfaces; (p = *pp) != NULL; ) - { - if (p->change == IFN_DELETE) - { - *pp = p->next; /* advance *pp */ - free(p->vname); - free(p->rname); - close(p->fd); - free(p); - } - else - { - pp = &p->next; /* advance pp */ - } - } - } - - /* this must be done after the release_dead_interfaces - * in case some to the newly unoriented connections can - * become oriented here. - */ - if (some_dead || some_new) - check_orientations(); -} - -void -free_ifaces(void) -{ - mark_ifaces_dead(); - free_dead_ifaces(); -} - -struct raw_iface { - ip_address addr; - char name[IFNAMSIZ + 20]; /* what would be a safe size? */ - struct raw_iface *next; -}; - -/* Called to handle --interface <ifname> - * Semantics: if specified, only these (real) interfaces are considered. - */ -static const char *pluto_ifn[10]; -static int pluto_ifn_roof = 0; - -bool -use_interface(const char *rifn) -{ - if (pluto_ifn_roof >= (int)countof(pluto_ifn)) - { - return FALSE; - } - else - { - pluto_ifn[pluto_ifn_roof++] = rifn; - return TRUE; - } -} - -static struct raw_iface * -find_raw_ifaces4(void) -{ - int j; /* index into buf */ - struct ifconf ifconf; - struct ifreq buf[300]; /* for list of interfaces -- arbitrary limit */ - struct raw_iface *rifaces = NULL; - int master_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Get a UDP socket */ - - /* get list of interfaces with assigned IPv4 addresses from system */ - - if (master_sock == -1) - exit_log_errno((e, "socket() failed in find_raw_ifaces4()")); - - if (setsockopt(master_sock, SOL_SOCKET, SO_REUSEADDR - , (const void *)&on, sizeof(on)) < 0) - exit_log_errno((e, "setsockopt() in find_raw_ifaces4()")); - - /* bind the socket */ - { - ip_address any; - - happy(anyaddr(AF_INET, &any)); - setportof(htons(pluto_port), &any); - if (bind(master_sock, sockaddrof(&any), sockaddrlenof(&any)) < 0) - exit_log_errno((e, "bind() failed in find_raw_ifaces4()")); - } - - /* Get local interfaces. See netdevice(7). */ - ifconf.ifc_len = sizeof(buf); - ifconf.ifc_buf = (void *) buf; - zero(buf); - - if (ioctl(master_sock, SIOCGIFCONF, &ifconf) == -1) - exit_log_errno((e, "ioctl(SIOCGIFCONF) in find_raw_ifaces4()")); - - /* Add an entry to rifaces for each interesting interface. */ - for (j = 0; (j+1) * sizeof(*buf) <= (size_t)ifconf.ifc_len; j++) - { - struct raw_iface ri; - const struct sockaddr_in *rs = (struct sockaddr_in *) &buf[j].ifr_addr; - struct ifreq auxinfo; - - /* ignore all but AF_INET interfaces */ - if (rs->sin_family != AF_INET) - continue; /* not interesting */ - - /* build a NUL-terminated copy of the rname field */ - memcpy(ri.name, buf[j].ifr_name, IFNAMSIZ); - ri.name[IFNAMSIZ] = '\0'; - - /* ignore if our interface names were specified, and this isn't one */ - if (pluto_ifn_roof != 0) - { - int i; - - for (i = 0; i != pluto_ifn_roof; i++) - if (streq(ri.name, pluto_ifn[i])) - break; - if (i == pluto_ifn_roof) - continue; /* not found -- skip */ - } - - /* Find out stuff about this interface. See netdevice(7). */ - zero(&auxinfo); /* paranoia */ - memcpy(auxinfo.ifr_name, buf[j].ifr_name, IFNAMSIZ); - if (ioctl(master_sock, SIOCGIFFLAGS, &auxinfo) == -1) - exit_log_errno((e - , "ioctl(SIOCGIFFLAGS) for %s in find_raw_ifaces4()" - , ri.name)); - if (!(auxinfo.ifr_flags & IFF_UP)) - continue; /* ignore an interface that isn't UP */ - - /* ignore unconfigured interfaces */ - if (rs->sin_addr.s_addr == 0) - continue; - - happy(initaddr((const void *)&rs->sin_addr, sizeof(struct in_addr) - , AF_INET, &ri.addr)); - - DBG(DBG_CONTROL, DBG_log("found %s with address %s" - , ri.name, ip_str(&ri.addr))); - ri.next = rifaces; - rifaces = clone_thing(ri); - } - - close(master_sock); - - return rifaces; -} - -static struct raw_iface * -find_raw_ifaces6(void) -{ - - /* Get list of interfaces with IPv6 addresses from system from /proc/net/if_inet6). - * - * Documentation of format? - * RTFS: linux-2.2.16/net/ipv6/addrconf.c:iface_proc_info() - * linux-2.4.9-13/net/ipv6/addrconf.c:iface_proc_info() - * - * Sample from Gerhard's laptop: - * 00000000000000000000000000000001 01 80 10 80 lo - * 30490009000000000000000000010002 02 40 00 80 ipsec0 - * 30490009000000000000000000010002 07 40 00 80 eth0 - * fe80000000000000025004fffefd5484 02 0a 20 80 ipsec0 - * fe80000000000000025004fffefd5484 07 0a 20 80 eth0 - * - * Each line contains: - * - IPv6 address: 16 bytes, in hex, no punctuation - * - ifindex: 1 byte, in hex - * - prefix_len: 1 byte, in hex - * - scope (e.g. global, link local): 1 byte, in hex - * - flags: 1 byte, in hex - * - device name: string, followed by '\n' - */ - struct raw_iface *rifaces = NULL; - static const char proc_name[] = "/proc/net/if_inet6"; - FILE *proc_sock = fopen(proc_name, "r"); - - if (proc_sock == NULL) - { - DBG(DBG_CONTROL, DBG_log("could not open %s", proc_name)); - } - else - { - for (;;) - { - struct raw_iface ri; - unsigned short xb[8]; /* IPv6 address as 8 16-bit chunks */ - char sb[8*5]; /* IPv6 address as string-with-colons */ - unsigned int if_idx; /* proc field, not used */ - unsigned int plen; /* proc field, not used */ - unsigned int scope; /* proc field, used to exclude link-local */ - unsigned int dad_status; /* proc field, not used */ - /* ??? I hate and distrust scanf -- DHR */ - int r = fscanf(proc_sock - , "%4hx%4hx%4hx%4hx%4hx%4hx%4hx%4hx" - " %02x %02x %02x %02x %20s\n" - , xb+0, xb+1, xb+2, xb+3, xb+4, xb+5, xb+6, xb+7 - , &if_idx, &plen, &scope, &dad_status, ri.name); - - /* ??? we should diagnose any problems */ - if (r != 13) - break; - - /* ignore addresses with link local scope. - * From linux-2.4.9-13/include/net/ipv6.h: - * IPV6_ADDR_LINKLOCAL 0x0020U - * IPV6_ADDR_SCOPE_MASK 0x00f0U - */ - if ((scope & 0x00f0U) == 0x0020U) - continue; - - snprintf(sb, sizeof(sb) - , "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" - , xb[0], xb[1], xb[2], xb[3], xb[4], xb[5], xb[6], xb[7]); - - happy(ttoaddr(sb, 0, AF_INET6, &ri.addr)); - - if (!isunspecaddr(&ri.addr)) - { - DBG(DBG_CONTROL - , DBG_log("found %s with address %s" - , ri.name, sb)); - ri.next = rifaces; - rifaces = clone_thing(ri); - } - } - fclose(proc_sock); - } - - return rifaces; -} - -static int -create_socket(struct raw_iface *ifp, const char *v_name, int port) -{ - int fd = socket(addrtypeof(&ifp->addr), SOCK_DGRAM, IPPROTO_UDP); - int fcntl_flags; - - if (fd < 0) - { - log_errno((e, "socket() in process_raw_ifaces()")); - return -1; - } - - /* Set socket Nonblocking */ - if ((fcntl_flags=fcntl(fd, F_GETFL)) >= 0) { - if (!(fcntl_flags & O_NONBLOCK)) { - fcntl_flags |= O_NONBLOCK; - fcntl(fd, F_SETFL, fcntl_flags); - } - } - - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - { - log_errno((e, "fcntl(,, FD_CLOEXEC) in process_raw_ifaces()")); - close(fd); - return -1; - } - - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR - , (const void *)&on, sizeof(on)) < 0) - { - log_errno((e, "setsockopt SO_REUSEADDR in process_raw_ifaces()")); - close(fd); - return -1; - } - - /* To improve error reporting. See ip(7). */ -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) - if (setsockopt(fd, SOL_IP, IP_RECVERR - , (const void *)&on, sizeof(on)) < 0) - { - log_errno((e, "setsockopt IP_RECVERR in process_raw_ifaces()")); - close(fd); - return -1; - } -#endif - - /* With IPv6, there is no fragmentation after - * it leaves our interface. PMTU discovery - * is mandatory but doesn't work well with IKE (why?). - * So we must set the IPV6_USE_MIN_MTU option. - * See draft-ietf-ipngwg-rfc2292bis-01.txt 11.1 - */ -#ifdef IPV6_USE_MIN_MTU /* YUCK: not always defined */ - if (addrtypeof(&ifp->addr) == AF_INET6 - && setsockopt(fd, SOL_SOCKET, IPV6_USE_MIN_MTU - , (const void *)&on, sizeof(on)) < 0) - { - log_errno((e, "setsockopt IPV6_USE_MIN_MTU in process_raw_ifaces()")); - close(fd); - return -1; - } -#endif - - { - struct sadb_x_policy policy; - int level, opt; - - policy.sadb_x_policy_len = sizeof(policy) / IPSEC_PFKEYv2_ALIGN; - policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; - policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS; - policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND; - policy.sadb_x_policy_reserved = 0; - policy.sadb_x_policy_id = 0; - policy.sadb_x_policy_reserved2 = 0; - - if (addrtypeof(&ifp->addr) == AF_INET6) - { - level = IPPROTO_IPV6; - opt = IPV6_IPSEC_POLICY; - } - else - { - level = IPPROTO_IP; - opt = IP_IPSEC_POLICY; - } - - if (setsockopt(fd, level, opt - , &policy, sizeof(policy)) < 0) - { - log_errno((e, "setsockopt IPSEC_POLICY in process_raw_ifaces()")); - close(fd); - return -1; - } - - policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; - - if (setsockopt(fd, level, opt - , &policy, sizeof(policy)) < 0) - { - log_errno((e, "setsockopt IPSEC_POLICY in process_raw_ifaces()")); - close(fd); - return -1; - } - } - - setportof(htons(port), &ifp->addr); - if (bind(fd, sockaddrof(&ifp->addr), sockaddrlenof(&ifp->addr)) < 0) - { - log_errno((e, "bind() for %s/%s %s:%u in process_raw_ifaces()" - , ifp->name, v_name - , ip_str(&ifp->addr), (unsigned) port)); - close(fd); - return -1; - } - setportof(htons(pluto_port), &ifp->addr); - return fd; -} - -static void -process_raw_ifaces(struct raw_iface *rifaces) -{ - struct raw_iface *ifp; - - /* For each real interface... - */ - for (ifp = rifaces; ifp != NULL; ifp = ifp->next) - { - struct raw_iface *v = NULL; - bool after = FALSE; /* has vfp passed ifp on the list? */ - bool bad = FALSE; - struct raw_iface *vfp; - - for (vfp = rifaces; vfp != NULL; vfp = vfp->next) - { - if (vfp == ifp) - { - after = TRUE; - } - else if (sameaddr(&ifp->addr, &vfp->addr)) - { - /* ugh: a second interface with the same IP address - * "after" allows us to avoid double reporting. - */ - if (after) - { - bad = TRUE; - break; - } - continue; - } - } - - if (bad) - continue; - - v = ifp; - - /* We've got all we need; see if this is a new thing: - * search old interfaces list. - */ - { - struct iface **p = &interfaces; - - for (;;) - { - struct iface *q = *p; - - /* search is over if at end of list */ - if (q == NULL) - { - /* matches nothing -- create a new entry */ - int fd = create_socket(ifp, v->name, pluto_port); - - if (fd < 0) - break; - - if (nat_traversal_support_non_ike - && addrtypeof(&ifp->addr) == AF_INET) - { - nat_traversal_espinudp_socket(fd, ESPINUDP_WITH_NON_IKE); - } - - q = malloc_thing(struct iface); - zero(q); - q->rname = clone_str(ifp->name); - q->vname = clone_str(v->name); - q->addr = ifp->addr; - q->fd = fd; - q->next = interfaces; - q->change = IFN_ADD; - interfaces = q; - plog("adding interface %s/%s %s:%d" - , q->vname, q->rname, ip_str(&q->addr), pluto_port); - - if (nat_traversal_support_port_floating - && addrtypeof(&ifp->addr) == AF_INET) - { - fd = create_socket(ifp, v->name, NAT_T_IKE_FLOAT_PORT); - if (fd < 0) - break; - nat_traversal_espinudp_socket(fd, - ESPINUDP_WITH_NON_ESP); - q = malloc_thing(struct iface); - zero(q); - q->rname = clone_str(ifp->name); - q->vname = clone_str(v->name); - q->addr = ifp->addr; - setportof(htons(NAT_T_IKE_FLOAT_PORT), &q->addr); - q->fd = fd; - q->next = interfaces; - q->change = IFN_ADD; - q->ike_float = TRUE; - interfaces = q; - plog("adding interface %s/%s %s:%d", - q->vname, q->rname, ip_str(&q->addr), NAT_T_IKE_FLOAT_PORT); - } - break; - } - - /* search over if matching old entry found */ - if (streq(q->rname, ifp->name) - && streq(q->vname, v->name) - && sameaddr(&q->addr, &ifp->addr)) - { - /* matches -- rejuvinate old entry */ - q->change = IFN_KEEP; - - /* look for other interfaces to keep (due to NAT-T) */ - for (q = q->next ; q ; q = q->next) - { - if (streq(q->rname, ifp->name) - && streq(q->vname, v->name) - && sameaddr(&q->addr, &ifp->addr)) - { - q->change = IFN_KEEP; - } - } - break; - } - - /* try again */ - p = &q->next; - } /* for (;;) */ - } - } - - /* delete the raw interfaces list */ - while (rifaces != NULL) - { - struct raw_iface *t = rifaces; - - rifaces = t->next; - free(t); - } -} - -void -find_ifaces(void) -{ - mark_ifaces_dead(); - process_raw_ifaces(find_raw_ifaces4()); - process_raw_ifaces(find_raw_ifaces6()); - - free_dead_ifaces(); /* ditch remaining old entries */ - - if (interfaces == NULL) - loglog(RC_LOG_SERIOUS, "no public interfaces found"); -} - -void -show_ifaces_status(void) -{ - struct iface *p; - - for (p = interfaces; p != NULL; p = p->next) - whack_log(RC_COMMENT, "interface %s/%s %s:%d" - , p->vname, p->rname, ip_str(&p->addr), ntohs(portof(&p->addr))); -} - -void -show_debug_status(void) -{ -#ifdef DEBUG - whack_log(RC_COMMENT, "debug options: %s" - , bitnamesof(debug_bit_names, cur_debugging)); -#endif -} - -static volatile sig_atomic_t sighupflag = FALSE; - -static void -huphandler(int sig UNUSED) -{ - sighupflag = TRUE; -} - -static volatile sig_atomic_t sigtermflag = FALSE; - -static void -termhandler(int sig UNUSED) -{ - sigtermflag = TRUE; -} - -/* call_server listens for incoming ISAKMP packets and Whack messages, - * and handles timer events. - */ -void -call_server(void) -{ - struct iface *ifp; - - /* catch SIGHUP and SIGTERM */ - { - int r; - struct sigaction act; - - act.sa_handler = &huphandler; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; /* no SA_ONESHOT, no SA_RESTART, no nothing */ - r = sigaction(SIGHUP, &act, NULL); - passert(r == 0); - - act.sa_handler = &termhandler; - r = sigaction(SIGTERM, &act, NULL); - r = sigaction(SIGINT, &act, NULL); - passert(r == 0); - } - - for (;;) - { - fd_set readfds; - fd_set writefds; - int ndes, events_fd; - - /* wait for next interesting thing */ - - for (;;) - { - long next_time = next_event(); /* time to any pending timer event */ - int maxfd = ctl_fd; - - if (sigtermflag) - exit_pluto(0); - - if (sighupflag) - { - /* Ignorant folks think poking any daemon with SIGHUP - * is polite. We catch it and tell them otherwise. - * There is one use: unsticking a hung recvfrom. - * This sticking happens sometimes -- kernel bug? - */ - sighupflag = FALSE; - plog("Pluto ignores SIGHUP -- perhaps you want \"whack --listen\""); - } - - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_SET(ctl_fd, &readfds); - -#ifdef ADNS - /* the only write file-descriptor of interest */ - if (adns_qfd != NULL_FD && unsent_ADNS_queries) - { - if (maxfd < adns_qfd) - maxfd = adns_qfd; - FD_SET(adns_qfd, &writefds); - } - - if (adns_afd != NULL_FD) - { - if (maxfd < adns_afd) - maxfd = adns_afd; - FD_SET(adns_afd, &readfds); - } -#endif /* ADNS */ - - events_fd = pluto->events->get_event_fd(pluto->events); - if (maxfd < events_fd) - maxfd = events_fd; - FD_SET(events_fd, &readfds); - - if (listening) - { - for (ifp = interfaces; ifp != NULL; ifp = ifp->next) - { - if (maxfd < ifp->fd) - maxfd = ifp->fd; - passert(!FD_ISSET(ifp->fd, &readfds)); - FD_SET(ifp->fd, &readfds); - } - } - - if (next_time == -1) - { - /* select without timer */ - - ndes = select(maxfd + 1, &readfds, &writefds, NULL, NULL); - } - else if (next_time == 0) - { - /* timer without select: there is a timer event pending, - * and it should fire now so don't bother to do the select. - */ - ndes = 0; /* signify timer expiration */ - } - else - { - /* select with timer */ - - struct timeval tm; - - tm.tv_sec = next_time; - tm.tv_usec = 0; - ndes = select(maxfd + 1, &readfds, &writefds, NULL, &tm); - } - - if (ndes != -1) - break; /* success */ - - if (errno != EINTR) - exit_log_errno((e, "select() failed in call_server()")); - - /* retry if terminated by signal */ - } - - /* figure out what is interesting */ - - if (ndes == 0) - { - /* timer event */ - - DBG(DBG_CONTROL, - DBG_log(BLANK_FORMAT); - DBG_log("*time to handle event")); - - handle_timer_event(); - passert(GLOBALS_ARE_RESET()); - } - else - { - /* at least one file descriptor is ready */ - -#ifdef ADNS - if (adns_qfd != NULL_FD && FD_ISSET(adns_qfd, &writefds)) - { - passert(ndes > 0); - send_unsent_ADNS_queries(); - passert(GLOBALS_ARE_RESET()); - ndes--; - } - - if (adns_afd != NULL_FD && FD_ISSET(adns_afd, &readfds)) - { - passert(ndes > 0); - DBG(DBG_CONTROL, - DBG_log(BLANK_FORMAT); - DBG_log("*received adns message")); - handle_adns_answer(); - passert(GLOBALS_ARE_RESET()); - ndes--; - } -#endif /* ADNS*/ - - if (FD_ISSET(events_fd, &readfds)) - { - passert(ndes > 0); - DBG(DBG_CONTROL, - DBG_log(BLANK_FORMAT); - DBG_log("*handling asynchronous events")); - pluto->events->handle(pluto->events); - passert(GLOBALS_ARE_RESET()); - ndes--; - } - - for (ifp = interfaces; ifp != NULL; ifp = ifp->next) - { - if (FD_ISSET(ifp->fd, &readfds)) - { - /* comm_handle will print DBG_CONTROL intro, - * with more info than we have here. - */ - - passert(ndes > 0); - comm_handle(ifp); - passert(GLOBALS_ARE_RESET()); - ndes--; - } - } - - if (FD_ISSET(ctl_fd, &readfds)) - { - passert(ndes > 0); - DBG(DBG_CONTROL, - DBG_log(BLANK_FORMAT); - DBG_log("*received whack message")); - whack_handle(ctl_fd); - passert(GLOBALS_ARE_RESET()); - ndes--; - } - - passert(ndes == 0); - } - } -} - -/* - * Local Variables: - * c-basic-offset: 4 - * End Variables: - */ diff --git a/src/pluto/server.h b/src/pluto/server.h deleted file mode 100644 index b8123f6dc..000000000 --- a/src/pluto/server.h +++ /dev/null @@ -1,56 +0,0 @@ -/* get-next-event loop - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -extern int ctl_fd; /* file descriptor of control (whack) socket */ -extern struct sockaddr_un ctl_addr; /* address of control (whack) socket */ - -extern int info_fd; /* file descriptor of control (info) socket */ -extern struct sockaddr_un info_addr; /* address of control (info) socket */ - -extern err_t init_ctl_socket(void); -extern void delete_ctl_socket(void); - -extern bool listening; /* should we pay attention to IKE messages? */ - - -/* interface: a terminal point for IKE traffic, IPsec transport mode - * and IPsec tunnels. - * Essentially: - * - an IP device (eg. eth1), and - * - its partner, an ipsec device (eg. ipsec0), and - * - their shared IP address (eg. 10.7.3.2) - * Note: the port for IKE is always implicitly UDP/pluto_port. - */ -struct iface { - char *vname; /* virtual (ipsec) device name */ - char *rname; /* real device name */ - ip_address addr; /* interface IP address */ - int fd; /* file descriptor of socket for IKE UDP messages */ - struct iface *next; - bool ike_float; - enum { IFN_ADD, IFN_KEEP, IFN_DELETE } change; -}; - -extern struct iface *interfaces; /* public interfaces */ - -extern bool use_interface(const char *rifn); -extern void find_ifaces(void); -extern void show_ifaces_status(void); -extern void free_ifaces(void); -extern void show_debug_status(void); -extern void call_server(void); - -/* in rcv_info.c */ -extern err_t init_info_socket(void); -extern void delete_info_socket(void); diff --git a/src/pluto/smartcard.c b/src/pluto/smartcard.c deleted file mode 100644 index 85e246ac4..000000000 --- a/src/pluto/smartcard.c +++ /dev/null @@ -1,1940 +0,0 @@ -/* Support of smartcards and cryptotokens - * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen - * Copyright (C) 2004 David Buechi, Michael Meier - * Zuercher Hochschule Winterthur, Switzerland - * - * Copyright (C) 2005 Michael Joosten - * - * Copyright (C) 2005 Andreas Steffen - * Hochschule fuer Technik Rapperswil, Switzerland - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <time.h> -#include <dlfcn.h> - -#include <freeswan.h> - -#include <asn1/asn1.h> -#include <credentials/keys/public_key.h> -#include <credentials/certificates/x509.h> - -#include "constants.h" - -#ifdef SMARTCARD -#include "rsaref/unix.h" -#include "rsaref/pkcs11.h" -#endif - -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "ca.h" -#include "certs.h" -#include "keys.h" -#include "smartcard.h" -#include "whack.h" -#include "fetch.h" - -#define DEFAULT_BASE 16 - -/* chained list of smartcard records */ -static smartcard_t *smartcards = NULL; - -/* number of generated sc objects */ -static int sc_number = 0; - -const smartcard_t empty_sc = { - NULL , /* next */ - 0 , /* last_load */ - NULL , /* last_cert */ - 0 , /* count */ - 0 , /* number */ - 999999 , /* slot */ - NULL , /* id */ - NULL , /* label */ - { NULL, 0 } , /* pin */ - FALSE , /* pinpad */ - FALSE , /* valid */ - FALSE , /* session_opened */ - FALSE , /* logged_in */ - TRUE , /* any_slot */ - 0L , /* session */ -}; - -#ifdef SMARTCARD /* compile with smartcard support */ - -#define SCX_MAGIC 0xd00bed00 - -struct scx_pkcs11_module { - u_int _magic; - void *handle; -}; - -typedef struct scx_pkcs11_module scx_pkcs11_module_t; - -/* PKCS #11 cryptoki context */ -static bool scx_initialized = FALSE; -static scx_pkcs11_module_t *pkcs11_module = NULL_PTR; -static CK_FUNCTION_LIST_PTR pkcs11_functions = NULL_PTR; - -/* crytoki v2.11 - return values of PKCS #11 functions*/ - -static const char *const pkcs11_return_name[] = { - "CKR_OK", - "CKR_CANCEL", - "CKR_HOST_MEMORY", - "CKR_SLOT_ID_INVALID", - "CKR_FLAGS_INVALID", - "CKR_GENERAL_ERROR", - "CKR_FUNCTION_FAILED", - "CKR_ARGUMENTS_BAD", - "CKR_NO_EVENT", - "CKR_NEED_TO_CREATE_THREADS", - "CKR_CANT_LOCK" - }; - -static const char *const pkcs11_return_name_10[] = { - "CKR_ATTRIBUTE_READ_ONLY", - "CKR_ATTRIBUTE_SENSITIVE", - "CKR_ATTRIBUTE_TYPE_INVALID", - "CKR_ATTRIBUTE_VALUE_INVALID" - }; - -static const char *const pkcs11_return_name_20[] = { - "CKR_DATA_INVALID", - "CKR_DATA_LEN_RANGE" - }; - -static const char *const pkcs11_return_name_30[] = { - "CKR_DEVICE_ERROR", - "CKR_DEVICE_MEMORY", - "CKR_DEVICE_REMOVED" - }; - -static const char *const pkcs11_return_name_40[] = { - "CKR_ENCRYPTED_DATA_INVALID", - "CKR_ENCRYPTED_DATA_LEN_RANGE" - }; - -static const char *const pkcs11_return_name_50[] = { - "CKR_FUNCTION_CANCELED", - "CKR_FUNCTION_NOT_PARALLEL", - "CKR_0x52_UNDEFINED", - "CKR_0x53_UNDEFINED", - "CKR_FUNCTION_NOT_SUPPORTED" - }; - -static const char *const pkcs11_return_name_60[] = { - "CKR_KEY_HANDLE_INVALID", - "CKR_KEY_SENSITIVE", - "CKR_KEY_SIZE_RANGE", - "CKR_KEY_TYPE_INCONSISTENT", - "CKR_KEY_NOT_NEEDED", - "CKR_KEY_CHANGED", - "CKR_KEY_NEEDED", - "CKR_KEY_INDIGESTIBLE", - "CKR_KEY_FUNCTION_NOT_PERMITTED", - "CKR_KEY_NOT_WRAPPABLE", - "CKR_KEY_UNEXTRACTABLE" - }; - -static const char *const pkcs11_return_name_70[] = { - "CKR_MECHANISM_INVALID", - "CKR_MECHANISM_PARAM_INVALID" - }; - -static const char *const pkcs11_return_name_80[] = { - "CKR_OBJECT_HANDLE_INVALID" - }; - -static const char *const pkcs11_return_name_90[] = { - "CKR_OPERATION_ACTIVE", - "CKR_OPERATION_NOT_INITIALIZED" - }; - -static const char *const pkcs11_return_name_A0[] = { - "CKR_PIN_INCORRECT", - "CKR_PIN_INVALID", - "CKR_PIN_LEN_RANGE", - "CKR_PIN_EXPIRED", - "CKR_PIN_LOCKED" - }; - -static const char *const pkcs11_return_name_B0[] = { - "CKR_SESSION_CLOSED", - "CKR_SESSION_COUNT", - "CKR_0xB2_UNDEFINED", - "CKR_SESSION_HANDLE_INVALID", - "CKR_SESSION_PARALLEL_NOT_SUPPORTED", - "CKR_SESSION_READ_ONLY", - "CKR_SESSION_EXISTS", - "CKR_SESSION_READ_ONLY_EXISTS", - "CKR_SESSION_READ_WRITE_SO_EXISTS" - }; - -static const char *const pkcs11_return_name_C0[] = { - "CKR_SIGNATURE_INVALID", - "CKR_SIGNATURE_LEN_RANGE" - }; - -static const char *const pkcs11_return_name_D0[] = { - "CKR_TEMPLATE_INCOMPLETE", - "CKR_TEMPLATE_INCONSISTENT" - }; - -static const char *const pkcs11_return_name_E0[] = { - "CKR_TOKEN_NOT_PRESENT", - "CKR_TOKEN_NOT_RECOGNIZED", - "CKR_TOKEN_WRITE_PROTECTED" - }; - -static const char *const pkcs11_return_name_F0[] = { - "CKR_UNWRAPPING_KEY_HANDLE_INVALID", - "CKR_UNWRAPPING_KEY_SIZE_RANGE", - "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT" - }; - -static const char *const pkcs11_return_name_100[] = { - "CKR_USER_ALREADY_LOGGED_IN", - "CKR_USER_NOT_LOGGED_IN", - "CKR_USER_PIN_NOT_INITIALIZED", - "CKR_USER_TYPE_INVALID", - "CKR_USER_ANOTHER_ALREADY_LOGGED_IN", - "CKR_USER_TOO_MANY_TYPES" - }; - -static const char *const pkcs11_return_name_110[] = { - "CKR_WRAPPED_KEY_INVALID", - "CKR_0x111_UNDEFINED", - "CKR_WRAPPED_KEY_LEN_RANGE", - "CKR_WRAPPING_KEY_HANDLE_INVALID", - "CKR_WRAPPING_KEY_SIZE_RANGE", - "CKR_WRAPPING_KEY_TYPE_INCONSISTENT" - }; - -static const char *const pkcs11_return_name_120[] = { - "CKR_RANDOM_SEED_NOT_SUPPORTED", - "CKR_RANDOM_NO_RNG" - }; - -static const char *const pkcs11_return_name_130[] = { - "CKR_DOMAIN_PARAMS_INVALID" - }; - -static const char *const pkcs11_return_name_150[] = { - "CKR_BUFFER_TOO_SMALL" - }; - -static const char *const pkcs11_return_name_160[] = { - "CKR_SAVED_STATE_INVALID" - }; - -static const char *const pkcs11_return_name_170[] = { - "CKR_INFORMATION_SENSITIVE" - }; - -static const char *const pkcs11_return_name_180[] = { - "CKR_STATE_UNSAVEABLE" - }; - -static const char *const pkcs11_return_name_190[] = { - "CKR_CRYPTOKI_NOT_INITIALIZED", - "CKR_CRYPTOKI_ALREADY_INITIALIZED" - }; - -static const char *const pkcs11_return_name_1A0[] = { - "CKR_MUTEX_BAD", - "CKR_MUTEX_NOT_LOCKED" - }; - -static const char *const pkcs11_return_name_200[] = { - "CKR_FUNCTION_REJECTED" - }; - -static const char *const pkcs11_return_name_vendor[] = { - "CKR_VENDOR_DEFINED" - }; - -static enum_names pkcs11_return_names_vendor = - { CKR_VENDOR_DEFINED, CKR_VENDOR_DEFINED - , pkcs11_return_name_vendor, NULL }; - -static enum_names pkcs11_return_names_200 = - { CKR_FUNCTION_REJECTED, CKR_FUNCTION_REJECTED - , pkcs11_return_name_200, &pkcs11_return_names_vendor }; - -static enum_names pkcs11_return_names_1A0 = - { CKR_MUTEX_BAD, CKR_MUTEX_NOT_LOCKED - , pkcs11_return_name_1A0, &pkcs11_return_names_200 }; - -static enum_names pkcs11_return_names_190 = - { CKR_CRYPTOKI_NOT_INITIALIZED, CKR_CRYPTOKI_ALREADY_INITIALIZED - , pkcs11_return_name_190, &pkcs11_return_names_1A0 }; - -static enum_names pkcs11_return_names_180 = - { CKR_STATE_UNSAVEABLE, CKR_STATE_UNSAVEABLE - , pkcs11_return_name_180, &pkcs11_return_names_190 }; - -static enum_names pkcs11_return_names_170 = - { CKR_INFORMATION_SENSITIVE, CKR_INFORMATION_SENSITIVE - , pkcs11_return_name_170, &pkcs11_return_names_180 }; - -static enum_names pkcs11_return_names_160 = - { CKR_SAVED_STATE_INVALID, CKR_SAVED_STATE_INVALID - , pkcs11_return_name_160, &pkcs11_return_names_170 }; - -static enum_names pkcs11_return_names_150 = - { CKR_BUFFER_TOO_SMALL, CKR_BUFFER_TOO_SMALL - , pkcs11_return_name_150, &pkcs11_return_names_160 }; - -static enum_names pkcs11_return_names_130 = - { CKR_DOMAIN_PARAMS_INVALID, CKR_DOMAIN_PARAMS_INVALID - , pkcs11_return_name_130, &pkcs11_return_names_150 }; - -static enum_names pkcs11_return_names_120 = - { CKR_RANDOM_SEED_NOT_SUPPORTED, CKR_RANDOM_NO_RNG - , pkcs11_return_name_120, &pkcs11_return_names_130 }; - -static enum_names pkcs11_return_names_110 = - { CKR_WRAPPED_KEY_INVALID, CKR_WRAPPING_KEY_TYPE_INCONSISTENT - , pkcs11_return_name_110, &pkcs11_return_names_120 }; - -static enum_names pkcs11_return_names_100 = - { CKR_USER_ALREADY_LOGGED_IN, CKR_USER_TOO_MANY_TYPES - , pkcs11_return_name_100, &pkcs11_return_names_110 }; - -static enum_names pkcs11_return_names_F0 = - { CKR_UNWRAPPING_KEY_HANDLE_INVALID, CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT - , pkcs11_return_name_F0, &pkcs11_return_names_100 }; - -static enum_names pkcs11_return_names_E0 = - { CKR_TOKEN_NOT_PRESENT, CKR_TOKEN_WRITE_PROTECTED - , pkcs11_return_name_E0, &pkcs11_return_names_F0 }; - -static enum_names pkcs11_return_names_D0 = - { CKR_TEMPLATE_INCOMPLETE, CKR_TEMPLATE_INCONSISTENT - , pkcs11_return_name_D0,&pkcs11_return_names_E0 }; - -static enum_names pkcs11_return_names_C0 = - { CKR_SIGNATURE_INVALID, CKR_SIGNATURE_LEN_RANGE - , pkcs11_return_name_C0, &pkcs11_return_names_D0 }; - -static enum_names pkcs11_return_names_B0 = - { CKR_SESSION_CLOSED, CKR_SESSION_READ_WRITE_SO_EXISTS - , pkcs11_return_name_B0, &pkcs11_return_names_C0 }; - -static enum_names pkcs11_return_names_A0 = - { CKR_PIN_INCORRECT, CKR_PIN_LOCKED - , pkcs11_return_name_A0, &pkcs11_return_names_B0 }; - -static enum_names pkcs11_return_names_90 = - { CKR_OPERATION_ACTIVE, CKR_OPERATION_NOT_INITIALIZED - , pkcs11_return_name_90, &pkcs11_return_names_A0 }; - -static enum_names pkcs11_return_names_80 = - { CKR_OBJECT_HANDLE_INVALID, CKR_OBJECT_HANDLE_INVALID - , pkcs11_return_name_80, &pkcs11_return_names_90 }; - -static enum_names pkcs11_return_names_70 = - { CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID - , pkcs11_return_name_70, &pkcs11_return_names_80 }; - -static enum_names pkcs11_return_names_60 = - { CKR_KEY_HANDLE_INVALID, CKR_KEY_UNEXTRACTABLE - , pkcs11_return_name_60, &pkcs11_return_names_70 }; - -static enum_names pkcs11_return_names_50 = - { CKR_FUNCTION_CANCELED, CKR_FUNCTION_NOT_SUPPORTED - , pkcs11_return_name_50, &pkcs11_return_names_60 }; - -static enum_names pkcs11_return_names_40 = - { CKR_ENCRYPTED_DATA_INVALID, CKR_ENCRYPTED_DATA_LEN_RANGE - , pkcs11_return_name_40, &pkcs11_return_names_50 }; - -static enum_names pkcs11_return_names_30 = - { CKR_DEVICE_ERROR, CKR_DEVICE_REMOVED - , pkcs11_return_name_30, &pkcs11_return_names_40 }; - -static enum_names pkcs11_return_names_20 = - { CKR_DATA_INVALID, CKR_DATA_LEN_RANGE - , pkcs11_return_name_20, &pkcs11_return_names_30 }; - -static enum_names pkcs11_return_names_10 = - { CKR_ATTRIBUTE_READ_ONLY, CKR_ATTRIBUTE_VALUE_INVALID - , pkcs11_return_name_10, &pkcs11_return_names_20}; - -static enum_names pkcs11_return_names = - { CKR_OK, CKR_CANT_LOCK - , pkcs11_return_name, &pkcs11_return_names_10}; - -/* - * Unload a PKCS#11 module. - * The calling application is responsible for cleaning up - * and calling C_Finalize() - */ -static CK_RV scx_unload_pkcs11_module(scx_pkcs11_module_t *mod) -{ - if (!mod || mod->_magic != SCX_MAGIC) - return CKR_ARGUMENTS_BAD; - - if (dlclose(mod->handle) < 0) - return CKR_FUNCTION_FAILED; - - memset(mod, 0, sizeof(*mod)); - free(mod); - return CKR_OK; -} - -static scx_pkcs11_module_t* scx_load_pkcs11_module(const char *name, - CK_FUNCTION_LIST_PTR_PTR funcs) -{ - CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR); - scx_pkcs11_module_t *mod; - void *handle; - int rv; - - if (name == NULL || *name == '\0') - return NULL; - - /* Try to load PKCS#11 library module*/ - handle = dlopen(name, RTLD_NOW); - if (handle == NULL) - return NULL; - - mod = malloc_thing(scx_pkcs11_module_t); - mod->_magic = SCX_MAGIC; - mod->handle = handle; - - /* Get the list of function pointers */ - c_get_function_list = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) - dlsym(mod->handle, "C_GetFunctionList"); - if (!c_get_function_list) - goto failed; - - rv = c_get_function_list(funcs); - if (rv == CKR_OK) - return mod; - -failed: scx_unload_pkcs11_module(mod); - return NULL; -} - -/* - * retrieve a certificate object - */ -static cert_t* scx_find_cert_object(CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE object, smartcard_t *sc) -{ - size_t hex_len, label_len; - u_char *hex_id = NULL; - cert_t *cert; - chunk_t blob; - - CK_ATTRIBUTE attr[] = { - { CKA_ID, NULL_PTR, 0L }, - { CKA_LABEL, NULL_PTR, 0L }, - { CKA_VALUE, NULL_PTR, 0L } - }; - - /* get the length of the attributes first */ - CK_RV rv = pkcs11_functions->C_GetAttributeValue(session, object, attr, 3); - if (rv != CKR_OK) - { - plog("couldn't read the attribute sizes: %s" - , enum_show(&pkcs11_return_names, rv)); - return NULL; - } - - free(sc->label); - - hex_id = malloc(attr[0].ulValueLen); - hex_len = attr[0].ulValueLen; - sc->label = malloc(attr[1].ulValueLen + 1); - label_len = attr[1].ulValueLen; - blob.ptr = malloc(attr[2].ulValueLen); - blob.len = attr[2].ulValueLen; - - attr[0].pValue = hex_id; - attr[1].pValue = sc->label; - attr[2].pValue = blob.ptr; - - /* now get the attributes */ - rv = pkcs11_functions->C_GetAttributeValue(session, object, attr, 3); - if (rv != CKR_OK) - { - plog("couldn't read the attributes: %s" - , enum_show(&pkcs11_return_names, rv)); - free(hex_id); - free(sc->label); - free(blob.ptr); - return NULL; - } - - free(sc->id); - - /* convert id from hex to ASCII */ - sc->id = malloc(2*hex_len + 1); - datatot(hex_id, hex_len, 16, sc->id, 2*hex_len + 1); - free(hex_id); - - /* safeguard in case the label is not null terminated */ - sc->label[label_len] = '\0'; - - /* parse the retrieved cert */ - - /* initialize the return argument */ - cert = malloc_thing(cert_t); - *cert = cert_empty; - cert->smartcard = TRUE; - cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, blob, - BUILD_END); - if (cert->cert) - { - return cert; - } - - plog("failed to load cert from smartcard, error in X.509 certificate"); - cert_free(cert); - return NULL; -} - - -/* - * search a given slot for PKCS#11 certificate objects - */ -static void scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) -{ - CK_RV rv; - CK_OBJECT_CLASS class = CKO_CERTIFICATE; - CK_ATTRIBUTE attr[] = {{ CKA_CLASS, &class, sizeof(class) }}; - - rv = pkcs11_functions->C_FindObjectsInit(session, attr, 1); - if (rv != CKR_OK) - { - plog("error in C_FindObjectsInit: %s" - , enum_show(&pkcs11_return_names, rv)); - return; - } - - for (;;) - { - CK_OBJECT_HANDLE object; - CK_ULONG obj_count = 0; - time_t valid_until; - smartcard_t *sc; - cert_t *cert; - certificate_t *certificate; - x509_t *x509; - - rv = pkcs11_functions->C_FindObjects(session, &object, 1, &obj_count); - if (rv != CKR_OK) - { - plog("error in C_FindObjects: %s" - , enum_show(&pkcs11_return_names, rv)); - break; - } - - /* no objects left */ - if (obj_count == 0) - break; - - /* create and initialize a new smartcard object */ - sc = malloc_thing(smartcard_t); - *sc = empty_sc; - sc->any_slot = FALSE; - sc->slot = slot; - cert = scx_find_cert_object(session, object, sc); - if (!cert) - { - scx_free(sc); - continue; - } - DBG(DBG_CONTROL, - DBG_log("found cert in %s with id: %s, label: '%s'" - , scx_print_slot(sc, ""), sc->id, sc->label) - ) - - /* check validity of certificate */ - certificate = cert->cert; - if (!certificate->get_validity(certificate, NULL, NULL, &valid_until)) - { - cert_free(cert); - scx_free(sc); - continue; - } - DBG(DBG_CONTROL, - DBG_log(" certificate is valid") - ) - - sc = scx_add(sc); - - /* put end entity and ca certificates into different chains */ - x509 = (x509_t*)certificate; - if (x509->get_flags(x509) & X509_CA) - { - sc->last_cert = add_authcert(cert, X509_CA); - } - else - { - add_public_key_from_cert(cert, valid_until, DAL_LOCAL); - sc->last_cert = cert_add(cert); - } - - cert_share(sc->last_cert); - time(&sc->last_load); - } - - rv = pkcs11_functions->C_FindObjectsFinal(session); - if (rv != CKR_OK) - { - plog("error in C_FindObjectsFinal: %s" - , enum_show(&pkcs11_return_names, rv)); - } -} - -/* - * search all slots for PKCS#11 certificate objects - */ -static void scx_find_all_cert_objects(void) -{ - CK_RV rv; - CK_SLOT_ID_PTR slots = NULL_PTR; - CK_ULONG slot_count = 0; - CK_ULONG i; - - if (!scx_initialized) - { - plog("pkcs11 module not initialized"); - return; - } - - /* read size, always returns CKR_OK ! */ - rv = pkcs11_functions->C_GetSlotList(FALSE, NULL_PTR, &slot_count); - - /* allocate memory for the slots */ - slots = (CK_SLOT_ID *)malloc(slot_count * sizeof(CK_SLOT_ID)); - - rv = pkcs11_functions->C_GetSlotList(FALSE, slots, &slot_count); - if (rv != CKR_OK) - { - plog("error in C_GetSlotList: %s", enum_show(&pkcs11_return_names, rv)); - free(slots); - return; - } - - /* look in every slot for certificate objects */ - for (i = 0; i < slot_count; i++) - { - CK_SLOT_ID slot = slots[i]; - CK_SLOT_INFO info; - CK_SESSION_HANDLE session; - - rv = pkcs11_functions->C_GetSlotInfo(slot, &info); - - if (rv != CKR_OK) - { - plog("error in C_GetSlotInfo: %s" - , enum_show(&pkcs11_return_names, rv)); - continue; - } - - if (!(info.flags & CKF_TOKEN_PRESENT)) - { - plog("no token present in slot %lu", slot); - continue; - } - - rv = pkcs11_functions->C_OpenSession(slot - , CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session); - if (rv != CKR_OK) - { - plog("failed to open a session on slot %lu: %s" - , slot, enum_show(&pkcs11_return_names, rv)); - continue; - } - DBG(DBG_CONTROLMORE, - DBG_log("pkcs11 session #%ld for searching slot %lu", session, slot) - ) - scx_find_cert_objects(slot, session); - - rv = pkcs11_functions->C_CloseSession(session); - if (rv != CKR_OK) - { - plog("error in C_CloseSession: %s" - , enum_show(&pkcs11_return_names, rv)); - } - } - free(slots); -} -#endif - -/* - * load and initialize PKCS#11 cryptoki module - * - * init_args should be unused when we have a PKCS#11 compliant module, - * but NSS softoken breaks that API. - */ -void scx_init(const char* module, const char *init_args) -{ -#ifdef SMARTCARD - CK_C_INITIALIZE_ARGS args = { .pReserved = (char *)init_args, }; - CK_RV rv; - - if (scx_initialized) - { - plog("weird - pkcs11 module seems already to be initialized"); - return; - } - - if (module == NULL) -#ifdef PKCS11_DEFAULT_LIB - module = PKCS11_DEFAULT_LIB; -#else - { - plog("no pkcs11 module defined"); - return; - } -#endif - - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("pkcs11 module '%s' loading...", module) - ) - pkcs11_module = scx_load_pkcs11_module(module, &pkcs11_functions); - if (pkcs11_module == NULL) - { - plog("failed to load pkcs11 module '%s'", module); - return; - } - - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("pkcs11 module initializing...") - ) - rv = pkcs11_functions->C_Initialize(init_args ? &args : NULL); - if (rv != CKR_OK) - { - plog("failed to initialize pkcs11 module: %s" - , enum_show(&pkcs11_return_names, rv)); - return; - } - - scx_initialized = TRUE; - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("pkcs11 module loaded and initialized") - ) - - scx_find_all_cert_objects(); -#endif -} - -/* - * finalize and unload PKCS#11 cryptoki module - */ -void scx_finalize(void) -{ -#ifdef SMARTCARD - while (smartcards != NULL) - { - scx_release(smartcards); - } - - if (pkcs11_functions != NULL_PTR) - { - pkcs11_functions->C_Finalize(NULL_PTR); - pkcs11_functions = NULL_PTR; - } - - if (pkcs11_module != NULL) - { - scx_unload_pkcs11_module(pkcs11_module); - pkcs11_module = NULL; - } - - scx_initialized = FALSE; - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("pkcs11 module finalized and unloaded") - ) -#endif -} - -/* - * does a filename contain the token %smartcard? - */ -bool scx_on_smartcard(const char *filename) -{ - return strneq(filename, SCX_TOKEN, strlen(SCX_TOKEN)); -} - -#ifdef SMARTCARD -/* - * find a specific object on the smartcard - */ -static bool scx_pkcs11_find_object(CK_SESSION_HANDLE session, - CK_OBJECT_HANDLE_PTR object, - CK_OBJECT_CLASS class, const char* id) -{ - size_t len; - char buf[BUF_LEN]; - CK_RV rv; - CK_ULONG obj_count = 0; - CK_ULONG attr_count = 1; - - CK_ATTRIBUTE attr[] = { - { CKA_CLASS, &class, sizeof(class) }, - { CKA_ID, &buf, 0L } - }; - - if (id != NULL) - { - ttodata(id, strlen(id), 16, buf, BUF_LEN, &len); - attr[1].ulValueLen = len; - attr_count = 2; - } - - /* get info for certificate with id */ - rv = pkcs11_functions->C_FindObjectsInit(session, attr, attr_count); - if (rv != CKR_OK) - { - plog("error in C_FindObjectsInit: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - - rv = pkcs11_functions->C_FindObjects(session, object, 1, &obj_count); - if (rv != CKR_OK) - { - plog("error in C_FindObjects: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - - rv = pkcs11_functions->C_FindObjectsFinal(session); - if (rv != CKR_OK) - { - plog("error in C_FindObjectsFinal: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - - return (obj_count != 0); -} - -/* - * check if a given certificate object id is found in a slot - */ -static bool scx_find_cert_id_in_slot(smartcard_t *sc, CK_SLOT_ID slot) -{ - CK_SESSION_HANDLE session; - CK_OBJECT_HANDLE object; - CK_SLOT_INFO info; - - CK_RV rv = pkcs11_functions->C_GetSlotInfo(slot, &info); - - if (rv != CKR_OK) - { - plog("error in C_GetSlotInfo: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - - if (!(info.flags & CKF_TOKEN_PRESENT)) - { - plog("no token present in slot %lu", slot); - return FALSE; - } - - rv = pkcs11_functions->C_OpenSession(slot - , CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session); - if (rv != CKR_OK) - { - plog("failed to open a session on slot %lu: %s" - , slot, enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - DBG(DBG_CONTROLMORE, - DBG_log("pkcs11 session #%ld for searching slot %lu", session, slot) - ) - - /* check if there is a certificate on the card in the specified slot */ - if (scx_pkcs11_find_object(session, &object, CKO_CERTIFICATE, sc->id)) - { - sc->slot = slot; - sc->any_slot = FALSE; - sc->session = session; - sc->session_opened = TRUE; - return TRUE; - } - - rv = pkcs11_functions->C_CloseSession(session); - if (rv != CKR_OK) - { - plog("error in C_CloseSession: %s" - , enum_show(&pkcs11_return_names, rv)); - } - return FALSE; -} -#endif - -/* - * Connect to the smart card in the reader and select the correct slot - */ -bool scx_establish_context(smartcard_t *sc) -{ -#ifdef SMARTCARD - bool id_found = FALSE; - - if (!scx_initialized) - { - plog("pkcs11 module not initialized"); - return FALSE; - } - - if (sc->session_opened) - { - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("pkcs11 session #%ld already open", sc->session) - ) - return TRUE; - } - - if (!sc->any_slot) - id_found = scx_find_cert_id_in_slot(sc, sc->slot); - - if (!id_found) - { - CK_RV rv; - CK_SLOT_ID slot; - CK_SLOT_ID_PTR slots = NULL_PTR; - CK_ULONG slot_count = 0; - CK_ULONG i; - - /* read size, always returns CKR_OK ! */ - rv = pkcs11_functions->C_GetSlotList(FALSE, NULL_PTR, &slot_count); - - /* allocate memory for the slots */ - slots = (CK_SLOT_ID *)malloc(slot_count * sizeof(CK_SLOT_ID)); - - rv = pkcs11_functions->C_GetSlotList(FALSE, slots, &slot_count); - if (rv != CKR_OK) - { - plog("error in C_GetSlotList: %s" - , enum_show(&pkcs11_return_names, rv)); - free(slots); - return FALSE; - } - - /* look in every slot for a certificate with a given object ID */ - for (i = 0; i < slot_count; i++) - { - slot = slots[i]; - id_found = scx_find_cert_id_in_slot(sc, slot); - if (id_found) - break; - } - free(slots); - } - - if (id_found) - { - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("found token with id %s in slot %lu", sc->id, sc->slot); - DBG_log("pkcs11 session #%ld opened", sc->session) - ) - } - else - { - plog(" no certificate with id %s found on smartcard", sc->id); - } - return id_found; -#else - plog("warning: SMARTCARD support is deactivated in pluto/Makefile!"); - return FALSE; -#endif -} - -/* - * log in to a session - */ -bool scx_login(smartcard_t *sc) -{ -#ifdef SMARTCARD - CK_RV rv; - - if (sc->logged_in) - { - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("pkcs11 session #%ld login already done", sc->session) - ) - return TRUE; - } - - if (sc->pin.ptr == NULL) - { - plog("unable to log in without PIN!"); - return FALSE; - } - - if (!sc->session_opened) - { - plog("session not opened"); - return FALSE; - } - - rv = pkcs11_functions->C_Login(sc->session, CKU_USER - , (CK_UTF8CHAR *) sc->pin.ptr, sc->pin.len); - if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) - { - plog("unable to login: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("pkcs11 session #%ld login successful", sc->session) - ) - sc->logged_in = TRUE; - return TRUE; -#else - return FALSE; -#endif -} - -#ifdef SMARTCARD -/* - * logout from a session - */ -static void scx_logout(smartcard_t *sc) -{ - CK_RV rv; - - rv = pkcs11_functions->C_Logout(sc->session); - if (rv != CKR_OK) - plog("error in C_Logout: %s" - , enum_show(&pkcs11_return_names, rv)); - else - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("pkcs11 session #%ld logout", sc->session) - ) - sc->logged_in = FALSE; -} -#endif - - -/* - * Release context and disconnect from card - */ -void scx_release_context(smartcard_t *sc) -{ -#ifdef SMARTCARD - CK_RV rv; - - if (!scx_initialized) - return; - - if (sc->session_opened) - { - if (sc->logged_in) - scx_logout(sc); - - sc->session_opened = FALSE; - - rv = pkcs11_functions->C_CloseSession(sc->session); - if (rv != CKR_OK) - plog("error in C_CloseSession: %s" - , enum_show(&pkcs11_return_names, rv)); - else - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("pkcs11 session #%ld closed", sc->session) - ) - } -#endif -} - -/* - * Load host certificate from smartcard - */ -cert_t* scx_load_cert(const char *filename, smartcard_t **scp, bool *cached) -{ -#ifdef SMARTCARD /* compile with smartcard support */ - const char *number_slot_id = filename + strlen(SCX_TOKEN); - CK_OBJECT_HANDLE object; - smartcard_t *sc; - cert_t *cert = NULL; - - /* return the smartcard object */ - *scp = sc = scx_add(scx_parse_number_slot_id(number_slot_id)); - - /* is there a cached smartcard certificate? */ - *cached = sc->last_cert && - (time(NULL) - sc->last_load) < SCX_CERT_CACHE_INTERVAL; - - if (*cached) - { - plog(" using cached cert from smartcard #%d (%s, id: %s, label: '%s')" - , sc->number - , scx_print_slot(sc, "") - , sc->id - , sc->label); - return sc->last_cert; - } - - if (!scx_establish_context(sc)) - { - scx_release_context(sc); - return NULL; - } - - /* find the certificate object */ - if (!scx_pkcs11_find_object(sc->session, &object, CKO_CERTIFICATE, sc->id)) - { - scx_release_context(sc); - return NULL; - } - - /* retrieve the certificate object */ - cert = scx_find_cert_object(sc->session, object, sc); - if (cert == NULL) - { - scx_release_context(sc); - return NULL; - } - - if (!pkcs11_keep_state) - { - scx_release_context(sc); - } - plog(" loaded cert from smartcard #%d (%s, id: %s, label: '%s')" - , sc->number - , scx_print_slot(sc, "") - , sc->id - , sc->label); - - return cert; -#else - plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!"); - return NULL; -#endif -} - -/* - * parse slot number and key id - * the following syntax is allowed - * number slot id - * %smartcard 1 - - - * %smartcard#2 2 - - - * %smartcard0 - 0 - - * %smartcard:45 - - 45 - * %smartcard0:45 - 0 45 - */ -smartcard_t* scx_parse_number_slot_id(const char *number_slot_id) -{ - int len = strlen(number_slot_id); - smartcard_t *sc = malloc_thing(smartcard_t); - - /* assign default values */ - *sc = empty_sc; - - if (len == 0) /* default: use certificate #1 */ - { - sc->number = 1; - } - else if (*number_slot_id == '#') /* #number scheme */ - { - err_t ugh; - unsigned long ul; - - ugh = atoul(number_slot_id+1, len-1 , 10, &ul); - if (ugh == NULL) - sc->number = (int)ul; - else - plog("error parsing smartcard number: %s", ugh); - } - else /* slot:id scheme */ - { - int slot_len = len; - char *p = strchr(number_slot_id, ':'); - - if (p != NULL) - { - int id_len = len - (p + 1 - number_slot_id); - slot_len -= (1 + id_len); - - if (id_len > 0) /* we have an id */ - sc->id = p + 1; - } - if (slot_len > 0) /* we have a slot */ - { - err_t ugh = NULL; - unsigned long ul; - - ugh = atoul(number_slot_id, slot_len, 10, &ul); - if (ugh == NULL) - { - sc->slot = ul; - sc->any_slot = FALSE; - } - else - plog("error parsing smartcard slot number: %s", ugh); - } - } - /* unshare the id string */ - sc->id = clone_str(sc->id); - return sc; -} - -/* - * Verify pin on card - */ -bool scx_verify_pin(smartcard_t *sc) -{ -#ifdef SMARTCARD - CK_RV rv; - - if (!sc->pinpad) - sc->valid = FALSE; - - if (sc->pin.ptr == NULL) - { - plog("unable to verify without PIN"); - return FALSE; - } - - /* establish context */ - if (!scx_establish_context(sc)) - { - scx_release_context(sc); - return FALSE; - } - - rv = pkcs11_functions->C_Login(sc->session, CKU_USER, - (CK_UTF8CHAR *) sc->pin.ptr, sc->pin.len); - if (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) - { - sc->valid = TRUE; - sc->logged_in = TRUE; - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log((rv == CKR_OK) - ? "PIN code correct" - : "already logged in, no PIN entry required"); - DBG_log("pkcs11 session #%ld login successful", sc->session) - ) - } - else - { - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("PIN code incorrect") - ) - } - if (!pkcs11_keep_state) - scx_release_context(sc); -#else - sc->valid = FALSE; -#endif - return sc->valid; -} - -/* - * Sign hash on smartcard - */ -bool scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen, u_char *out, - size_t outlen) -{ -#ifdef SMARTCARD - CK_RV rv; - CK_OBJECT_HANDLE object; - CK_ULONG siglen = (CK_ULONG)outlen; - CK_BBOOL sign_flag, decrypt_flag; - CK_ATTRIBUTE attr[] = { - { CKA_SIGN, &sign_flag, sizeof(sign_flag) }, - { CKA_DECRYPT, &decrypt_flag, sizeof(decrypt_flag) } - }; - - if (!sc->logged_in) - return FALSE; - - if (!scx_pkcs11_find_object(sc->session, &object, CKO_PRIVATE_KEY, sc->id)) - { - plog("unable to find private key with id '%s'", sc->id); - return FALSE; - } - - rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 2); - if (rv != CKR_OK) - { - plog("couldn't read the private key attributes: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("RSA key flags: sign = %s, decrypt = %s" - , (sign_flag)? "true":"false" - , (decrypt_flag)? "true":"false") - ) - - if (sign_flag) - { - CK_MECHANISM mech = { CKM_RSA_PKCS, NULL_PTR, 0 }; - - rv = pkcs11_functions->C_SignInit(sc->session, &mech, object); - if (rv != CKR_OK) - { - plog("error in C_SignInit: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - - rv = pkcs11_functions->C_Sign(sc->session, (CK_BYTE_PTR)in, inlen - , out, &siglen); - if (rv != CKR_OK) - { - plog("error in C_Sign: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - } - else if (decrypt_flag) - { - CK_MECHANISM mech = { CKM_RSA_X_509, NULL_PTR, 0 }; - size_t padlen; - u_char *p = out ; - - /* PKCS#1 v1.5 8.1 encryption-block formatting */ - *p++ = 0x00; - *p++ = 0x01; /* BT (block type) 01 */ - padlen = outlen - 3 - inlen; - memset(p, 0xFF, padlen); - p += padlen; - *p++ = 0x00; - memcpy(p, in, inlen); - - rv = pkcs11_functions->C_DecryptInit(sc->session, &mech, object); - if (rv != CKR_OK) - { - plog("error in C_DecryptInit: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - - rv = pkcs11_functions->C_Decrypt(sc->session, out, outlen - , out, &siglen); - if (rv != CKR_OK) - { - plog("error in C_Decrypt: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - } - else - { - plog("private key has neither sign nor decrypt flag set"); - return FALSE; - } - - if (siglen > (CK_ULONG)outlen) - { - plog("signature length (%lu) larger than allocated buffer (%d)" - , siglen, (int)outlen); - return FALSE; - } - return TRUE; -#else - return FALSE; -#endif -} - -/* - * encrypt data block with an RSA public key - */ -bool scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen, u_char *out, - size_t *outlen) -{ -#ifdef SMARTCARD - CK_RV rv; - CK_OBJECT_HANDLE object; - CK_ULONG len = (CK_ULONG)(*outlen); - CK_BBOOL encrypt_flag; - CK_ATTRIBUTE attr[] = { - { CKA_MODULUS, NULL_PTR, 0L }, - { CKA_PUBLIC_EXPONENT, NULL_PTR, 0L }, - { CKA_ENCRYPT, &encrypt_flag, sizeof(encrypt_flag) } - }; - CK_MECHANISM mech = { CKM_RSA_PKCS, NULL_PTR, 0 }; - - if (!scx_establish_context(sc)) - { - scx_release_context(sc); - return FALSE; - } - - if (!scx_pkcs11_find_object(sc->session, &object, CKO_PUBLIC_KEY, sc->id)) - { - plog("unable to find public key with id '%s'", sc->id); - return FALSE; - } - - rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 3); - if (rv != CKR_OK) - { - plog("couldn't read the public key attributes: %s" - , enum_show(&pkcs11_return_names, rv)); - scx_release_context(sc); - return FALSE; - } - - if (!encrypt_flag) - { - plog("public key cannot be used for encryption"); - scx_release_context(sc); - return FALSE; - } - - /* there must be enough space left for the PKCS#1 v1.5 padding */ - if (inlen > attr[0].ulValueLen - 11) - { - plog("smartcard input data length (%d) exceeds maximum of %lu bytes" - , (int)inlen, attr[0].ulValueLen - 11); - if (!pkcs11_keep_state) - scx_release_context(sc); - return FALSE; - } - - rv = pkcs11_functions->C_EncryptInit(sc->session, &mech, object); - - if (rv != CKR_OK) - { - if (rv == CKR_FUNCTION_NOT_SUPPORTED) - { - public_key_t *key; - chunk_t rsa_modulus, rsa_exponent, rsa_key, cipher_text; - chunk_t plain_text = {(u_char*)in, inlen}; - - DBG(DBG_CONTROL, - DBG_log("doing RSA encryption in software") - ) - attr[0].pValue = malloc(attr[0].ulValueLen); - attr[1].pValue = malloc(attr[1].ulValueLen); - - rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 2); - if (rv != CKR_OK) - { - plog("couldn't read modulus and public exponent: %s" - , enum_show(&pkcs11_return_names, rv)); - free(attr[0].pValue); - free(attr[1].pValue); - scx_release_context(sc); - return FALSE; - } - rsa_modulus = chunk_create((u_char*) attr[0].pValue, - (size_t) attr[0].ulValueLen); - rsa_exponent = chunk_create((u_char*) attr[1].pValue, - (size_t) attr[1].ulValueLen); - rsa_key = asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_integer("m", rsa_modulus), - asn1_integer("m", rsa_exponent)); - key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, - BUILD_BLOB_ASN1_DER, rsa_key, BUILD_END); - free(rsa_key.ptr); - if (key == NULL) - { - return FALSE; - } - key->encrypt(key, ENCRYPT_RSA_PKCS1, plain_text, &cipher_text); - key->destroy(key); - - if (cipher_text.ptr == NULL) - { - plog("smartcard input data length is too large"); - if (!pkcs11_keep_state) - { - scx_release_context(sc); - } - return FALSE; - } - - memcpy(out, cipher_text.ptr, cipher_text.len); - *outlen = cipher_text.len; - free(cipher_text.ptr); - - if (!pkcs11_keep_state) - { - scx_release_context(sc); - } - return TRUE; - } - else - { - plog("error in C_EncryptInit: %s" - , enum_show(&pkcs11_return_names, rv)); - scx_release_context(sc); - return FALSE; - } - } - - DBG(DBG_CONTROL, - DBG_log("doing RSA encryption on smartcard") - ) - rv = pkcs11_functions->C_Encrypt(sc->session, (u_char*)in, inlen - , out, &len); - if (rv != CKR_OK) - { - plog("error in C_Encrypt: %s" - , enum_show(&pkcs11_return_names, rv)); - scx_release_context(sc); - return FALSE; - } - if (!pkcs11_keep_state) - scx_release_context(sc); - - *outlen = (size_t)len; - return TRUE; -#else - return FALSE; -#endif -} -/* - * decrypt a data block with an RSA private key - */ -bool scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen, u_char *out, - size_t *outlen) -{ -#ifdef SMARTCARD - CK_RV rv; - CK_OBJECT_HANDLE object; - CK_ULONG len = (CK_ULONG)(*outlen); - CK_BBOOL decrypt_flag; - CK_ATTRIBUTE attr[] = { - { CKA_DECRYPT, &decrypt_flag, sizeof(decrypt_flag) } - }; - CK_MECHANISM mech = { CKM_RSA_PKCS, NULL_PTR, 0 }; - - if (!scx_establish_context(sc) || !scx_login(sc)) - { - scx_release_context(sc); - return FALSE; - } - - if (!scx_pkcs11_find_object(sc->session, &object, CKO_PRIVATE_KEY, sc->id)) - { - plog("unable to find private key with id '%s'", sc->id); - return FALSE; - } - - rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 1); - if (rv != CKR_OK) - { - plog("couldn't read the private key attributes: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - - if (!decrypt_flag) - { - plog("private key cannot be used for decryption"); - scx_release_context(sc); - return FALSE; - } - - DBG(DBG_CONTROL, - DBG_log("doing RSA decryption on smartcard") - ) - rv = pkcs11_functions->C_DecryptInit(sc->session, &mech, object); - if (rv != CKR_OK) - { - plog("error in C_DecryptInit: %s" - , enum_show(&pkcs11_return_names, rv)); - scx_release_context(sc); - return FALSE; - } - - rv = pkcs11_functions->C_Decrypt(sc->session, (u_char*)in, inlen - , out, &len); - if (rv != CKR_OK) - { - plog("error in C_Decrypt: %s" - , enum_show(&pkcs11_return_names, rv)); - scx_release_context(sc); - return FALSE; - } - if (!pkcs11_keep_state) - scx_release_context(sc); - - *outlen = (size_t)len; - return TRUE; -#else - return FALSE; -#endif -} - -/* receive an encrypted data block via whack, - * decrypt it using a private RSA key and - * return the decrypted data block via whack - */ -bool scx_op_via_whack(const char* msg, int inbase, int outbase, sc_op_t op, - const char* keyid, int whackfd) -{ - char inbuf[RSA_MAX_OCTETS]; - char outbuf[2*RSA_MAX_OCTETS + 1]; - size_t outlen = sizeof(inbuf); - size_t inlen; - smartcard_t *sc,*sc_new; - - const char *number_slot_id = ""; - - err_t ugh = ttodata(msg, 0, inbase, inbuf, sizeof(inbuf), &inlen); - - /* no prefix - use default base */ - if (ugh != NULL && inbase == 0) - ugh = ttodata(msg, 0, DEFAULT_BASE, inbuf, sizeof(inbuf), &inlen); - - if (ugh != NULL) - { - plog("format error in smartcard input data: %s", ugh); - return FALSE; - } - - if (keyid != NULL) - { - number_slot_id = (strneq(keyid, SCX_TOKEN, strlen(SCX_TOKEN))) - ? keyid + strlen(SCX_TOKEN) : keyid; - } - - sc_new = scx_parse_number_slot_id(number_slot_id); - sc = scx_add(sc_new); - if (sc == sc_new) - scx_share(sc); - - DBG((op == SC_OP_ENCRYPT)? DBG_PRIVATE:DBG_RAW, - DBG_dump("smartcard input data:\n", inbuf, inlen) - ) - - if (op == SC_OP_DECRYPT) - { - if (!sc->valid && whackfd != NULL_FD) - scx_get_pin(sc, whackfd); - - if (!sc->valid) - { - loglog(RC_NOVALIDPIN, "cannot decrypt without valid PIN"); - return FALSE; - } - } - - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("using RSA key from smartcard (slot: %d, id: %s)" - , (int)sc->slot, sc->id) - ) - - switch (op) - { - case SC_OP_ENCRYPT: - if (!scx_encrypt(sc, inbuf, inlen, inbuf, &outlen)) - return FALSE; - break; - case SC_OP_DECRYPT: - if (!scx_decrypt(sc, inbuf, inlen, inbuf, &outlen)) - return FALSE; - break; - default: - break; - } - - DBG((op == SC_OP_DECRYPT)? DBG_PRIVATE:DBG_RAW, - DBG_dump("smartcard output data:\n", inbuf, outlen) - ) - - if (outbase == 0) /* use default base */ - outbase = DEFAULT_BASE; - - if (outbase == 256) /* ascii plain text */ - whack_log(RC_COMMENT, "%.*s", (int)outlen, inbuf); - else - { - outlen = datatot(inbuf, outlen, outbase, outbuf, sizeof(outbuf)); - if (outlen == 0) - { - plog("error in output format conversion"); - return FALSE; - } - whack_log(RC_COMMENT, "%s", outbuf); - } - return TRUE; -} - - /* - * get length of RSA key in bytes - */ -size_t scx_get_keylength(smartcard_t *sc) -{ -#ifdef SMARTCARD - CK_RV rv; - CK_OBJECT_HANDLE object; - CK_ATTRIBUTE attr[] = {{ CKA_MODULUS, NULL_PTR, 0}}; - - if (!sc->logged_in) - return FALSE; - - if (!scx_pkcs11_find_object(sc->session, &object, CKO_PRIVATE_KEY, sc->id)) - { - plog("unable to find private key with id '%s'", sc->id); - return FALSE; - } - - /* get the length of the private key */ - rv = pkcs11_functions->C_GetAttributeValue(sc->session, object - , (CK_ATTRIBUTE_PTR)&attr, 1); - if (rv != CKR_OK) - { - plog("failed to get key length: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } - - return attr[0].ulValueLen; /*Return key length in bytes */ -#else - return 0; -#endif -} - -/* - * prompt for pin and verify it - */ -bool scx_get_pin(smartcard_t *sc, int whackfd) -{ -#ifdef SMARTCARD - char pin[BUF_LEN]; - int i, n; - - whack_log(RC_ENTERSECRET, "need PIN for #%d (%s, id: %s, label: '%s')" - , sc->number, scx_print_slot(sc, ""), sc->id, sc->label); - - for (i = 0; i < SCX_MAX_PIN_TRIALS; i++) - { - if (i > 0) - whack_log(RC_ENTERSECRET, "invalid PIN, please try again"); - - n = read(whackfd, pin, BUF_LEN); - - if (n == -1) - { - whack_log(RC_LOG_SERIOUS, "read(whackfd) failed"); - return FALSE; - } - - if (strlen(pin) == 0) - { - whack_log(RC_LOG_SERIOUS, "no PIN entered, aborted"); - return FALSE; - } - - sc->pin.ptr = pin; - sc->pin.len = strlen(pin); - - /* verify the pin */ - if (scx_verify_pin(sc)) - { - sc->pin = chunk_create(pin, strlen(pin)); - sc->pin = chunk_clone(sc->pin); - break; - } - - /* wrong pin - we try another round */ - sc->pin = chunk_empty; - } - - if (sc->valid) - whack_log(RC_SUCCESS, "valid PIN"); - else - whack_log(RC_LOG_SERIOUS, "invalid PIN, too many trials"); -#else - sc->valid = FALSE; - whack_log(RC_LOG_SERIOUS, "SMARTCARD support is deactivated in pluto/Makefile!"); -#endif - return sc->valid; -} - - -/* - * free the pin code - */ -void scx_free_pin(chunk_t *pin) -{ - if (pin->ptr != NULL) - { - /* clear pin field in memory */ - memset(pin->ptr, '\0', pin->len); - free(pin->ptr); - *pin = chunk_empty; - } -} - -/* - * frees a smartcard record - */ -void scx_free(smartcard_t *sc) -{ - if (sc != NULL) - { - scx_release_context(sc); - cert_release(sc->last_cert); - free(sc->id); - free(sc->label); - scx_free_pin(&sc->pin); - free(sc); - } -} - -/* release of a smartcard record decreases the count by one - " the record is freed when the counter reaches zero - */ -void scx_release(smartcard_t *sc) -{ - if (sc != NULL && --sc->count == 0) - { - smartcard_t **pp = &smartcards; - while (*pp != sc) - pp = &(*pp)->next; - *pp = sc->next; - scx_free(sc); - } -} - -/* - * compare two smartcard records by comparing their slots and ids - */ -static bool scx_same(smartcard_t *a, smartcard_t *b) -{ - if (a->number && b->number) - { - /* same number */ - return a->number == b->number; - } - else - { - /* same id and/or same slot */ - return (!a->id || (b->id && streq(a->id, b->id))) - && (a->any_slot || b->any_slot || a->slot == b->slot); - } -} - -/* for each link pointing to the smartcard record - " increase the count by one - */ -void scx_share(smartcard_t *sc) -{ - if (sc != NULL) - sc->count++; -} - -/* - * adds a smartcard record to the chained list - */ -smartcard_t* scx_add(smartcard_t *smartcard) -{ - smartcard_t *sc = smartcards; - smartcard_t **psc = &smartcards; - - while (sc != NULL) - { - if (scx_same(smartcard, sc)) /* already in chain, free smartcard record */ - { - scx_free(smartcard); - return sc; - } - psc = &sc->next; - sc = sc->next; - } - - /* insert new smartcard record at the end of the chain */ - *psc = smartcard; - smartcard->number = ++sc_number; - smartcard->count = 1; - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" smartcard #%d added", sc_number) - ) - return smartcard; -} - -/* - * get the smartcard that belongs to an X.509 certificate - */ -smartcard_t* scx_get(cert_t *cert) -{ - smartcard_t *sc = smartcards; - - while (sc != NULL) - { - if (sc->last_cert == cert) - { - return sc; - } - sc = sc->next; - } - return NULL; -} - -/* - * prints either the slot number or 'any slot' - */ -char *scx_print_slot(smartcard_t *sc, const char *whitespace) -{ - char *buf = temporary_cyclic_buffer(); - - if (sc->any_slot) - snprintf(buf, BUF_LEN, "any slot"); - else - snprintf(buf, BUF_LEN, "slot: %s%lu", whitespace, sc->slot); - return buf; -} - -/* - * list all smartcard info records in a chained list - */ -void scx_list(bool utc) -{ - smartcard_t *sc = smartcards; - - if (sc != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of Smartcard Objects:"); - } - - while (sc != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " %s, session %s, logged %s, has %s" - , scx_print_slot(sc, " ") - , sc->session_opened? "opened" : "closed" - , sc->logged_in? "in" : "out" - , sc->pinpad? "pin pad" - : ((sc->pin.ptr == NULL)? "no pin" - : sc->valid? "valid pin" : "invalid pin")); - if (sc->id != NULL) - whack_log(RC_COMMENT, " id: %s", sc->id); - if (sc->label != NULL) - whack_log(RC_COMMENT, " label: '%s'", sc->label); - if (sc->last_cert) - { - certificate_t *certificate = sc->last_cert->cert; - - whack_log(RC_COMMENT, " subject: '%Y'", - certificate->get_subject(certificate)); - } - sc = sc->next; - } -} diff --git a/src/pluto/smartcard.h b/src/pluto/smartcard.h deleted file mode 100644 index 7a2229794..000000000 --- a/src/pluto/smartcard.h +++ /dev/null @@ -1,100 +0,0 @@ -/* Support of smartcards and cryptotokens - * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen - * Copyright (C) 2004 David Buechi, Michael Meier - * Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _SMARTCARD_H -#define _SMARTCARD_H - -#include "certs.h" - -#define SCX_TOKEN "%smartcard" -#define SCX_CERT_CACHE_INTERVAL 60 /* seconds */ -#define SCX_MAX_PIN_TRIALS 3 - -/* smartcard operations, update copy in whack.h */ - -#ifndef SC_OP_T -#define SC_OP_T -typedef enum { - SC_OP_NONE = 0, - SC_OP_ENCRYPT = 1, - SC_OP_DECRYPT = 2, - SC_OP_SIGN = 3, -} sc_op_t; -#endif /* SC_OP_T */ - -/* smartcard record */ - -typedef struct smartcard smartcard_t; - -struct smartcard { - smartcard_t *next; - time_t last_load; - cert_t *last_cert; - int count; - int number; - unsigned long slot; - char *id; - char *label; - chunk_t pin; - bool pinpad; - bool valid; - bool session_opened; - bool logged_in; - bool any_slot; - long session; -}; - -extern const smartcard_t empty_sc; - -/* keep a PKCS#11 login during the lifetime of pluto - * flag set in plutomain.c and used in ipsec_doi.c and ocsp.c - */ -extern bool pkcs11_keep_state; - -/* allow other applications access to pluto's PKCS#11 interface - * via whack. Could be used e.g. for disk encryption - */ -extern bool pkcs11_proxy; - -extern smartcard_t* scx_parse_number_slot_id(const char *number_slot_id); -extern void scx_init(const char *module, const char *init_args); -extern void scx_finalize(void); -extern bool scx_establish_context(smartcard_t *sc); -extern bool scx_login(smartcard_t *sc); -extern bool scx_on_smartcard(const char *filename); -extern cert_t* scx_load_cert(const char *filename, smartcard_t **scp, bool *cached); -extern bool scx_verify_pin(smartcard_t *sc); -extern void scx_share(smartcard_t *sc); -extern bool scx_sign_hash(smartcard_t *sc, const u_char *in, size_t inlen - , u_char *out, size_t outlen); -extern bool scx_encrypt(smartcard_t *sc, const u_char *in, size_t inlen - , u_char *out, size_t *outlen); -extern bool scx_decrypt(smartcard_t *sc, const u_char *in, size_t inlen - , u_char *out, size_t *outlen); -extern bool scx_op_via_whack(const char* msg, int inbase, int outbase - , sc_op_t op, const char *keyid, int whackfd); -extern bool scx_get_pin(smartcard_t *sc, int whackfd); -extern size_t scx_get_keylength(smartcard_t *sc); -extern smartcard_t* scx_add(smartcard_t *sc); -extern smartcard_t* scx_get(cert_t *cert); -extern void scx_release(smartcard_t *sc); -extern void scx_release_context(smartcard_t *sc); -extern void scx_free_pin(chunk_t *pin); -extern void scx_free(smartcard_t *sc); -extern void scx_list(bool utc); -extern char *scx_print_slot(smartcard_t *sc, const char *whitespace); - -#endif /* _SMARTCARD_H */ diff --git a/src/pluto/spdb.c b/src/pluto/spdb.c deleted file mode 100644 index 06fe7d7c8..000000000 --- a/src/pluto/spdb.c +++ /dev/null @@ -1,2315 +0,0 @@ -/* Security Policy Data Base (such as it is) - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <sys/queue.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "state.h" -#include "packet.h" -#include "keys.h" -#include "kernel.h" -#include "log.h" -#include "spdb.h" -#include "whack.h" -#include "crypto.h" -#include "alg_info.h" -#include "kernel_alg.h" -#include "ike_alg.h" -#include "db_ops.h" -#include "nat_traversal.h" - -#define AD(x) x, countof(x) /* Array Description */ -#define AD_NULL NULL, 0 - -/**************** Oakely (main mode) SA database ****************/ - -/* array of proposals to be conjoined (can only be one for Oakley) */ - -static struct db_prop oakley_pc[] = - { { PROTO_ISAKMP, AD_NULL } }; - -/* array of proposal conjuncts (can only be one) */ - -static struct db_prop_conj oakley_props[] = { { AD(oakley_pc) } }; - -/* the sadb entry */ -struct db_sa oakley_sadb = { AD(oakley_props) }; - -/**************** IPsec (quick mode) SA database ****************/ - -/* arrays of attributes for transforms */ - -static struct db_attr espsha1_attr[] = { - { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 }, - }; - -static struct db_attr ah_HMAC_SHA1_attr[] = { - { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 }, - }; - -/* arrays of transforms, each in in preference order */ - -static struct db_trans espa_trans[] = { - { ESP_3DES, AD(espsha1_attr) }, - }; - -static struct db_trans esp_trans[] = { - { ESP_3DES, AD_NULL }, - }; - -#ifdef SUPPORT_ESP_NULL -static struct db_trans espnull_trans[] = { - { ESP_NULL, AD(espsha1_attr) }, - }; -#endif /* SUPPORT_ESP_NULL */ - -static struct db_trans ah_trans[] = { - { AH_SHA, AD(ah_HMAC_SHA1_attr) }, - }; - -static struct db_trans ipcomp_trans[] = { - { IPCOMP_DEFLATE, AD_NULL }, - }; - -/* arrays of proposals to be conjoined */ - -static struct db_prop ah_pc[] = { - { PROTO_IPSEC_AH, AD(ah_trans) }, - }; - -#ifdef SUPPORT_ESP_NULL -static struct db_prop espnull_pc[] = { - { PROTO_IPSEC_ESP, AD(espnull_trans) }, - }; -#endif /* SUPPORT_ESP_NULL */ - -static struct db_prop esp_pc[] = { - { PROTO_IPSEC_ESP, AD(espa_trans) }, - }; - -static struct db_prop ah_esp_pc[] = { - { PROTO_IPSEC_AH, AD(ah_trans) }, - { PROTO_IPSEC_ESP, AD(esp_trans) }, - }; - -static struct db_prop compress_pc[] = { - { PROTO_IPCOMP, AD(ipcomp_trans) }, - }; - -static struct db_prop ah_compress_pc[] = { - { PROTO_IPSEC_AH, AD(ah_trans) }, - { PROTO_IPCOMP, AD(ipcomp_trans) }, - }; - -#ifdef SUPPORT_ESP_NULL -static struct db_prop espnull_compress_pc[] = { - { PROTO_IPSEC_ESP, AD(espnull_trans) }, - { PROTO_IPCOMP, AD(ipcomp_trans) }, - }; -#endif /* SUPPORT_ESP_NULL */ - -static struct db_prop esp_compress_pc[] = { - { PROTO_IPSEC_ESP, AD(espa_trans) }, - { PROTO_IPCOMP, AD(ipcomp_trans) }, - }; - -static struct db_prop ah_esp_compress_pc[] = { - { PROTO_IPSEC_AH, AD(ah_trans) }, - { PROTO_IPSEC_ESP, AD(esp_trans) }, - { PROTO_IPCOMP, AD(ipcomp_trans) }, - }; - -/* arrays of proposal alternatives (each element is a conjunction) */ - -static struct db_prop_conj ah_props[] = { - { AD(ah_pc) }, -#ifdef SUPPORT_ESP_NULL - { AD(espnull_pc) } -#endif - }; - -static struct db_prop_conj esp_props[] = - { { AD(esp_pc) } }; - -static struct db_prop_conj ah_esp_props[] = - { { AD(ah_esp_pc) } }; - -static struct db_prop_conj compress_props[] = { - { AD(compress_pc) }, - }; - -static struct db_prop_conj ah_compress_props[] = { - { AD(ah_compress_pc) }, -#ifdef SUPPORT_ESP_NULL - { AD(espnull_compress_pc) } -#endif - }; - -static struct db_prop_conj esp_compress_props[] = - { { AD(esp_compress_pc) } }; - -static struct db_prop_conj ah_esp_compress_props[] = - { { AD(ah_esp_compress_pc) } }; - -/* The IPsec sadb is subscripted by a bitset (subset of policy) - * with members from { POLICY_ENCRYPT, POLICY_AUTHENTICATE, POLICY_COMPRESS } - * shifted right by POLICY_IPSEC_SHIFT. - */ -struct db_sa ipsec_sadb[1 << 3] = { - { AD_NULL }, /* none */ - { AD(esp_props) }, /* POLICY_ENCRYPT */ - { AD(ah_props) }, /* POLICY_AUTHENTICATE */ - { AD(ah_esp_props) }, /* POLICY_ENCRYPT+POLICY_AUTHENTICATE */ - { AD(compress_props) }, /* POLICY_COMPRESS */ - { AD(esp_compress_props) }, /* POLICY_ENCRYPT+POLICY_COMPRESS */ - { AD(ah_compress_props) }, /* POLICY_AUTHENTICATE+POLICY_COMPRESS */ - { AD(ah_esp_compress_props) }, /* POLICY_ENCRYPT+POLICY_AUTHENTICATE+POLICY_COMPRESS */ - }; - -#undef AD -#undef AD_NULL - -/* output an attribute (within an SA) */ -static bool -out_attr(int type -, unsigned long val -, struct_desc *attr_desc -, enum_names **attr_val_descs USED_BY_DEBUG -, pb_stream *pbs) -{ - struct isakmp_attribute attr; - - if (val >> 16 == 0) - { - /* short value: use TV form */ - attr.isaat_af_type = type | ISAKMP_ATTR_AF_TV; - attr.isaat_lv = val; - if (!out_struct(&attr, attr_desc, pbs, NULL)) - return FALSE; - } - else - { - /* This is a real fudge! Since we rarely use long attributes - * and since this is the only place where we can cause an - * ISAKMP message length to be other than a multiple of 4 octets, - * we force the length of the value to be a multiple of 4 octets. - * Furthermore, we only handle values up to 4 octets in length. - * Voila: a fixed format! - */ - pb_stream val_pbs; - u_int32_t nval = htonl(val); - - attr.isaat_af_type = type | ISAKMP_ATTR_AF_TLV; - if (!out_struct(&attr, attr_desc, pbs, &val_pbs) - || !out_raw(&nval, sizeof(nval), &val_pbs, "long attribute value")) - return FALSE; - close_output_pbs(&val_pbs); - } - DBG(DBG_EMITTING, - enum_names *d = attr_val_descs[type]; - - if (d != NULL) - DBG_log(" [%lu is %s]" - , val, enum_show(d, val))); - return TRUE; -} -#define return_on(var, val) do { var=val;goto return_out; } while(0) -/* Output an SA, as described by a db_sa. - * This has the side-effect of allocating SPIs for us. - */ -bool -out_sa(pb_stream *outs -, struct db_sa *sadb -, struct state *st -, bool oakley_mode -, u_int8_t np) -{ - pb_stream sa_pbs; - int pcn; - bool ret = FALSE; - bool ah_spi_generated = FALSE - , esp_spi_generated = FALSE - , ipcomp_cpi_generated = FALSE; -#if !defined NO_KERNEL_ALG || !defined NO_IKE_ALG - struct db_context *db_ctx = NULL; -#endif - - /* SA header out */ - { - struct isakmp_sa sa; - - sa.isasa_np = np; - st->st_doi = sa.isasa_doi = ISAKMP_DOI_IPSEC; /* all we know */ - if (!out_struct(&sa, &isakmp_sa_desc, outs, &sa_pbs)) - return_on(ret, FALSE); - } - - /* within SA: situation out */ - st->st_situation = SIT_IDENTITY_ONLY; - if (!out_struct(&st->st_situation, &ipsec_sit_desc, &sa_pbs, NULL)) - return_on(ret, FALSE); - - /* within SA: Proposal Payloads - * - * Multiple Proposals with the same number are simultaneous - * (conjuncts) and must deal with different protocols (AH or ESP). - * Proposals with different numbers are alternatives (disjuncts), - * in preference order. - * Proposal numbers must be monotonic. - * See RFC 2408 "ISAKMP" 4.2 - */ - - for (pcn = 0; pcn != sadb->prop_conj_cnt; pcn++) - { - struct db_prop_conj *pc = &sadb->prop_conjs[pcn]; - int pn; - - for (pn = 0; pn != pc->prop_cnt; pn++) - { - struct db_prop *p = &pc->props[pn]; - pb_stream proposal_pbs; - struct isakmp_proposal proposal; - struct_desc *trans_desc = NULL; - struct_desc *attr_desc = NULL; - enum_names **attr_val_descs = NULL; - int tn; - bool tunnel_mode; - - tunnel_mode = (pn == pc->prop_cnt-1) - && (st->st_policy & POLICY_TUNNEL); - - /* Proposal header */ - proposal.isap_np = pcn == sadb->prop_conj_cnt-1 && pn == pc->prop_cnt-1 - ? ISAKMP_NEXT_NONE : ISAKMP_NEXT_P; - proposal.isap_proposal = pcn; - proposal.isap_protoid = p->protoid; - proposal.isap_spisize = oakley_mode ? 0 - : p->protoid == PROTO_IPCOMP ? IPCOMP_CPI_SIZE - : IPSEC_DOI_SPI_SIZE; - - /* In quick mode ONLY, create proposal for runtime kernel algos. - * Replace ESP proposals with runtime created one - */ - if (!oakley_mode && p->protoid == PROTO_IPSEC_ESP) - { - DBG(DBG_CONTROL | DBG_CRYPT, - if (st->st_connection->alg_info_esp) - { - static char buf[BUF_LEN]=""; - - alg_info_snprint(buf, sizeof (buf), - (struct alg_info *)st->st_connection->alg_info_esp); - DBG_log("esp proposal: %s", buf); - } - ) - db_ctx = kernel_alg_db_new(st->st_connection->alg_info_esp, st->st_policy); - p = db_prop_get(db_ctx); - - if (!p || p->trans_cnt == 0) - { - loglog(RC_LOG_SERIOUS, - "empty IPSEC SA proposal to send " - "(no kernel algorithms for esp selection)"); - return_on(ret, FALSE); - } - } - - if (oakley_mode && p->protoid == PROTO_ISAKMP) - { - DBG(DBG_CONTROL | DBG_CRYPT, - if (st->st_connection->alg_info_ike) - { - static char buf[BUF_LEN]=""; - - alg_info_snprint(buf, sizeof (buf), - (struct alg_info *)st->st_connection->alg_info_ike); - DBG_log("ike proposal: %s", buf); - } - ) - db_ctx = ike_alg_db_new(st->st_connection, st->st_policy); - p = db_prop_get(db_ctx); - - if (!p || p->trans_cnt == 0) - { - loglog(RC_LOG_SERIOUS, - "empty ISAKMP SA proposal to send " - "(no algorithms for ike selection?)"); - return_on(ret, FALSE); - } - } - - proposal.isap_notrans = p->trans_cnt; - if (!out_struct(&proposal, &isakmp_proposal_desc, &sa_pbs, &proposal_pbs)) - return_on(ret, FALSE); - - /* Per-protocols stuff: - * Set trans_desc. - * Set attr_desc. - * Set attr_val_descs. - * If not oakley_mode, emit SPI. - * We allocate SPIs on demand. - * All ESPs in an SA will share a single SPI. - * All AHs in an SAwill share a single SPI. - * AHs' SPI will be distinct from ESPs'. - * This latter is needed because KLIPS doesn't - * use the protocol when looking up a (dest, protocol, spi). - * ??? If multiple ESPs are composed, how should their SPIs - * be allocated? - */ - { - ipsec_spi_t *spi_ptr = NULL; - int proto = 0; - bool *spi_generated = NULL; - - switch (p->protoid) - { - case PROTO_ISAKMP: - passert(oakley_mode); - trans_desc = &isakmp_isakmp_transform_desc; - attr_desc = &isakmp_oakley_attribute_desc; - attr_val_descs = oakley_attr_val_descs; - /* no SPI needed */ - break; - case PROTO_IPSEC_AH: - passert(!oakley_mode); - trans_desc = &isakmp_ah_transform_desc; - attr_desc = &isakmp_ipsec_attribute_desc; - attr_val_descs = ipsec_attr_val_descs; - spi_ptr = &st->st_ah.our_spi; - spi_generated = &ah_spi_generated; - proto = IPPROTO_AH; - break; - case PROTO_IPSEC_ESP: - passert(!oakley_mode); - trans_desc = &isakmp_esp_transform_desc; - attr_desc = &isakmp_ipsec_attribute_desc; - attr_val_descs = ipsec_attr_val_descs; - spi_ptr = &st->st_esp.our_spi; - spi_generated = &esp_spi_generated; - proto = IPPROTO_ESP; - break; - case PROTO_IPCOMP: - passert(!oakley_mode); - trans_desc = &isakmp_ipcomp_transform_desc; - attr_desc = &isakmp_ipsec_attribute_desc; - attr_val_descs = ipsec_attr_val_descs; - - /* a CPI isn't quite the same as an SPI - * so we use specialized code to emit it. - */ - if (!ipcomp_cpi_generated) - { - st->st_ipcomp.our_spi = get_my_cpi( - &st->st_connection->spd, tunnel_mode); - if (st->st_ipcomp.our_spi == 0) - return_on(ret, FALSE); /* problem generating CPI */ - - ipcomp_cpi_generated = TRUE; - } - /* CPI is stored in network low order end of an - * ipsec_spi_t. So we start a couple of bytes in. - */ - if (!out_raw((u_char *)&st->st_ipcomp.our_spi - + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE - , IPCOMP_CPI_SIZE - , &proposal_pbs, "CPI")) - return_on(ret, FALSE); - break; - default: - bad_case(p->protoid); - } - if (spi_ptr != NULL) - { - if (!*spi_generated) - { - *spi_ptr = get_ipsec_spi(0 - , proto - , &st->st_connection->spd - , tunnel_mode); - if (*spi_ptr == 0) - return_on(ret, FALSE); - *spi_generated = TRUE; - } - if (!out_raw((u_char *)spi_ptr, IPSEC_DOI_SPI_SIZE - , &proposal_pbs, "SPI")) - return_on(ret, FALSE); - } - } - - /* within proposal: Transform Payloads */ - for (tn = 0; tn != p->trans_cnt; tn++) - { - struct db_trans *t = &p->trans[tn]; - pb_stream trans_pbs; - struct isakmp_transform trans; - int an; - - trans.isat_np = (tn == p->trans_cnt - 1) - ? ISAKMP_NEXT_NONE : ISAKMP_NEXT_T; - trans.isat_transnum = tn; - trans.isat_transid = t->transid; - if (!out_struct(&trans, trans_desc, &proposal_pbs, &trans_pbs)) - return_on(ret, FALSE); - - /* Within transform: Attributes. */ - - /* For Phase 2 / Quick Mode, GROUP_DESCRIPTION is - * automatically generated because it must be the same - * in every transform. Except IPCOMP. - */ - if (p->protoid != PROTO_IPCOMP && st->st_pfs_group != NULL) - { - passert(!oakley_mode); - passert(st->st_pfs_group != &unset_group); - out_attr(GROUP_DESCRIPTION, st->st_pfs_group->algo_id - , attr_desc, attr_val_descs - , &trans_pbs); - } - - /* automatically generate duration - * and, for Phase 2 / Quick Mode, encapsulation. - */ - if (oakley_mode) - { - out_attr(OAKLEY_LIFE_TYPE, OAKLEY_LIFE_SECONDS - , attr_desc, attr_val_descs - , &trans_pbs); - out_attr(OAKLEY_LIFE_DURATION - , st->st_connection->sa_ike_life_seconds - , attr_desc, attr_val_descs - , &trans_pbs); - } - else - { - /* RFC 2407 (IPSEC DOI) 4.5 specifies that - * the default is "unspecified (host-dependent)". - * This makes little sense, so we always specify it. - * - * Unlike other IPSEC transforms, IPCOMP defaults - * to Transport Mode, so we can exploit the default - * (draft-shacham-ippcp-rfc2393bis-05.txt 4.1). - */ - if (p->protoid != PROTO_IPCOMP - || st->st_policy & POLICY_TUNNEL) - { -#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT - if ((st->nat_traversal & NAT_T_DETECTED) - && !(st->st_policy & POLICY_TUNNEL)) - { - /* Inform user that we will not respect policy and only - * propose Tunnel Mode - */ - loglog(RC_LOG_SERIOUS, "NAT-Traversal: " - "Transport Mode not allowed due to security concerns -- " - "using Tunnel mode"); - } -#endif - out_attr(ENCAPSULATION_MODE -#ifdef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT - , NAT_T_ENCAPSULATION_MODE(st, st->st_policy) -#else - /* If NAT-T is detected, use UDP_TUNNEL as long as Transport - * Mode has security concerns. - * - * User has been informed of that - */ - , NAT_T_ENCAPSULATION_MODE(st, POLICY_TUNNEL) -#endif - , attr_desc, attr_val_descs - , &trans_pbs); - } - out_attr(SA_LIFE_TYPE, SA_LIFE_TYPE_SECONDS - , attr_desc, attr_val_descs - , &trans_pbs); - out_attr(SA_LIFE_DURATION - , st->st_connection->sa_ipsec_life_seconds - , attr_desc, attr_val_descs - , &trans_pbs); - } - - /* spit out attributes from table */ - for (an = 0; an != t->attr_cnt; an++) - { - struct db_attr *a = &t->attrs[an]; - - out_attr(a->type, a->val - , attr_desc, attr_val_descs - , &trans_pbs); - } - - close_output_pbs(&trans_pbs); - } - close_output_pbs(&proposal_pbs); - } - /* end of a conjunction of proposals */ - } - close_output_pbs(&sa_pbs); - ret = TRUE; - -return_out: - -#if !defined NO_KERNEL_ALG || !defined NO_IKE_ALG - if (db_ctx) - db_destroy(db_ctx); -#endif - return ret; -} - -/* Handle long form of duration attribute. - * The code is can only handle values that can fit in unsigned long. - * "Clamping" is probably an acceptable way to impose this limitation. - */ -static u_int32_t decode_long_duration(pb_stream *pbs) -{ - u_int32_t val = 0; - - /* ignore leading zeros */ - while (pbs_left(pbs) != 0 && *pbs->cur == '\0') - pbs->cur++; - - if (pbs_left(pbs) > sizeof(val)) - { - /* "clamp" too large value to max representable value */ - val = UINT32_MAX; - DBG(DBG_PARSING, DBG_log(" too large duration clamped to: %lu" - , (unsigned long)val)); - } - else - { - /* decode number */ - while (pbs_left(pbs) != 0) - val = (val << BITS_PER_BYTE) | *pbs->cur++; - DBG(DBG_PARSING, DBG_log(" long duration: %lu", (unsigned long)val)); - } - return val; -} - -/* Preparse the body of an ISAKMP SA Payload and - * return body of ISAKMP Proposal Payload - * - * Only IPsec DOI is accepted (what is the ISAKMP DOI?). - * Error response is rudimentary. - */ -notification_t -preparse_isakmp_sa_body(const struct isakmp_sa *sa - , pb_stream *sa_pbs - , u_int32_t *ipsecdoisit - , pb_stream *proposal_pbs - , struct isakmp_proposal *proposal) -{ - /* DOI */ - if (sa->isasa_doi != ISAKMP_DOI_IPSEC) - { - loglog(RC_LOG_SERIOUS, "Unknown/unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi)); - /* XXX Could send notification back */ - return ISAKMP_DOI_NOT_SUPPORTED; - } - - /* Situation */ - if (!in_struct(ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) - { - return ISAKMP_SITUATION_NOT_SUPPORTED; - } - if (*ipsecdoisit != SIT_IDENTITY_ONLY) - { - loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)" - , bitnamesof(sit_bit_names, *ipsecdoisit)); - /* XXX Could send notification back */ - return ISAKMP_SITUATION_NOT_SUPPORTED; - } - - /* The rules for ISAKMP SAs are scattered. - * RFC 2409 "IKE" section 5 says that there - * can only be one SA, and it can have only one proposal in it. - * There may well be multiple transforms. - */ - if (!in_struct(proposal, &isakmp_proposal_desc, sa_pbs, proposal_pbs)) - { - return ISAKMP_PAYLOAD_MALFORMED; - } - if (proposal->isap_np != ISAKMP_NEXT_NONE) - { - loglog(RC_LOG_SERIOUS, "Proposal Payload must be alone in Oakley SA; found %s following Proposal" - , enum_show(&payload_names, proposal->isap_np)); - return ISAKMP_PAYLOAD_MALFORMED; - } - - if (proposal->isap_protoid != PROTO_ISAKMP) - { - loglog(RC_LOG_SERIOUS, "unexpected Protocol ID (%s) found in Oakley Proposal" - , enum_show(&protocol_names, proposal->isap_protoid)); - return ISAKMP_INVALID_PROTOCOL_ID; - } - - /* Just what should we accept for the SPI field? - * The RFC is sort of contradictory. We will ignore the SPI - * as long as it is of the proper size. - * - * From RFC2408 2.4 Identifying Security Associations: - * During phase 1 negotiations, the initiator and responder cookies - * determine the ISAKMP SA. Therefore, the SPI field in the Proposal - * payload is redundant and MAY be set to 0 or it MAY contain the - * transmitting entity's cookie. - * - * From RFC2408 3.5 Proposal Payload: - * o SPI Size (1 octet) - Length in octets of the SPI as defined by - * the Protocol-Id. In the case of ISAKMP, the Initiator and - * Responder cookie pair from the ISAKMP Header is the ISAKMP SPI, - * therefore, the SPI Size is irrelevant and MAY be from zero (0) to - * sixteen (16). If the SPI Size is non-zero, the content of the - * SPI field MUST be ignored. If the SPI Size is not a multiple of - * 4 octets it will have some impact on the SPI field and the - * alignment of all payloads in the message. The Domain of - * Interpretation (DOI) will dictate the SPI Size for other - * protocols. - */ - if (proposal->isap_spisize == 0) - { - /* empty (0) SPI -- fine */ - } - else if (proposal->isap_spisize <= MAX_ISAKMP_SPI_SIZE) - { - u_char junk_spi[MAX_ISAKMP_SPI_SIZE]; - - if (!in_raw(junk_spi, proposal->isap_spisize, proposal_pbs, "Oakley SPI")) - return ISAKMP_PAYLOAD_MALFORMED; - } - else - { - loglog(RC_LOG_SERIOUS, "invalid SPI size (%u) in Oakley Proposal" - , (unsigned)proposal->isap_spisize); - return ISAKMP_INVALID_SPI; - } - return ISAKMP_NOTHING_WRONG; -} - -static struct { - u_int8_t *start; - u_int8_t *cur; - u_int8_t *roof; -} backup; - -/** - * Backup the pointer into a pb_stream - */ -void backup_pbs(pb_stream *pbs) -{ - backup.start = pbs->start; - backup.cur = pbs->cur; - backup.roof = pbs->roof; -} - -/** - * Restore the pointer into a pb_stream - */ -void restore_pbs(pb_stream *pbs) -{ - pbs->start = backup.start; - pbs->cur = backup.cur; - pbs->roof = backup.roof; -} - -/** - * Parse an ISAKMP Proposal Payload for RSA and PSK authentication policies - */ -notification_t parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans, - lset_t *policy) -{ - int last_transnum = -1; - - *policy = LEMPTY; - - while (notrans--) - { - pb_stream trans_pbs; - u_char *attr_start; - size_t attr_len; - struct isakmp_transform trans; - - if (!in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs)) - { - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - if (trans.isat_transnum <= last_transnum) - { - /* picky, picky, picky */ - loglog(RC_LOG_SERIOUS, "Transform Numbers are not monotonically increasing" - " in Oakley Proposal"); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - last_transnum = trans.isat_transnum; - - if (trans.isat_transid != KEY_IKE) - { - loglog(RC_LOG_SERIOUS, "expected KEY_IKE but found %s in Oakley Transform" - , enum_show(&isakmp_transformid_names, trans.isat_transid)); - return ISAKMP_INVALID_TRANSFORM_ID; - } - - attr_start = trans_pbs.cur; - attr_len = pbs_left(&trans_pbs); - - /* preprocess authentication attributes only */ - while (pbs_left(&trans_pbs) != 0) - { - struct isakmp_attribute a; - pb_stream attr_pbs; - - if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs)) - { - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); - - switch (a.isaat_af_type) - { - case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV: - switch (a.isaat_lv) - { - case OAKLEY_PRESHARED_KEY: - *policy |= POLICY_PSK; - break; - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - *policy |= POLICY_PUBKEY; - break; - case XAUTHInitPreShared: - *policy |= POLICY_XAUTH_SERVER; - /* fall through */ - case XAUTHRespPreShared: - *policy |= POLICY_XAUTH_PSK; - break; - case XAUTHInitRSA: - *policy |= POLICY_XAUTH_SERVER; - /* fall through */ - case XAUTHRespRSA: - *policy |= POLICY_XAUTH_RSASIG; - break; - default: - break; - } - break; - default: - break; - } - } - } - DBG(DBG_CONTROL|DBG_PARSING, - DBG_log("preparse_isakmp_policy: peer requests %s authentication" - , prettypolicy(*policy)) - ) - return ISAKMP_NOTHING_WRONG; -} - -/** - * Check that we can find a preshared secret - */ -static err_t find_preshared_key(struct state* st) -{ - err_t ugh = NULL; - connection_t *c = st->st_connection; - - if (get_preshared_secret(c) == NULL) - { - char his_id[BUF_LEN]; - - if (his_id_was_instantiated(c)) - { - strcpy(his_id, "%any"); - } - else - { - snprintf(his_id, sizeof(his_id), "%Y", c->spd.that.id); - } - ugh = builddiag("Can't authenticate: no preshared key found " - "for '%Y' and '%s'", c->spd.this.id, his_id); - } - return ugh; -} - -/* Parse the body of an ISAKMP SA Payload (i.e. Phase 1 / Main Mode). - * Various shortcuts are taken. In particular, the policy, such as - * it is, is hardwired. - * - * If r_sa is non-NULL, the body of an SA representing the selected - * proposal is emitted. - * - * This routine is used by main_inI1_outR1() and main_inR1_outI2(). - */ -notification_t parse_isakmp_sa_body(u_int32_t ipsecdoisit, - pb_stream *proposal_pbs, - struct isakmp_proposal *proposal, - pb_stream *r_sa_pbs, - struct state *st, - bool initiator) -{ - connection_t *c = st->st_connection; - unsigned no_trans_left; - - /* for each transform payload... */ - no_trans_left = proposal->isap_notrans; - - for (;;) - { - pb_stream trans_pbs; - u_char *attr_start; - size_t attr_len; - struct isakmp_transform trans; - lset_t seen_attrs = 0; - lset_t seen_durations = 0; - u_int16_t life_type = 0; - struct oakley_trans_attrs ta = { .encrypter = NULL }; - err_t ugh = NULL; /* set to diagnostic when problem detected */ - - /* initialize only optional field in ta */ - ta.life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT; /* When this SA expires (seconds) */ - - if (no_trans_left == 0) - { - loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload"); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - - in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs); - attr_start = trans_pbs.cur; - attr_len = pbs_left(&trans_pbs); - - /* process all the attributes that make up the transform */ - - while (pbs_left(&trans_pbs) != 0) - { - struct isakmp_attribute a; - pb_stream attr_pbs; - u_int32_t val; /* room for larger values */ - - if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs)) - return ISAKMP_BAD_PROPOSAL_SYNTAX; - - passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); - - if (LHAS(seen_attrs, a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK)) - { - loglog(RC_LOG_SERIOUS, "repeated %s attribute in Oakley Transform %u" - , enum_show(&oakley_attr_names, a.isaat_af_type) - , trans.isat_transnum); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - - seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK); - - val = a.isaat_lv; - - DBG(DBG_PARSING, - { - enum_names *vdesc = oakley_attr_val_descs - [a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK]; - - if (vdesc != NULL) - { - const char *nm = enum_name(vdesc, val); - - if (nm != NULL) - DBG_log(" [%u is %s]", (unsigned)val, nm); - } - }); - - switch (a.isaat_af_type) - { - case OAKLEY_ENCRYPTION_ALGORITHM | ISAKMP_ATTR_AF_TV: - if (ike_alg_get_crypter(val)) - { - ta.encrypt = val; - ta.encrypter = ike_alg_get_crypter(val); - ta.enckeylen = ta.encrypter->keydeflen; - } - else - { - ugh = builddiag("%s is not supported" - , enum_show(&oakley_enc_names, val)); - } - break; - - case OAKLEY_HASH_ALGORITHM | ISAKMP_ATTR_AF_TV: - if (ike_alg_get_hasher(val)) - { - ta.hash = val; - ta.hasher = ike_alg_get_hasher(val); - } - else - { - ugh = builddiag("%s is not supported" - , enum_show(&oakley_hash_names, val)); - } - break; - - case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV: - { - /* check that authentication method is acceptable */ - lset_t iap = st->st_policy & POLICY_ID_AUTH_MASK; - - /* is the initiator the XAUTH client? */ - bool xauth_init = ( initiator && (st->st_policy & POLICY_XAUTH_SERVER) == LEMPTY) - || (!initiator && (st->st_policy & POLICY_XAUTH_SERVER) != LEMPTY); - - switch (val) - { - case OAKLEY_PRESHARED_KEY: - if ((iap & POLICY_PSK) == LEMPTY) - { - ugh = "policy does not allow pre-shared key authentication"; - } - else - { - ugh = find_preshared_key(st); - ta.auth = OAKLEY_PRESHARED_KEY; - } - break; - case XAUTHInitPreShared: - if ((iap & POLICY_XAUTH_PSK) == LEMPTY || !xauth_init) - { - ugh = "policy does not allow XAUTHInitPreShared authentication"; - } - else - { - ugh = find_preshared_key(st); - ta.auth = XAUTHInitPreShared; - } - break; - case XAUTHRespPreShared: - if ((iap & POLICY_XAUTH_PSK) == LEMPTY || xauth_init) - { - ugh = "policy does not allow XAUTHRespPreShared authentication"; - } - else - { - ugh = find_preshared_key(st); - ta.auth = XAUTHRespPreShared; - } - break; - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - if ((iap & POLICY_PUBKEY) == LEMPTY) - { - ugh = "policy does not allow public key authentication"; - } - else - { - ta.auth = val; - } - break; - case XAUTHInitRSA: - if ((iap & POLICY_XAUTH_RSASIG) == LEMPTY || !xauth_init) - { - ugh = "policy does not allow XAUTHInitRSA authentication"; - } - else - { - ta.auth = XAUTHInitRSA; - } - break; - case XAUTHRespRSA: - if ((iap & POLICY_XAUTH_RSASIG) == LEMPTY || xauth_init) - { - ugh = "policy does not allow XAUTHRespRSA authentication"; - } - else - { - ta.auth = XAUTHRespRSA; - } - break; - default: - ugh = builddiag("Pluto does not support %s authentication" - , enum_show(&oakley_auth_names, val)); - break; - } - } - break; - - case OAKLEY_GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV: - ta.group = ike_alg_get_dh_group(val); - if (ta.group == NULL) - { - ugh = builddiag("%s is not supported" - , enum_show(&oakley_group_names, val)); - } - break; - - case OAKLEY_LIFE_TYPE | ISAKMP_ATTR_AF_TV: - switch (val) - { - case OAKLEY_LIFE_SECONDS: - case OAKLEY_LIFE_KILOBYTES: - if (LHAS(seen_durations, val)) - { - loglog(RC_LOG_SERIOUS - , "attribute OAKLEY_LIFE_TYPE value %s repeated" - , enum_show(&oakley_lifetime_names, val)); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - seen_durations |= LELEM(val); - life_type = val; - break; - default: - ugh = builddiag("unknown value %s" - , enum_show(&oakley_lifetime_names, val)); - break; - } - break; - - case OAKLEY_LIFE_DURATION | ISAKMP_ATTR_AF_TLV: - val = decode_long_duration(&attr_pbs); - /* fall through */ - case OAKLEY_LIFE_DURATION | ISAKMP_ATTR_AF_TV: - if (!LHAS(seen_attrs, OAKLEY_LIFE_TYPE)) - { - ugh = "OAKLEY_LIFE_DURATION attribute not preceded by OAKLEY_LIFE_TYPE attribute"; - break; - } - seen_attrs &= ~(LELEM(OAKLEY_LIFE_DURATION) | LELEM(OAKLEY_LIFE_TYPE)); - - switch (life_type) - { - case OAKLEY_LIFE_SECONDS: - if (val > OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM) - { -#ifdef CISCO_QUIRKS - plog("peer requested %lu seconds" - " which exceeds our limit %d seconds" - , (long) val - , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM); - plog("lifetime reduced to %d seconds " - "(todo: IPSEC_RESPONDER_LIFETIME notification)" - , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM); - val = OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM; -#else - ugh = builddiag("peer requested %lu seconds" - " which exceeds our limit %d seconds" - , (long) val - , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM); -#endif - } - ta.life_seconds = val; - break; - case OAKLEY_LIFE_KILOBYTES: - ta.life_kilobytes = val; - break; - default: - bad_case(life_type); - } - break; - - case OAKLEY_KEY_LENGTH | ISAKMP_ATTR_AF_TV: - if ((seen_attrs & LELEM(OAKLEY_ENCRYPTION_ALGORITHM)) == 0) - { - ugh = "OAKLEY_KEY_LENGTH attribute not preceded by " - "OAKLEY_ENCRYPTION_ALGORITHM attribute"; - break; - } - if (ta.encrypter == NULL) - { - ugh = "NULL encrypter with seen OAKLEY_ENCRYPTION_ALGORITHM"; - break; - } - /* - * check if this keylen is compatible with specified algorithm - */ - if (val - && (val < ta.encrypter->keyminlen || val > ta.encrypter->keymaxlen)) - { - ugh = "peer proposed key length not valid for " - "encryption algorithm specified"; - } - ta.enckeylen = val; - break; -#if 0 /* not yet supported */ - case OAKLEY_GROUP_TYPE | ISAKMP_ATTR_AF_TV: - case OAKLEY_PRF | ISAKMP_ATTR_AF_TV: - case OAKLEY_FIELD_SIZE | ISAKMP_ATTR_AF_TV: - - case OAKLEY_GROUP_PRIME | ISAKMP_ATTR_AF_TV: - case OAKLEY_GROUP_PRIME | ISAKMP_ATTR_AF_TLV: - case OAKLEY_GROUP_GENERATOR_ONE | ISAKMP_ATTR_AF_TV: - case OAKLEY_GROUP_GENERATOR_ONE | ISAKMP_ATTR_AF_TLV: - case OAKLEY_GROUP_GENERATOR_TWO | ISAKMP_ATTR_AF_TV: - case OAKLEY_GROUP_GENERATOR_TWO | ISAKMP_ATTR_AF_TLV: - case OAKLEY_GROUP_CURVE_A | ISAKMP_ATTR_AF_TV: - case OAKLEY_GROUP_CURVE_A | ISAKMP_ATTR_AF_TLV: - case OAKLEY_GROUP_CURVE_B | ISAKMP_ATTR_AF_TV: - case OAKLEY_GROUP_CURVE_B | ISAKMP_ATTR_AF_TLV: - case OAKLEY_GROUP_ORDER | ISAKMP_ATTR_AF_TV: - case OAKLEY_GROUP_ORDER | ISAKMP_ATTR_AF_TLV: -#endif - default: - /* fix compiler warning */ - memset(&ta, 0, sizeof(ta)); - ugh = "unsupported OAKLEY attribute"; - break; - } - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "%s. Attribute %s" - , ugh, enum_show(&oakley_attr_names, a.isaat_af_type)); - break; - } - } - - /* - * ML: at last check for allowed transforms in alg_info_ike - * (ALG_INFO_F_STRICT flag) - */ - if (ugh == NULL) - { - if (!ike_alg_ok_final(ta.encrypt, ta.enckeylen, ta.hash, - ta.group ? ta.group->algo_id : -1, c->alg_info_ike)) - { - ugh = "OAKLEY proposal refused"; - } - } - - if (ugh == NULL) - { - /* a little more checking is in order */ - { - lset_t missing - = ~seen_attrs - & (LELEM(OAKLEY_ENCRYPTION_ALGORITHM) - | LELEM(OAKLEY_HASH_ALGORITHM) - | LELEM(OAKLEY_AUTHENTICATION_METHOD) - | LELEM(OAKLEY_GROUP_DESCRIPTION)); - - if (missing) - { - loglog(RC_LOG_SERIOUS, "missing mandatory attribute(s) %s in Oakley Transform %u" - , bitnamesof(oakley_attr_bit_names, missing) - , trans.isat_transnum); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - } - /* We must have liked this transform. - * Lets finish early and leave. - */ - - DBG(DBG_PARSING | DBG_CRYPT - , DBG_log("Oakley Transform %u accepted", trans.isat_transnum)); - - if (r_sa_pbs != NULL) - { - struct isakmp_proposal r_proposal = *proposal; - pb_stream r_proposal_pbs; - struct isakmp_transform r_trans = trans; - pb_stream r_trans_pbs; - - /* Situation */ - if (!out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL)) - impossible(); - - /* Proposal */ -#ifdef EMIT_ISAKMP_SPI - r_proposal.isap_spisize = COOKIE_SIZE; -#else - r_proposal.isap_spisize = 0; -#endif - r_proposal.isap_notrans = 1; - if (!out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)) - impossible(); - - /* SPI */ -#ifdef EMIT_ISAKMP_SPI - if (!out_raw(my_cookie, COOKIE_SIZE, &r_proposal_pbs, "SPI")) - impossible(); - r_proposal.isap_spisize = COOKIE_SIZE; -#else - /* none (0) */ -#endif - - /* Transform */ - r_trans.isat_np = ISAKMP_NEXT_NONE; - if (!out_struct(&r_trans, &isakmp_isakmp_transform_desc, &r_proposal_pbs, &r_trans_pbs)) - impossible(); - - if (!out_raw(attr_start, attr_len, &r_trans_pbs, "attributes")) - impossible(); - close_output_pbs(&r_trans_pbs); - close_output_pbs(&r_proposal_pbs); - close_output_pbs(r_sa_pbs); - } - - /* copy over the results */ - st->st_oakley = ta; - return ISAKMP_NOTHING_WRONG; - } - - /* on to next transform */ - no_trans_left--; - - if (trans.isat_np == ISAKMP_NEXT_NONE) - { - if (no_trans_left != 0) - { - loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload"); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - break; - } - if (trans.isat_np != ISAKMP_NEXT_T) - { - loglog(RC_LOG_SERIOUS, "unexpected %s payload in Oakley Proposal" - , enum_show(&payload_names, proposal->isap_np)); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - } - loglog(RC_LOG_SERIOUS, "no acceptable Oakley Transform"); - return ISAKMP_NO_PROPOSAL_CHOSEN; -} - -/* Parse the body of an IPsec SA Payload (i.e. Phase 2 / Quick Mode). - * - * The main routine is parse_ipsec_sa_body; other functions defined - * between here and there are just helpers. - * - * Various shortcuts are taken. In particular, the policy, such as - * it is, is hardwired. - * - * If r_sa is non-NULL, the body of an SA representing the selected - * proposal is emitted into it. - * - * If "selection" is true, the SA is supposed to represent the - * single transform that the peer has accepted. - * ??? We only check that it is acceptable, not that it is one that we offered! - * - * Only IPsec DOI is accepted (what is the ISAKMP DOI?). - * Error response is rudimentary. - * - * Since all ISAKMP groups in all SA Payloads must match, st->st_pfs_group - * holds this across multiple payloads. - * &unset_group signifies not yet "set"; NULL signifies NONE. - * - * This routine is used by quick_inI1_outR1() and quick_inR1_outI2(). - */ - -static const struct ipsec_trans_attrs null_ipsec_trans_attrs = { - 0, /* transid (NULL, for now) */ - 0, /* spi */ - SA_LIFE_DURATION_DEFAULT, /* life_seconds */ - SA_LIFE_DURATION_K_DEFAULT, /* life_kilobytes */ - ENCAPSULATION_MODE_UNSPECIFIED, /* encapsulation */ - AUTH_ALGORITHM_NONE, /* auth */ - 0, /* key_len */ - 0, /* key_rounds */ -}; - -static bool parse_ipsec_transform(struct isakmp_transform *trans, - struct ipsec_trans_attrs *attrs, - pb_stream *prop_pbs, - pb_stream *trans_pbs, - struct_desc *trans_desc, - int previous_transnum, /* or -1 if none */ - bool selection, bool is_last, bool is_ipcomp, - struct state *st) /* current state object */ -{ - lset_t seen_attrs = 0; - lset_t seen_durations = 0; - u_int16_t life_type = 0; - const struct dh_desc *pfs_group = NULL; - - if (!in_struct(trans, trans_desc, prop_pbs, trans_pbs)) - { - return FALSE; - } - if (trans->isat_transnum <= previous_transnum) - { - loglog(RC_LOG_SERIOUS, "Transform Numbers in Proposal are not monotonically increasing"); - return FALSE; - } - - switch (trans->isat_np) - { - case ISAKMP_NEXT_T: - if (is_last) - { - loglog(RC_LOG_SERIOUS, "Proposal Payload has more Transforms than specified"); - return FALSE; - } - break; - case ISAKMP_NEXT_NONE: - if (!is_last) - { - loglog(RC_LOG_SERIOUS, "Proposal Payload has fewer Transforms than specified"); - return FALSE; - } - break; - default: - loglog(RC_LOG_SERIOUS, "expecting Transform Payload, but found %s in Proposal" - , enum_show(&payload_names, trans->isat_np)); - return FALSE; - } - - *attrs = null_ipsec_trans_attrs; - attrs->transid = trans->isat_transid; - - while (pbs_left(trans_pbs) != 0) - { - struct isakmp_attribute a; - pb_stream attr_pbs; - enum_names *vdesc; - u_int32_t val; /* room for larger value */ - bool ipcomp_inappropriate = is_ipcomp; /* will get reset if OK */ - - if (!in_struct(&a, &isakmp_ipsec_attribute_desc, trans_pbs, &attr_pbs)) - return FALSE; - - passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); - - if (LHAS(seen_attrs, a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK)) - { - loglog(RC_LOG_SERIOUS, "repeated %s attribute in IPsec Transform %u" - , enum_show(&ipsec_attr_names, a.isaat_af_type) - , trans->isat_transnum); - return FALSE; - } - - seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK); - - val = a.isaat_lv; - - vdesc = ipsec_attr_val_descs[a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK]; - if (vdesc != NULL) - { - if (enum_name(vdesc, val) == NULL) - { - loglog(RC_LOG_SERIOUS, "invalid value %u for attribute %s in IPsec Transform" - , (unsigned)val, enum_show(&ipsec_attr_names, a.isaat_af_type)); - return FALSE; - } - DBG(DBG_PARSING - , if ((a.isaat_af_type & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - DBG_log(" [%u is %s]" - , (unsigned)val, enum_show(vdesc, val))); - } - - switch (a.isaat_af_type) - { - case SA_LIFE_TYPE | ISAKMP_ATTR_AF_TV: - ipcomp_inappropriate = FALSE; - if (LHAS(seen_durations, val)) - { - loglog(RC_LOG_SERIOUS, "attribute SA_LIFE_TYPE value %s repeated in message" - , enum_show(&sa_lifetime_names, val)); - return FALSE; - } - seen_durations |= LELEM(val); - life_type = val; - break; - case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TLV: - val = decode_long_duration(&attr_pbs); - /* fall through */ - case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TV: - ipcomp_inappropriate = FALSE; - if (!LHAS(seen_attrs, SA_LIFE_DURATION)) - { - loglog(RC_LOG_SERIOUS, "SA_LIFE_DURATION IPsec attribute not preceded by SA_LIFE_TYPE attribute"); - return FALSE; - } - seen_attrs &= ~(LELEM(SA_LIFE_DURATION) | LELEM(SA_LIFE_TYPE)); - - switch (life_type) - { - case SA_LIFE_TYPE_SECONDS: - /* silently limit duration to our maximum */ - attrs->life_seconds = val <= SA_LIFE_DURATION_MAXIMUM - ? val : SA_LIFE_DURATION_MAXIMUM; - break; - case SA_LIFE_TYPE_KBYTES: - attrs->life_kilobytes = val; - break; - default: - bad_case(life_type); - } - break; - case GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV: - if (is_ipcomp) - { - /* Accept reluctantly. Should not happen, according to - * draft-shacham-ippcp-rfc2393bis-05.txt 4.1. - */ - ipcomp_inappropriate = FALSE; - loglog(RC_COMMENT - , "IPCA (IPcomp SA) contains GROUP_DESCRIPTION." - " Ignoring inapproprate attribute."); - } - pfs_group = ike_alg_get_dh_group(val); - if (pfs_group == NULL) - { - loglog(RC_LOG_SERIOUS, "only OAKLEY_GROUP_MODP1024 and OAKLEY_GROUP_MODP1536 supported for PFS"); - return FALSE; - } - break; - case ENCAPSULATION_MODE | ISAKMP_ATTR_AF_TV: - ipcomp_inappropriate = FALSE; - switch (val) - { - case ENCAPSULATION_MODE_TUNNEL: - case ENCAPSULATION_MODE_TRANSPORT: - if (st->nat_traversal & NAT_T_DETECTED) - { - loglog(RC_LOG_SERIOUS - , "%s must only be used if NAT-Traversal is not detected" - , enum_name(&enc_mode_names, val)); - /* - * Accept it anyway because SSH-Sentinel does not - * use UDP_TUNNEL or UDP_TRANSPORT for the diagnostic. - * - * remove when SSH-Sentinel is fixed - */ -#ifdef I_DONT_CARE_OF_SSH_SENTINEL - return FALSE; -#endif - } - attrs->encapsulation = val; - break; - case ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS: -#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT - loglog(RC_LOG_SERIOUS - , "NAT-Traversal: Transport mode disabled due to security concerns"); - return FALSE; -#endif - case ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS: - if (st->nat_traversal & NAT_T_WITH_RFC_VALUES) - { - loglog(RC_LOG_SERIOUS - , "%s must only be used with old IETF drafts" - , enum_name(&enc_mode_names, val)); - return FALSE; - } - else if (st->nat_traversal & NAT_T_DETECTED) - { - attrs->encapsulation = val - - ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS - + ENCAPSULATION_MODE_TUNNEL; - } - else - { - loglog(RC_LOG_SERIOUS - , "%s must only be used if NAT-Traversal is detected" - , enum_name(&enc_mode_names, val)); - return FALSE; - } - break; - case ENCAPSULATION_MODE_UDP_TRANSPORT_RFC: -#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT - loglog(RC_LOG_SERIOUS - , "NAT-Traversal: Transport mode disabled due " - "to security concerns"); - return FALSE; -#endif - case ENCAPSULATION_MODE_UDP_TUNNEL_RFC: - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->nat_traversal & NAT_T_WITH_RFC_VALUES)) - { - attrs->encapsulation = val - - ENCAPSULATION_MODE_UDP_TUNNEL_RFC - + ENCAPSULATION_MODE_TUNNEL; - } - else if (st->nat_traversal & NAT_T_DETECTED) - { - loglog(RC_LOG_SERIOUS - , "%s must only be used with NAT-T RFC" - , enum_name(&enc_mode_names, val)); - return FALSE; - } - else - { - loglog(RC_LOG_SERIOUS - , "%s must only be used if NAT-Traversal is detected" - , enum_name(&enc_mode_names, val)); - return FALSE; - } - break; - default: - loglog(RC_LOG_SERIOUS - , "unknown ENCAPSULATION_MODE %d in IPSec SA", val); - return FALSE; - } - break; - case AUTH_ALGORITHM | ISAKMP_ATTR_AF_TV: - attrs->auth = val; - break; - case KEY_LENGTH | ISAKMP_ATTR_AF_TV: - attrs->key_len = val; - break; - case KEY_ROUNDS | ISAKMP_ATTR_AF_TV: - attrs->key_rounds = val; - break; -#if 0 /* not yet implemented */ - case COMPRESS_DICT_SIZE | ISAKMP_ATTR_AF_TV: - break; - case COMPRESS_PRIVATE_ALG | ISAKMP_ATTR_AF_TV: - break; - - case SA_LIFE_DURATION | ISAKMP_ATTR_AF_TLV: - break; - case COMPRESS_PRIVATE_ALG | ISAKMP_ATTR_AF_TLV: - break; -#endif - default: - loglog(RC_LOG_SERIOUS, "unsupported IPsec attribute %s" - , enum_show(&ipsec_attr_names, a.isaat_af_type)); - return FALSE; - } - if (ipcomp_inappropriate) - { - loglog(RC_LOG_SERIOUS, "IPsec attribute %s inappropriate for IPCOMP" - , enum_show(&ipsec_attr_names, a.isaat_af_type)); - return FALSE; - } - } - - /* Although an IPCOMP SA (IPCA) ought not to have a pfs_group, - * if it does, demand that it be consistent. - * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1. - */ - if (!is_ipcomp || pfs_group != NULL) - { - if (st->st_pfs_group == &unset_group) - st->st_pfs_group = pfs_group; - - if (st->st_pfs_group != pfs_group) - { - loglog(RC_LOG_SERIOUS, "GROUP_DESCRIPTION inconsistent with that of %s in IPsec SA" - , selection? "the Proposal" : "a previous Transform"); - return FALSE; - } - } - - if (LHAS(seen_attrs, SA_LIFE_DURATION)) - { - loglog(RC_LOG_SERIOUS, "SA_LIFE_TYPE IPsec attribute not followed by SA_LIFE_DURATION attribute in message"); - return FALSE; - } - - if (!LHAS(seen_attrs, ENCAPSULATION_MODE)) - { - if (is_ipcomp) - { - /* draft-shacham-ippcp-rfc2393bis-05.txt 4.1: - * "If the Encapsulation Mode is unspecified, - * the default value of Transport Mode is assumed." - * This contradicts/overrides the DOI (quuoted below). - */ - attrs->encapsulation = ENCAPSULATION_MODE_TRANSPORT; - } - else - { - /* ??? Technically, RFC 2407 (IPSEC DOI) 4.5 specifies that - * the default is "unspecified (host-dependent)". - * This makes little sense, so we demand that it be specified. - */ - loglog(RC_LOG_SERIOUS, "IPsec Transform must specify ENCAPSULATION_MODE"); - return FALSE; - } - } - - /* ??? should check for key_len and/or key_rounds if required */ - - return TRUE; -} - -static void -echo_proposal( - struct isakmp_proposal r_proposal, /* proposal to emit */ - struct isakmp_transform r_trans, /* winning transformation within it */ - u_int8_t np, /* Next Payload for proposal */ - pb_stream *r_sa_pbs, /* SA PBS into which to emit */ - struct ipsec_proto_info *pi, /* info about this protocol instance */ - struct_desc *trans_desc, /* descriptor for this transformation */ - pb_stream *trans_pbs, /* PBS for incoming transform */ - struct spd_route *sr, /* host details for the association */ - bool tunnel_mode) /* true for inner most tunnel SA */ -{ - pb_stream r_proposal_pbs; - pb_stream r_trans_pbs; - - /* Proposal */ - r_proposal.isap_np = np; - r_proposal.isap_notrans = 1; - if (!out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)) - impossible(); - - /* allocate and emit our CPI/SPI */ - if (r_proposal.isap_protoid == PROTO_IPCOMP) - { - /* CPI is stored in network low order end of an - * ipsec_spi_t. So we start a couple of bytes in. - * Note: we may fail to generate a satisfactory CPI, - * but we'll ignore that. - */ - pi->our_spi = get_my_cpi(sr, tunnel_mode); - out_raw((u_char *) &pi->our_spi - + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE - , IPCOMP_CPI_SIZE - , &r_proposal_pbs, "CPI"); - } - else - { - pi->our_spi = get_ipsec_spi(pi->attrs.spi - , r_proposal.isap_protoid == PROTO_IPSEC_AH ? - IPPROTO_AH : IPPROTO_ESP - , sr - , tunnel_mode); - /* XXX should check for errors */ - out_raw((u_char *) &pi->our_spi, IPSEC_DOI_SPI_SIZE - , &r_proposal_pbs, "SPI"); - } - - /* Transform */ - r_trans.isat_np = ISAKMP_NEXT_NONE; - if (!out_struct(&r_trans, trans_desc, &r_proposal_pbs, &r_trans_pbs)) - impossible(); - - /* Transform Attributes: pure echo */ - trans_pbs->cur = trans_pbs->start + sizeof(struct isakmp_transform); - if (!out_raw(trans_pbs->cur, pbs_left(trans_pbs) - , &r_trans_pbs, "attributes")) - impossible(); - - close_output_pbs(&r_trans_pbs); - close_output_pbs(&r_proposal_pbs); -} - -notification_t -parse_ipsec_sa_body( - pb_stream *sa_pbs, /* body of input SA Payload */ - const struct isakmp_sa *sa, /* header of input SA Payload */ - pb_stream *r_sa_pbs, /* if non-NULL, where to emit body of winning SA */ - bool selection, /* if this SA is a selection, only one transform may appear */ - struct state *st) /* current state object */ -{ - const connection_t *c = st->st_connection; - u_int32_t ipsecdoisit; - pb_stream next_proposal_pbs; - - struct isakmp_proposal next_proposal; - ipsec_spi_t next_spi; - - bool next_full = TRUE; - - /* DOI */ - if (sa->isasa_doi != ISAKMP_DOI_IPSEC) - { - loglog(RC_LOG_SERIOUS, "Unknown or unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi)); - /* XXX Could send notification back */ - return ISAKMP_DOI_NOT_SUPPORTED; - } - - /* Situation */ - if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) - return ISAKMP_SITUATION_NOT_SUPPORTED; - - if (ipsecdoisit != SIT_IDENTITY_ONLY) - { - loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)" - , bitnamesof(sit_bit_names, ipsecdoisit)); - /* XXX Could send notification back */ - return ISAKMP_SITUATION_NOT_SUPPORTED; - } - - /* The rules for IPsec SAs are scattered. - * RFC 2408 "ISAKMP" section 4.2 gives some info. - * There may be multiple proposals. Those with identical proposal - * numbers must be considered as conjuncts. Those with different - * numbers are disjuncts. - * Each proposal may have several transforms, each considered - * an alternative. - * Each transform may have several attributes, all applying. - * - * To handle the way proposals are combined, we need to do a - * look-ahead. - */ - - if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs)) - return ISAKMP_BAD_PROPOSAL_SYNTAX; - - /* for each conjunction of proposals... */ - while (next_full) - { - int propno = next_proposal.isap_proposal; - pb_stream ah_prop_pbs, esp_prop_pbs, ipcomp_prop_pbs; - struct isakmp_proposal ah_proposal = {0, 0, 0, 0, 0, 0, 0}; - struct isakmp_proposal esp_proposal = {0, 0, 0, 0, 0, 0, 0}; - struct isakmp_proposal ipcomp_proposal = {0, 0, 0, 0, 0, 0, 0}; - ipsec_spi_t ah_spi = 0; - ipsec_spi_t esp_spi = 0; - ipsec_spi_t ipcomp_cpi = 0; - bool ah_seen = FALSE; - bool esp_seen = FALSE; - bool ipcomp_seen = FALSE; - bool tunnel_mode = FALSE; - int inner_proto = 0; - u_int16_t well_known_cpi = 0; - - pb_stream ah_trans_pbs, esp_trans_pbs, ipcomp_trans_pbs; - struct isakmp_transform ah_trans, esp_trans, ipcomp_trans; - struct ipsec_trans_attrs ah_attrs, esp_attrs, ipcomp_attrs; - - /* for each proposal in the conjunction */ - do { - - if (next_proposal.isap_protoid == PROTO_IPCOMP) - { - /* IPCOMP CPI */ - if (next_proposal.isap_spisize == IPSEC_DOI_SPI_SIZE) - { - /* This code is to accommodate those peculiar - * implementations that send a CPI in the bottom of an - * SPI-sized field. - * See draft-shacham-ippcp-rfc2393bis-05.txt 4.1 - */ - u_int8_t filler[IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE]; - - if (!in_raw(filler, sizeof(filler) - , &next_proposal_pbs, "CPI filler") - || !all_zero(filler, sizeof(filler))) - return ISAKMP_INVALID_SPI; - } - else if (next_proposal.isap_spisize != IPCOMP_CPI_SIZE) - { - loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper CPI size (%u)" - , next_proposal.isap_spisize); - return ISAKMP_INVALID_SPI; - } - - /* We store CPI in the low order of a network order - * ipsec_spi_t. So we start a couple of bytes in. - */ - zero(&next_spi); - if (!in_raw((u_char *)&next_spi - + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE - , IPCOMP_CPI_SIZE, &next_proposal_pbs, "CPI")) - return ISAKMP_INVALID_SPI; - - /* If sanity ruled, CPIs would have to be such that - * the SAID (the triple (CPI, IPCOM, destination IP)) - * would be unique, just like for SPIs. But there is a - * perversion where CPIs can be well-known and consequently - * the triple is not unique. We hide this fact from - * ourselves by fudging the top 16 bits to make - * the property true internally! - */ - switch (ntohl(next_spi)) - { - case IPCOMP_DEFLATE: - well_known_cpi = ntohl(next_spi); - next_spi = uniquify_his_cpi(next_spi, st); - if (next_spi == 0) - { - loglog(RC_LOG_SERIOUS - , "IPsec Proposal contains well-known CPI that I cannot uniquify"); - return ISAKMP_INVALID_SPI; - } - break; - default: - if (ntohl(next_spi) < IPCOMP_FIRST_NEGOTIATED - || ntohl(next_spi) > IPCOMP_LAST_NEGOTIATED) - { - loglog(RC_LOG_SERIOUS, "IPsec Proposal contains CPI from non-negotiated range (0x%lx)" - , (unsigned long) ntohl(next_spi)); - return ISAKMP_INVALID_SPI; - } - break; - } - } - else - { - /* AH or ESP SPI */ - if (next_proposal.isap_spisize != IPSEC_DOI_SPI_SIZE) - { - loglog(RC_LOG_SERIOUS, "IPsec Proposal with improper SPI size (%u)" - , next_proposal.isap_spisize); - return ISAKMP_INVALID_SPI; - } - - if (!in_raw((u_char *)&next_spi, sizeof(next_spi), &next_proposal_pbs, "SPI")) - return ISAKMP_INVALID_SPI; - - /* SPI value 0 is invalid and values 1-255 are reserved to IANA. - * RFC 2402 (ESP) 2.4, RFC 2406 (AH) 2.1 - * IPCOMP??? - */ - if (ntohl(next_spi) < IPSEC_DOI_SPI_MIN) - { - loglog(RC_LOG_SERIOUS, "IPsec Proposal contains invalid SPI (0x%lx)" - , (unsigned long) ntohl(next_spi)); - return ISAKMP_INVALID_SPI; - } - } - - if (next_proposal.isap_notrans == 0) - { - loglog(RC_LOG_SERIOUS, "IPsec Proposal contains no Transforms"); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - - switch (next_proposal.isap_protoid) - { - case PROTO_IPSEC_AH: - if (ah_seen) - { - loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous AH Proposals"); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - ah_seen = TRUE; - ah_prop_pbs = next_proposal_pbs; - ah_proposal = next_proposal; - ah_spi = next_spi; - break; - - case PROTO_IPSEC_ESP: - if (esp_seen) - { - loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous ESP Proposals"); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - esp_seen = TRUE; - esp_prop_pbs = next_proposal_pbs; - esp_proposal = next_proposal; - esp_spi = next_spi; - break; - - case PROTO_IPCOMP: - if (ipcomp_seen) - { - loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous IPCOMP Proposals"); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - ipcomp_seen = TRUE; - ipcomp_prop_pbs = next_proposal_pbs; - ipcomp_proposal = next_proposal; - ipcomp_cpi = next_spi; - break; - - default: - loglog(RC_LOG_SERIOUS, "unexpected Protocol ID (%s) in IPsec Proposal" - , enum_show(&protocol_names, next_proposal.isap_protoid)); - return ISAKMP_INVALID_PROTOCOL_ID; - } - - /* refill next_proposal */ - if (next_proposal.isap_np == ISAKMP_NEXT_NONE) - { - next_full = FALSE; - break; - } - else if (next_proposal.isap_np != ISAKMP_NEXT_P) - { - loglog(RC_LOG_SERIOUS, "unexpected in Proposal: %s" - , enum_show(&payload_names, next_proposal.isap_np)); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - - if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs)) - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } while (next_proposal.isap_proposal == propno); - - /* Now that we have all conjuncts, we should try - * the Cartesian product of eachs tranforms! - * At the moment, we take short-cuts on account of - * our rudimentary hard-wired policy. - * For now, we find an acceptable AH (if any) - * and then an acceptable ESP. The only interaction - * is that the ESP acceptance can know whether there - * was an acceptable AH and hence not require an AUTH. - */ - - if (ah_seen) - { - int previous_transnum = -1; - int tn; - - for (tn = 0; tn != ah_proposal.isap_notrans; tn++) - { - int ok_transid = 0; - bool ok_auth = FALSE; - - if (!parse_ipsec_transform(&ah_trans - , &ah_attrs - , &ah_prop_pbs - , &ah_trans_pbs - , &isakmp_ah_transform_desc - , previous_transnum - , selection - , tn == ah_proposal.isap_notrans - 1 - , FALSE - , st)) - return ISAKMP_BAD_PROPOSAL_SYNTAX; - - previous_transnum = ah_trans.isat_transnum; - - /* we must understand ah_attrs.transid - * COMBINED with ah_attrs.auth. - * See RFC 2407 "IPsec DOI" section 4.4.3 - * The following combinations are legal, - * but we don't implement all of them: - * It seems as if each auth algorithm - * only applies to one ah transid. - * AH_MD5, AUTH_ALGORITHM_HMAC_MD5 - * AH_MD5, AUTH_ALGORITHM_KPDK (unimplemented) - * AH_SHA, AUTH_ALGORITHM_HMAC_SHA1 - * AH_DES, AUTH_ALGORITHM_DES_MAC (unimplemented) - */ - switch (ah_attrs.auth) - { - case AUTH_ALGORITHM_NONE: - loglog(RC_LOG_SERIOUS, "AUTH_ALGORITHM attribute missing in AH Transform"); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - - case AUTH_ALGORITHM_HMAC_MD5: - ok_auth = TRUE; - /* fall through */ - case AUTH_ALGORITHM_KPDK: - ok_transid = AH_MD5; - break; - - case AUTH_ALGORITHM_HMAC_SHA1: - ok_auth = TRUE; - ok_transid = AH_SHA; - break; - - case AUTH_ALGORITHM_DES_MAC: - ok_transid = AH_DES; - break; - } - if (ah_attrs.transid != ok_transid) - { - loglog(RC_LOG_SERIOUS, "%s attribute inappropriate in %s Transform" - , enum_name(&auth_alg_names, ah_attrs.auth) - , enum_show(&ah_transform_names, ah_attrs.transid)); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - if (!ok_auth) - { - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("%s attribute unsupported" - " in %s Transform from %s" - , enum_name(&auth_alg_names, ah_attrs.auth) - , enum_show(&ah_transform_names, ah_attrs.transid) - , ip_str(&c->spd.that.host_addr))); - continue; /* try another */ - } - break; /* we seem to be happy */ - } - if (tn == ah_proposal.isap_notrans) - continue; /* we didn't find a nice one */ - ah_attrs.spi = ah_spi; - inner_proto = IPPROTO_AH; - if (ah_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - tunnel_mode = TRUE; - } - - if (esp_seen) - { - int previous_transnum = -1; - int tn; - - for (tn = 0; tn != esp_proposal.isap_notrans; tn++) - { - if (!parse_ipsec_transform(&esp_trans - , &esp_attrs - , &esp_prop_pbs - , &esp_trans_pbs - , &isakmp_esp_transform_desc - , previous_transnum - , selection - , tn == esp_proposal.isap_notrans - 1 - , FALSE - , st)) - return ISAKMP_BAD_PROPOSAL_SYNTAX; - - previous_transnum = esp_trans.isat_transnum; - - /* set default key length for AES encryption */ - if (!esp_attrs.key_len && esp_attrs.transid == ESP_AES) - { - esp_attrs.key_len = 128; /* bits */ - } - - if (!kernel_alg_esp_enc_ok(esp_attrs.transid, esp_attrs.key_len - ,c->alg_info_esp)) - { - switch (esp_attrs.transid) - { - case ESP_3DES: - break; -#ifdef SUPPORT_ESP_NULL /* should be about as secure as AH-only */ - case ESP_NULL: - if (esp_attrs.auth == AUTH_ALGORITHM_NONE) - { - loglog(RC_LOG_SERIOUS, "ESP_NULL requires auth algorithm"); - return BAD_PROPOSAL_SYNTAX; - } - if (st->st_policy & POLICY_ENCRYPT) - { - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("ESP_NULL Transform Proposal from %s" - " does not satisfy POLICY_ENCRYPT" - , ip_str(&c->spd.that.host_addr))); - continue; /* try another */ - } - break; -#endif - default: - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("unsupported ESP Transform %s from %s" - , enum_show(&esp_transform_names, esp_attrs.transid) - , ip_str(&c->spd.that.host_addr))); - continue; /* try another */ - } - } - - if (!kernel_alg_esp_auth_ok(esp_attrs.auth, c->alg_info_esp)) - { - switch (esp_attrs.auth) - { - case AUTH_ALGORITHM_NONE: - if (!ah_seen) - { - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("ESP from %s must either have AUTH or be combined with AH" - , ip_str(&c->spd.that.host_addr))); - continue; /* try another */ - } - break; - case AUTH_ALGORITHM_HMAC_MD5: - case AUTH_ALGORITHM_HMAC_SHA1: - break; - default: - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("unsupported ESP auth alg %s from %s" - , enum_show(&auth_alg_names, esp_attrs.auth) - , ip_str(&c->spd.that.host_addr))); - continue; /* try another */ - } - } - - /* A last check for allowed transforms in alg_info_esp - * (ALG_INFO_F_STRICT flag) - */ - if (!kernel_alg_esp_ok_final(esp_attrs.transid, esp_attrs.key_len - ,esp_attrs.auth, c->alg_info_esp)) - { - continue; - } - - if (ah_seen && ah_attrs.encapsulation != esp_attrs.encapsulation) - { - /* ??? This should be an error, but is it? */ - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("AH and ESP transforms disagree about encapsulation; TUNNEL presumed")); - } - - break; /* we seem to be happy */ - } - if (tn == esp_proposal.isap_notrans) - continue; /* we didn't find a nice one */ - - esp_attrs.spi = esp_spi; - inner_proto = IPPROTO_ESP; - if (esp_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - tunnel_mode = TRUE; - } - else if (st->st_policy & POLICY_ENCRYPT) - { - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("policy for \"%s\" requires encryption but ESP not in Proposal from %s" - , c->name, ip_str(&c->spd.that.host_addr))); - continue; /* we needed encryption, but didn't find ESP */ - } - else if ((st->st_policy & POLICY_AUTHENTICATE) && !ah_seen) - { - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("policy for \"%s\" requires authentication" - " but none in Proposal from %s" - , c->name, ip_str(&c->spd.that.host_addr))); - continue; /* we need authentication, but we found neither ESP nor AH */ - } - - if (ipcomp_seen) - { - int previous_transnum = -1; - int tn; - -#ifdef NEVER /* we think IPcomp is working now */ - /**** FUDGE TO PREVENT UNREQUESTED IPCOMP: - **** NEEDED BECAUSE OUR IPCOMP IS EXPERIMENTAL (UNSTABLE). - ****/ - if (!(st->st_policy & POLICY_COMPRESS)) - { - plog("compression proposed by %s, but policy for \"%s\" forbids it" - , ip_str(&c->spd.that.host_addr), c->name); - continue; /* unwanted compression proposal */ - } -#endif - if (!can_do_IPcomp) - { - plog("compression proposed by %s, but kernel does not support IPCOMP" - , ip_str(&c->spd.that.host_addr)); - continue; - } - - if (well_known_cpi != 0 && !ah_seen && !esp_seen) - { - plog("illegal proposal: bare IPCOMP used with well-known CPI"); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - - for (tn = 0; tn != ipcomp_proposal.isap_notrans; tn++) - { - if (!parse_ipsec_transform(&ipcomp_trans - , &ipcomp_attrs - , &ipcomp_prop_pbs - , &ipcomp_trans_pbs - , &isakmp_ipcomp_transform_desc - , previous_transnum - , selection - , tn == ipcomp_proposal.isap_notrans - 1 - , TRUE - , st)) - return ISAKMP_BAD_PROPOSAL_SYNTAX; - - previous_transnum = ipcomp_trans.isat_transnum; - - if (well_known_cpi != 0 && ipcomp_attrs.transid != well_known_cpi) - { - plog("illegal proposal: IPCOMP well-known CPI disagrees with transform"); - return ISAKMP_BAD_PROPOSAL_SYNTAX; - } - - switch (ipcomp_attrs.transid) - { - case IPCOMP_DEFLATE: /* all we can handle! */ - break; - - default: - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("unsupported IPCOMP Transform %s from %s" - , enum_show(&ipcomp_transformid_names, ipcomp_attrs.transid) - , ip_str(&c->spd.that.host_addr))); - continue; /* try another */ - } - - if (ah_seen && ah_attrs.encapsulation != ipcomp_attrs.encapsulation) - { - /* ??? This should be an error, but is it? */ - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("AH and IPCOMP transforms disagree about encapsulation; TUNNEL presumed")); - } else if (esp_seen && esp_attrs.encapsulation != ipcomp_attrs.encapsulation) - { - /* ??? This should be an error, but is it? */ - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("ESP and IPCOMP transforms disagree about encapsulation; TUNNEL presumed")); - } - - break; /* we seem to be happy */ - } - if (tn == ipcomp_proposal.isap_notrans) - continue; /* we didn't find a nice one */ - ipcomp_attrs.spi = ipcomp_cpi; - inner_proto = IPPROTO_COMP; - if (ipcomp_attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - tunnel_mode = TRUE; - } - - /* Eureka: we liked what we saw -- accept it. */ - - if (r_sa_pbs != NULL) - { - /* emit what we've accepted */ - - /* Situation */ - if (!out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL)) - impossible(); - - /* AH proposal */ - if (ah_seen) - echo_proposal(ah_proposal - , ah_trans - , esp_seen || ipcomp_seen? ISAKMP_NEXT_P : ISAKMP_NEXT_NONE - , r_sa_pbs - , &st->st_ah - , &isakmp_ah_transform_desc - , &ah_trans_pbs - , &st->st_connection->spd - , tunnel_mode && inner_proto == IPPROTO_AH); - - /* ESP proposal */ - if (esp_seen) - echo_proposal(esp_proposal - , esp_trans - , ipcomp_seen? ISAKMP_NEXT_P : ISAKMP_NEXT_NONE - , r_sa_pbs - , &st->st_esp - , &isakmp_esp_transform_desc - , &esp_trans_pbs - , &st->st_connection->spd - , tunnel_mode && inner_proto == IPPROTO_ESP); - - /* IPCOMP proposal */ - if (ipcomp_seen) - echo_proposal(ipcomp_proposal - , ipcomp_trans - , ISAKMP_NEXT_NONE - , r_sa_pbs - , &st->st_ipcomp - , &isakmp_ipcomp_transform_desc - , &ipcomp_trans_pbs - , &st->st_connection->spd - , tunnel_mode && inner_proto == IPPROTO_COMP); - - close_output_pbs(r_sa_pbs); - } - - /* save decoded version of winning SA in state */ - - st->st_ah.present = ah_seen; - if (ah_seen) - st->st_ah.attrs = ah_attrs; - - st->st_esp.present = esp_seen; - if (esp_seen) - st->st_esp.attrs = esp_attrs; - - st->st_ipcomp.present = ipcomp_seen; - if (ipcomp_seen) - st->st_ipcomp.attrs = ipcomp_attrs; - - return ISAKMP_NOTHING_WRONG; - } - - loglog(RC_LOG_SERIOUS, "no acceptable Proposal in IPsec SA"); - return ISAKMP_NO_PROPOSAL_CHOSEN; -} diff --git a/src/pluto/spdb.h b/src/pluto/spdb.h deleted file mode 100644 index 8a0bffbbd..000000000 --- a/src/pluto/spdb.h +++ /dev/null @@ -1,110 +0,0 @@ -/* Security Policy Data Base (such as it is) - * Copyright (C) 1998, 1999 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _SPDB_H -#define _SPDB_H - -#include "packet.h" - -/* database of SA properties */ - -/* Attribute type and value pair. - * Note: only "basic" values are represented so far. - */ -struct db_attr { - u_int16_t type; /* ISAKMP_ATTR_AF_TV is implied; 0 for end */ - u_int16_t val; -}; - -/* transform */ -struct db_trans { - u_int8_t transid; /* Transform-Id */ - struct db_attr *attrs; /* array */ - int attr_cnt; /* number of elements */ -}; - -/* proposal */ -struct db_prop { - u_int8_t protoid; /* Protocol-Id */ - struct db_trans *trans; /* array (disjunction) */ - int trans_cnt; /* number of elements */ - /* SPI size and value isn't part of DB */ -}; - -/* conjunction of proposals */ -struct db_prop_conj { - struct db_prop *props; /* array */ - int prop_cnt; /* number of elements */ -}; - -/* security association */ -struct db_sa { - struct db_prop_conj *prop_conjs; /* array */ - int prop_conj_cnt; /* number of elements */ - /* Hardwired for now; - * DOI: ISAKMP_DOI_IPSEC - * Situation: SIT_IDENTITY_ONLY - */ -}; - -/* The oakley sadb */ -extern struct db_sa oakley_sadb; - -/* The ipsec sadb is subscripted by a bitset with members - * from POLICY_ENCRYPT, POLICY_AUTHENTICATE, POLICY_COMPRESS - */ -extern struct db_sa ipsec_sadb[1 << 3]; - -/* forward declaration */ -struct state; - -extern bool out_sa( - pb_stream *outs, - struct db_sa *sadb, - struct state *st, - bool oakley_mode, - u_int8_t np); - -extern notification_t preparse_isakmp_sa_body( - const struct isakmp_sa *sa, /* header of input SA Payload */ - pb_stream *sa_pbs, /* body of input SA Payload */ - u_int32_t *ipsecdoisit, /* IPsec DOI SIT bitset */ - pb_stream *proposal_pbs, /* body of proposal Payload */ - struct isakmp_proposal *proposal); - -extern notification_t parse_isakmp_policy( - pb_stream *proposal_pbs, /* body of proposal Payload */ - u_int notrans, /* number of transforms */ - lset_t *policy); /* RSA, PSK or XAUTH policy */ - -extern notification_t parse_isakmp_sa_body( - u_int32_t ipsecdoisit, /* IPsec DOI SIT bitset */ - pb_stream *proposal_pbs, /* body of proposal Payload */ - struct isakmp_proposal *proposal, - pb_stream *r_sa_pbs, /* if non-NULL, where to emit winning SA */ - struct state *st, /* current state object */ - bool initiator); /* is caller initiator? */ - -extern notification_t parse_ipsec_sa_body( - pb_stream *sa_pbs, /* body of input SA Payload */ - const struct isakmp_sa *sa, /* header of input SA Payload */ - pb_stream *r_sa_pbs, /* if non-NULL, where to emit winning SA */ - bool selection, /* if this SA is a selection, only one transform can appear */ - struct state *st); /* current state object */ - -extern void backup_pbs(pb_stream *pbs); -extern void restore_pbs(pb_stream *pbs); - -#endif /* _SPDB_H */ - diff --git a/src/pluto/state.c b/src/pluto/state.c deleted file mode 100644 index f5185888e..000000000 --- a/src/pluto/state.c +++ /dev/null @@ -1,952 +0,0 @@ -/* routines for state objects - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <fcntl.h> -#include <sys/queue.h> - -#include <freeswan.h> - -#include <library.h> -#include <crypto/rngs/rng.h> - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "state.h" -#include "kernel.h" -#include "log.h" -#include "packet.h" /* so we can calculate sizeof(struct isakmp_hdr) */ -#include "keys.h" /* for free_public_key */ -#include "timer.h" -#include "whack.h" -#include "demux.h" /* needs packet.h */ -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "crypto.h" - -/* - * Global variables: had to go somewhere, might as well be this file. - */ - -u_int16_t pluto_port = IKE_UDP_PORT; /* Pluto's port */ - -/* - * This file has the functions that handle the - * state hash table and the Message ID list. - */ - -/* Message-IDs - * - * A Message ID is contained in each IKE message header. - * For Phase 1 exchanges (Main and Aggressive), it will be zero. - * For other exchanges, which must be under the protection of an - * ISAKMP SA, the Message ID must be unique within that ISAKMP SA. - * Effectively, this labels the message as belonging to a particular - * exchange. - * BTW, we feel this uniqueness allows rekeying to be somewhat simpler - * than specified by draft-jenkins-ipsec-rekeying-06.txt. - * - * A MessageID is a 32 bit unsigned number. We represent the value - * internally in network order -- they are just blobs to us. - * They are unsigned numbers to make hashing and comparing easy. - * - * The following mechanism is used to allocate message IDs. This - * requires that we keep track of which numbers have already been used - * so that we don't allocate one in use. - */ - -struct msgid_list -{ - msgid_t msgid; /* network order */ - struct msgid_list *next; -}; - -bool reserve_msgid(struct state *isakmp_sa, msgid_t msgid) -{ - struct msgid_list *p; - - passert(msgid != MAINMODE_MSGID); - passert(IS_ISAKMP_ENCRYPTED(isakmp_sa->st_state)); - - for (p = isakmp_sa->st_used_msgids; p != NULL; p = p->next) - if (p->msgid == msgid) - return FALSE; - - p = malloc_thing(struct msgid_list); - p->msgid = msgid; - p->next = isakmp_sa->st_used_msgids; - isakmp_sa->st_used_msgids = p; - return TRUE; -} - -msgid_t generate_msgid(struct state *isakmp_sa) -{ - int timeout = 100; /* only try so hard for unique msgid */ - msgid_t msgid; - rng_t *rng; - - passert(IS_ISAKMP_ENCRYPTED(isakmp_sa->st_state)); - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - - for (;;) - { - rng->get_bytes(rng, sizeof(msgid), (void *) &msgid); - if (msgid != 0 && reserve_msgid(isakmp_sa, msgid)) - { - break; - } - if (--timeout == 0) - { - plog("gave up looking for unique msgid; using 0x%08lx" - , (unsigned long) msgid); - break; - } - } - rng->destroy(rng); - return msgid; -} - - -/* state table functions */ - -#define STATE_TABLE_SIZE 32 - -static struct state *statetable[STATE_TABLE_SIZE]; - -static struct state **state_hash(const u_char *icookie, const u_char *rcookie, - const ip_address *peer) -{ - u_int i = 0, j; - const unsigned char *byte_ptr; - size_t length = addrbytesptr(peer, &byte_ptr); - - DBG(DBG_RAW | DBG_CONTROL, - DBG_dump("ICOOKIE:", icookie, COOKIE_SIZE); - DBG_dump("RCOOKIE:", rcookie, COOKIE_SIZE); - DBG_dump("peer:", byte_ptr, length)); - - /* XXX the following hash is pretty pathetic */ - - for (j = 0; j < COOKIE_SIZE; j++) - i = i * 407 + icookie[j] + rcookie[j]; - - for (j = 0; j < length; j++) - i = i * 613 + byte_ptr[j]; - - i = i % STATE_TABLE_SIZE; - - DBG(DBG_CONTROL, DBG_log("state hash entry %d", i)); - - return &statetable[i]; -} - -/* Get a state object. - * Caller must schedule an event for this object so that it doesn't leak. - * Caller must insert_state(). - */ -struct state *new_state(void) -{ - /* initialized all to zero & NULL */ - static const struct state blank_state = { - .st_serialno = 0, - }; - static so_serial_t next_so = SOS_FIRST; - struct state *st; - - st = clone_thing(blank_state); - st->st_serialno = next_so++; - passert(next_so > SOS_FIRST); /* overflow can't happen! */ - st->st_whack_sock = NULL_FD; - DBG(DBG_CONTROL, DBG_log("creating state object #%lu at %p", - st->st_serialno, (void *) st)); - return st; -} - -/* - * Initialize the state table (and mask*). - */ -void init_states(void) -{ - int i; - - for (i = 0; i < STATE_TABLE_SIZE; i++) - statetable[i] = (struct state *) NULL; -} - -/* Find the state object with this serial number. - * This allows state object references that don't turn into dangerous - * dangling pointers: reference a state by its serial number. - * Returns NULL if there is no such state. - * If this turns out to be a significant CPU hog, it could be - * improved to use a hash table rather than sequential seartch. - */ -struct state *state_with_serialno(so_serial_t sn) -{ - if (sn >= SOS_FIRST) - { - struct state *st; - int i; - - for (i = 0; i < STATE_TABLE_SIZE; i++) - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) - if (st->st_serialno == sn) - return st; - } - return NULL; -} - -/* Insert a state object in the hash table. The object is inserted - * at the beginning of list. - * Needs cookies, connection, and msgid. - */ -void insert_state(struct state *st) -{ - struct state **p = state_hash(st->st_icookie, st->st_rcookie - , &st->st_connection->spd.that.host_addr); - - passert(st->st_hashchain_prev == NULL && st->st_hashchain_next == NULL); - - if (*p != NULL) - { - passert((*p)->st_hashchain_prev == NULL); - (*p)->st_hashchain_prev = st; - } - st->st_hashchain_next = *p; - *p = st; - - /* Ensure that somebody is in charge of killing this state: - * if no event is scheduled for it, schedule one to discard the state. - * If nothing goes wrong, this event will be replaced by - * a more appropriate one. - */ - if (st->st_event == NULL) - event_schedule(EVENT_SO_DISCARD, 0, st); -} - -/* unlink a state object from the hash table, but don't free it - */ -void unhash_state(struct state *st) -{ - /* unlink from forward chain */ - struct state **p = st->st_hashchain_prev == NULL - ? state_hash(st->st_icookie, st->st_rcookie - , &st->st_connection->spd.that.host_addr) - : &st->st_hashchain_prev->st_hashchain_next; - - /* unlink from forward chain */ - passert(*p == st); - *p = st->st_hashchain_next; - - /* unlink from backward chain */ - if (st->st_hashchain_next != NULL) - { - passert(st->st_hashchain_next->st_hashchain_prev == st); - st->st_hashchain_next->st_hashchain_prev = st->st_hashchain_prev; - } - - st->st_hashchain_next = st->st_hashchain_prev = NULL; -} - -/* Free the Whack socket file descriptor. - * This has the side effect of telling Whack that we're done. - */ -void release_whack(struct state *st) -{ - close_any(st->st_whack_sock); -} - -/** - * Delete a state object - */ -void delete_state(struct state *st) -{ - connection_t *const c = st->st_connection; - struct state *old_cur_state = cur_state == st? NULL : cur_state; - - set_cur_state(st); - - /* If DPD is enabled on this state object, clear any pending events */ - if(st->st_dpd_event != NULL) - delete_dpd_event(st); - - /* if there is a suspended state transition, disconnect us */ - if (st->st_suspended_md != NULL) - { - passert(st->st_suspended_md->st == st); - st->st_suspended_md->st = NULL; - } - - /* tell the other side of any IPSEC SAs that are going down */ - if (IS_IPSEC_SA_ESTABLISHED(st->st_state) - || IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - send_delete(st); - - delete_event(st); /* delete any pending timer event */ - - /* Ditch anything pending on ISAKMP SA being established. - * Note: this must be done before the unhash_state to prevent - * flush_pending_by_state inadvertently and prematurely - * deleting our connection. - */ - flush_pending_by_state(st); - - /* effectively, this deletes any ISAKMP SA that this state represents */ - unhash_state(st); - - /* tell kernel to delete any IPSEC SA - * ??? we ought to tell peer to delete IPSEC SAs - */ - if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) - delete_ipsec_sa(st, FALSE); - else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) - delete_ipsec_sa(st, TRUE); - - if (c->newest_ipsec_sa == st->st_serialno) - c->newest_ipsec_sa = SOS_NOBODY; - - if (c->newest_isakmp_sa == st->st_serialno) - c->newest_isakmp_sa = SOS_NOBODY; - - st->st_connection = NULL; /* we might be about to free it */ - cur_state = old_cur_state; /* without st_connection, st isn't complete */ - connection_discard(c); - - release_whack(st); - - /* from here on we are just freeing RAM */ - - { - struct msgid_list *p = st->st_used_msgids; - - while (p != NULL) - { - struct msgid_list *q = p; - p = p->next; - free(q); - } - } - - unreference_key(&st->st_peer_pubkey); - - DESTROY_IF(st->st_dh); - - chunk_clear(&st->st_tpacket); - chunk_clear(&st->st_rpacket); - chunk_clear(&st->st_p1isa); - chunk_clear(&st->st_gi); - chunk_clear(&st->st_gr); - chunk_clear(&st->st_shared); - chunk_clear(&st->st_ni); - chunk_clear(&st->st_nr); - chunk_clear(&st->st_skeyid); - chunk_clear(&st->st_skeyid_d); - chunk_clear(&st->st_skeyid_a); - chunk_clear(&st->st_skeyid_e); - chunk_clear(&st->st_enc_key); - - free(st->st_ah.our_keymat); - free(st->st_ah.peer_keymat); - free(st->st_esp.our_keymat); - free(st->st_esp.peer_keymat); - - free(st); -} - -/** - * Is a connection in use by some state? - */ -bool states_use_connection(connection_t *c) -{ - /* are there any states still using it? */ - struct state *st = NULL; - int i; - - for (i = 0; st == NULL && i < STATE_TABLE_SIZE; i++) - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) - if (st->st_connection == c) - return TRUE; - - return FALSE; -} - -/** - * Delete all states that were created for a given connection. - * if relations == TRUE, then also delete states that share - * the same phase 1 SA. - */ -void delete_states_by_connection(connection_t *c, bool relations) -{ - int pass; - /* this kludge avoids an n^2 algorithm */ - enum connection_kind ck = c->kind; - struct spd_route *sr; - - /* save this connection's isakmp SA, since it will get set to later SOS_NOBODY */ - so_serial_t parent_sa = c->newest_isakmp_sa; - - if (ck == CK_INSTANCE) - c->kind = CK_GOING_AWAY; - - /* We take two passes so that we delete any ISAKMP SAs last. - * This allows Delete Notifications to be sent. - * ?? We could probably double the performance by caching any - * ISAKMP SA states found in the first pass, avoiding a second. - */ - for (pass = 0; pass != 2; pass++) - { - int i; - - /* For each hash chain... */ - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - struct state *st; - - /* For each state in the hash chain... */ - for (st = statetable[i]; st != NULL; ) - { - struct state *this = st; - - st = st->st_hashchain_next; /* before this is deleted */ - - - if ((this->st_connection == c - || (relations && parent_sa != SOS_NOBODY - && this->st_clonedfrom == parent_sa)) - && (pass == 1 || !IS_ISAKMP_SA_ESTABLISHED(this->st_state))) - { - struct state *old_cur_state - = cur_state == this? NULL : cur_state; -#ifdef DEBUG - lset_t old_cur_debugging = cur_debugging; -#endif - - set_cur_state(this); - plog("deleting state (%s)" - , enum_show(&state_names, this->st_state)); - delete_state(this); - cur_state = old_cur_state; -#ifdef DEBUG - cur_debugging = old_cur_debugging; -#endif - } - } - } - } - - sr = &c->spd; - while (sr != NULL) - { - passert(sr->eroute_owner == SOS_NOBODY); - passert(sr->routing != RT_ROUTED_TUNNEL); - sr = sr->next; - } - c->kind = ck; -} - -/** - * Walk through the state table, and delete each state whose phase 1 (IKE) - * peer is among those given. - */ -void delete_states_by_peer(ip_address *peer) -{ - char peerstr[ADDRTOT_BUF]; - int i; - - addrtot(peer, 0, peerstr, sizeof(peerstr)); - - /* For each hash chain... */ - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - struct state *st; - - /* For each state in the hash chain... */ - for (st = statetable[i]; st != NULL; ) - { - struct state *this = st; - struct spd_route *sr; - connection_t *c = this->st_connection; - - st = st->st_hashchain_next; /* before this is deleted */ - - /* ??? Is it not the case that the peer is the same for all spds? */ - for (sr = &c->spd; sr != NULL; sr = sr->next) - { - if (sameaddr(&sr->that.host_addr, peer)) - { - plog("peer %s for connection %s deleting - claimed to have crashed" - , peerstr - , c->name); - delete_states_by_connection(c, TRUE); - if (c->kind == CK_INSTANCE) - delete_connection(c, TRUE); - break; /* can only delete it once */ - } - } - } - } -} - -/* Duplicate a Phase 1 state object, to create a Phase 2 object. - * Caller must schedule an event for this object so that it doesn't leak. - * Caller must insert_state(). - */ -struct state *duplicate_state(struct state *st) -{ - struct state *nst; - - DBG(DBG_CONTROL, DBG_log("duplicating state object #%lu", - st->st_serialno)); - - /* record use of the Phase 1 state */ - st->st_outbound_count++; - st->st_outbound_time = now(); - - nst = new_state(); - - memcpy(nst->st_icookie, st->st_icookie, COOKIE_SIZE); - memcpy(nst->st_rcookie, st->st_rcookie, COOKIE_SIZE); - - nst->st_connection = st->st_connection; - nst->st_doi = st->st_doi; - nst->st_situation = st->st_situation; - nst->st_clonedfrom = st->st_serialno; - nst->st_oakley = st->st_oakley; - nst->st_modecfg = st->st_modecfg; - nst->st_skeyid_d = chunk_clone(st->st_skeyid_d); - nst->st_skeyid_a = chunk_clone(st->st_skeyid_a); - nst->st_skeyid_e = chunk_clone(st->st_skeyid_e); - nst->st_enc_key = chunk_clone(st->st_enc_key); - - return nst; -} - -#if 1 -void for_each_state(void *(f)(struct state *, void *data), void *data) -{ - struct state *st, *ocs = cur_state; - int i; - for (i=0; i<STATE_TABLE_SIZE; i++) { - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) { - set_cur_state(st); - f(st, data); - } - } - cur_state = ocs; -} -#endif - -/** - * Find a state object. - */ -struct state *find_state(const u_char *icookie, const u_char *rcookie, - const ip_address *peer, msgid_t msgid) -{ - struct state *st = *state_hash(icookie, rcookie, peer); - - while (st != (struct state *) NULL) - { - if (sameaddr(peer, &st->st_connection->spd.that.host_addr) - && memeq(icookie, st->st_icookie, COOKIE_SIZE) - && memeq(rcookie, st->st_rcookie, COOKIE_SIZE) - && msgid == st->st_msgid) - { - break; - } - else - { - st = st->st_hashchain_next; - } - } - DBG(DBG_CONTROL, - if (st == NULL) - DBG_log("state object not found"); - else - DBG_log("state object #%lu found, in %s" - , st->st_serialno - , enum_show(&state_names, st->st_state))); - - return st; -} - -/** - * Find the state that sent a packet - * ??? this could be expensive -- it should be rate-limited to avoid DoS - */ -struct state *find_sender(size_t packet_len, u_char *packet) -{ - int i; - struct state *st; - - if (packet_len >= sizeof(struct isakmp_hdr)) - { - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) - { - if (st->st_tpacket.ptr != NULL - && st->st_tpacket.len == packet_len - && memeq(st->st_tpacket.ptr, packet, packet_len)) - { - return st; - } - } - } - } - return NULL; -} - -struct state *find_phase2_state_to_delete(const struct state *p1st, - u_int8_t protoid, ipsec_spi_t spi, - bool *bogus) -{ - struct state *st; - int i; - - *bogus = FALSE; - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) - { - if (IS_IPSEC_SA_ESTABLISHED(st->st_state) - && p1st->st_connection->host_pair == st->st_connection->host_pair - && same_peer_ids(p1st->st_connection, st->st_connection, NULL)) - { - struct ipsec_proto_info *pr = protoid == PROTO_IPSEC_AH - ? &st->st_ah : &st->st_esp; - - if (pr->present) - { - if (pr->attrs.spi == spi) - return st; - if (pr->our_spi == spi) - *bogus = TRUE; - } - } - } - } - return NULL; -} - -/** - * Find newest Phase 1 negotiation state object for suitable for connection c - */ -struct state *find_phase1_state(const connection_t *c, lset_t ok_states) -{ - struct state - *st, - *best = NULL; - int i; - - for (i = 0; i < STATE_TABLE_SIZE; i++) - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) - if (LHAS(ok_states, st->st_state) - && c->host_pair == st->st_connection->host_pair - && same_peer_ids(c, st->st_connection, NULL) - && (best == NULL || best->st_serialno < st->st_serialno)) - best = st; - - return best; -} - -void state_eroute_usage(ip_subnet *ours, ip_subnet *his, unsigned long count, - time_t nw) -{ - struct state *st; - int i; - - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) - { - connection_t *c = st->st_connection; - - /* XXX spd-enum */ - if (IS_IPSEC_SA_ESTABLISHED(st->st_state) - && c->spd.eroute_owner == st->st_serialno - && c->spd.routing == RT_ROUTED_TUNNEL - && samesubnet(&c->spd.this.client, ours) - && samesubnet(&c->spd.that.client, his)) - { - if (st->st_outbound_count != count) - { - st->st_outbound_count = count; - st->st_outbound_time = nw; - } - return; - } - } - } - DBG(DBG_CONTROL, - { - char ourst[SUBNETTOT_BUF]; - char hist[SUBNETTOT_BUF]; - - subnettot(ours, 0, ourst, sizeof(ourst)); - subnettot(his, 0, hist, sizeof(hist)); - DBG_log("unknown tunnel eroute %s -> %s found in scan" - , ourst, hist); - }); -} - -void fmt_state(bool all, struct state *st, time_t n, char *state_buf, - size_t state_buf_len, char *state_buf2, size_t state_buf2_len) -{ - /* what the heck is interesting about a state? */ - const connection_t *c = st->st_connection; - - long delta = st->st_event->ev_time >= n - ? (long)(st->st_event->ev_time - n) - : -(long)(n - st->st_event->ev_time); - - char inst[CONN_INST_BUF]; - const char *np1 = c->newest_isakmp_sa == st->st_serialno - ? "; newest ISAKMP" : ""; - const char *np2 = c->newest_ipsec_sa == st->st_serialno - ? "; newest IPSEC" : ""; - /* XXX spd-enum */ - const char *eo = c->spd.eroute_owner == st->st_serialno - ? "; eroute owner" : ""; - const char *dpd = (all && st->st_dpd && c->dpd_action != DPD_ACTION_NONE) - ? "; DPD active" : ""; - - passert(st->st_event != 0); - - fmt_conn_instance(c, inst); - - snprintf(state_buf, state_buf_len - , "#%lu: \"%s\"%s %s (%s); %N in %lds%s%s%s%s" - , st->st_serialno - , c->name, inst - , enum_name(&state_names, st->st_state) - , state_story[st->st_state] - , timer_event_names, st->st_event->ev_type - , delta - , np1, np2, eo, dpd); - - /* print out SPIs if SAs are established */ - if (state_buf2_len != 0) - state_buf2[0] = '\0'; /* default to empty */ - if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - - bool tunnel; - char buf[SATOT_BUF*6 + 2*20 + 1]; - const char *p_end = buf + sizeof(buf); - char *p = buf; - -# define add_said(adst, aspi, aproto) { \ - ip_said s; \ - \ - initsaid(adst, aspi, aproto, &s); \ - if (p < p_end - 1) \ - { \ - *p++ = ' '; \ - p += satot(&s, 0, p, p_end - p) - 1; \ - } \ - } - -# define add_sa_info(st, inbound) { \ - u_int bytes; \ - time_t use_time; \ - \ - if (get_sa_info(st, inbound, &bytes, &use_time)) \ - { \ - p += snprintf(p, p_end - p, " (%'u bytes", bytes); \ - if (bytes > 0 && use_time != UNDEFINED_TIME) \ - p += snprintf(p, p_end - p, ", %ds ago", (int)(now - use_time)); \ - p += snprintf(p, p_end - p, ")"); \ - } \ - } - - *p = '\0'; - if (st->st_ah.present) - { - add_said(&c->spd.that.host_addr, st->st_ah.attrs.spi, SA_AH); - add_said(&c->spd.this.host_addr, st->st_ah.our_spi, SA_AH); - } - if (st->st_esp.present) - { - time_t now = time_monotonic(NULL); - - add_said(&c->spd.that.host_addr, st->st_esp.attrs.spi, SA_ESP); - add_sa_info(st, FALSE); - add_said(&c->spd.this.host_addr, st->st_esp.our_spi, SA_ESP); - add_sa_info(st, TRUE); - } - if (st->st_ipcomp.present) - { - add_said(&c->spd.that.host_addr, st->st_ipcomp.attrs.spi, SA_COMP); - add_said(&c->spd.this.host_addr, st->st_ipcomp.our_spi, SA_COMP); - } - tunnel = st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL - || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL - || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; - p += snprintf(p, p_end - p, "; %s", tunnel? "tunnel":"transport"); - - snprintf(state_buf2, state_buf2_len - , "#%lu: \"%s\"%s%s" - , st->st_serialno - , c->name, inst - , buf); - -# undef add_said -# undef add_sa_info - } -} - -/* - * sorting logic is: - * - * name - * type - * instance# - * isakmp_sa (XXX probably wrong) - * - */ -static int state_compare(const void *a, const void *b) -{ - const struct state *sap = *(const struct state *const *)a; - connection_t *ca = sap->st_connection; - const struct state *sbp = *(const struct state *const *)b; - connection_t *cb = sbp->st_connection; - - /* DBG_log("comparing %s to %s", ca->name, cb->name); */ - - return connection_compare(ca, cb); -} - -void show_states_status(bool all, const char *name) -{ - time_t n = now(); - int i; - char state_buf[LOG_WIDTH]; - char state_buf2[LOG_WIDTH]; - int count; - struct state **array; - - /* make count of states */ - count = 0; - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - struct state *st; - - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) - { - if (name == NULL || streq(name, st->st_connection->name)) - count++; - } - } - - /* build the array */ - array = malloc(sizeof(struct state *)*count); - count = 0; - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - struct state *st; - - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) - { - if (name == NULL || streq(name, st->st_connection->name)) - array[count++]=st; - } - } - - /* sort it! */ - qsort(array, count, sizeof(struct state *), state_compare); - - /* now print sorted results */ - for (i = 0; i < count; i++) - { - struct state *st; - - st = array[i]; - - fmt_state(all, st, n - , state_buf, sizeof(state_buf) - , state_buf2, sizeof(state_buf2)); - whack_log(RC_COMMENT, state_buf); - if (state_buf2[0] != '\0') - whack_log(RC_COMMENT, state_buf2); - - /* show any associated pending Phase 2s */ - if (IS_PHASE1(st->st_state)) - show_pending_phase2(st->st_connection->host_pair, st); - } - if (count > 0) - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ - - /* free the array */ - free(array); -} - -/* Muck with high-order 16 bits of this SPI in order to make - * the corresponding SAID unique. - * Its low-order 16 bits hold a well-known IPCOMP CPI. - * Oh, and remember that SPIs are stored in network order. - * Kludge!!! So I name it with the non-English word "uniquify". - * If we can't find one easily, return 0 (a bad SPI, - * no matter what order) indicating failure. - */ -ipsec_spi_t uniquify_his_cpi(ipsec_spi_t cpi, struct state *st) -{ - int tries = 0; - int i; - rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - -startover: - - /* network order makes first two bytes our target */ - rng->get_bytes(rng, 2, (u_char *)&cpi); - - /* Make sure that the result is unique. - * Hard work. If there is no unique value, we'll loop forever! - */ - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - struct state *s; - - for (s = statetable[i]; s != NULL; s = s->st_hashchain_next) - { - if (s->st_ipcomp.present - && sameaddr(&s->st_connection->spd.that.host_addr - , &st->st_connection->spd.that.host_addr) - && cpi == s->st_ipcomp.attrs.spi) - { - if (++tries == 20) - { - rng->destroy(rng); - return 0; /* FAILURE */ - } - goto startover; - } - } - } - rng->destroy(rng); - return cpi; -} - -/* - * Local Variables: - * c-basic-offset:4 - * End: - */ diff --git a/src/pluto/state.h b/src/pluto/state.h deleted file mode 100644 index a307d9f69..000000000 --- a/src/pluto/state.h +++ /dev/null @@ -1,274 +0,0 @@ -/* state and event objects - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _STATE_H -#define _STATE_H - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <time.h> - -#include <crypto/diffie_hellman.h> - -#include "defs.h" -#include "connections.h" - -/* Message ID mechanism. - * - * A Message ID is contained in each IKE message header. - * For Phase 1 exchanges (Main and Aggressive), it will be zero. - * For other exchanges, which must be under the protection of an - * ISAKMP SA, the Message ID must be unique within that ISAKMP SA. - * Effectively, this labels the message as belonging to a particular - * exchange. - * - * RFC2408 "ISAKMP" 3.1 "ISAKMP Header Format" (near end) states that - * the Message ID must be unique. We interpret this to be "unique within - * one ISAKMP SA". - * - * BTW, we feel this uniqueness allows rekeying to be somewhat simpler - * than specified by draft-jenkins-ipsec-rekeying-06.txt. - */ - -typedef u_int32_t msgid_t; /* Network order! */ -#define MAINMODE_MSGID ((msgid_t) 0) - -struct state; /* forward declaration of tag */ -extern bool reserve_msgid(struct state *isakmp_sa, msgid_t msgid); -extern msgid_t generate_msgid(struct state *isakmp_sa); - - -/* Oakley (Phase 1 / Main Mode) transform and attributes - * This is a flattened/decoded version of what is represented - * in the Transaction Payload. - * Names are chosen to match corresponding names in state. - */ -struct oakley_trans_attrs { - u_int16_t encrypt; /* Encryption algorithm */ - u_int16_t enckeylen; /* encryption key len (bits) */ - const struct encrypt_desc *encrypter; /* package of encryption routines */ - u_int16_t hash; /* Hash algorithm */ - const struct hash_desc *hasher; /* package of hashing routines */ - u_int16_t auth; /* Authentication method */ - const struct dh_desc *group; /* Diffie-Hellman group */ - time_t life_seconds; /* When this SA expires (seconds) */ - u_int32_t life_kilobytes; /* When this SA is exhausted (kilobytes) */ -#if 0 /* not yet */ - u_int16_t prf; /* Pseudo Random Function */ -#endif -}; - -/* IPsec (Phase 2 / Quick Mode) transform and attributes - * This is a flattened/decoded version of what is represented - * by a Transaction Payload. There may be one for AH, one - * for ESP, and a funny one for IPCOMP. - */ -struct ipsec_trans_attrs { - u_int8_t transid; /* transform id */ - ipsec_spi_t spi; /* his SPI */ - time_t life_seconds; /* When this SA expires */ - u_int32_t life_kilobytes; /* When this SA expires */ - u_int16_t encapsulation; - u_int16_t auth; - u_int16_t key_len; - u_int16_t key_rounds; -#if 0 /* not implemented yet */ - u_int16_t cmprs_dict_sz; - u_int32_t cmprs_alg; -#endif -}; - -/* IPsec per protocol state information */ -struct ipsec_proto_info { - bool present; /* was this transform specified? */ - struct ipsec_trans_attrs attrs; - ipsec_spi_t our_spi; - u_int16_t keymat_len; /* same for both */ - u_char *our_keymat; - u_char *peer_keymat; -}; - -/* state object: record the state of a (possibly nascent) SA - * - * Invariants (violated only during short transitions): - * - each state object will be in statetable exactly once. - * - each state object will always have a pending event. - * This prevents leaks. - */ -struct state -{ - so_serial_t st_serialno; /* serial number (for seniority) */ - so_serial_t st_clonedfrom; /* serial number of parent */ - - struct connection *st_connection; /* connection for this SA */ - - int st_whack_sock; /* fd for our Whack TCP socket. - * Single copy: close when freeing struct. - */ - - struct msg_digest *st_suspended_md; /* suspended state-transition */ - - struct oakley_trans_attrs st_oakley; - - struct ipsec_proto_info st_ah; - struct ipsec_proto_info st_esp; - struct ipsec_proto_info st_ipcomp; - ipsec_spi_t st_tunnel_in_spi; /* KLUDGE */ - ipsec_spi_t st_tunnel_out_spi; /* KLUDGE */ - - const struct dh_desc *st_pfs_group; /* group for Phase 2 PFS */ - - u_int32_t st_doi; /* Domain of Interpretation */ - u_int32_t st_situation; - - lset_t st_policy; /* policy for IPsec SA */ - - msgid_t st_msgid; /* MSG-ID from header. Network Order! */ - - /* only for a state representing an ISAKMP SA */ - struct msgid_list *st_used_msgids; /* used-up msgids */ - -/* symmetric stuff */ - - /* initiator stuff */ - chunk_t st_gi; /* Initiator public value */ - u_int8_t st_icookie[COOKIE_SIZE];/* Initiator Cookie */ - chunk_t st_ni; /* Ni nonce */ - - /* responder stuff */ - chunk_t st_gr; /* Responder public value */ - u_int8_t st_rcookie[COOKIE_SIZE];/* Responder Cookie */ - chunk_t st_nr; /* Nr nonce */ - - - /* my stuff */ - - chunk_t st_tpacket; /* Transmitted packet */ - - /* Phase 2 ID payload info about my user */ - u_int8_t st_myuserprotoid; /* IDcx.protoid */ - u_int16_t st_myuserport; - - /* his stuff */ - - chunk_t st_rpacket; /* Received packet */ - - /* Phase 2 ID payload info about peer's user */ - u_int8_t st_peeruserprotoid; /* IDcx.protoid */ - u_int16_t st_peeruserport; - -/* end of symmetric stuff */ - - diffie_hellman_t *st_dh; /* Our local DH secret value */ - chunk_t st_shared; /* Derived shared secret - * Note: during Quick Mode, - * presence indicates PFS - * selected. - */ - - /* In a Phase 1 state, preserve peer's public key after authentication */ - struct pubkey *st_peer_pubkey; - - enum state_kind st_state; /* State of exchange */ - u_int8_t st_retransmit; /* Number of retransmits */ - unsigned long st_try; /* number of times rekeying attempted */ - /* 0 means the only time */ - time_t st_margin; /* life after EVENT_SA_REPLACE */ - unsigned long st_outbound_count; /* traffic through eroute */ - time_t st_outbound_time; /* time of last change to st_outbound_count */ - chunk_t st_p1isa; /* Phase 1 initiator SA (Payload) for HASH */ - chunk_t st_skeyid; /* Key material */ - chunk_t st_skeyid_d; /* KM for non-ISAKMP key derivation */ - chunk_t st_skeyid_a; /* KM for ISAKMP authentication */ - chunk_t st_skeyid_e; /* KM for ISAKMP encryption */ - u_char st_iv[MAX_DIGEST_LEN]; /* IV for encryption */ - u_char st_new_iv[MAX_DIGEST_LEN]; - u_char st_ph1_iv[MAX_DIGEST_LEN]; /* IV at end if phase 1 */ - unsigned int st_iv_len; - unsigned int st_new_iv_len; - unsigned int st_ph1_iv_len; - - chunk_t st_enc_key; /* Oakley Encryption key */ - - struct event *st_event; /* backpointer for certain events */ - struct state *st_hashchain_next; /* Next in list */ - struct state *st_hashchain_prev; /* Previous in list */ - - struct { - bool vars_set; - bool started; - } st_modecfg; - - struct { - int attempt; - bool started; - bool status; - } st_xauth; - - u_int32_t nat_traversal; - ip_address nat_oa; - - /* RFC 3706 Dead Peer Detection */ - bool st_dpd; /* Peer supports DPD */ - time_t st_last_dpd; /* Time of last DPD transmit */ - u_int32_t st_dpd_seqno; /* Next R_U_THERE to send */ - u_int32_t st_dpd_expectseqno; /* Next R_U_THERE_ACK to receive */ - u_int32_t st_dpd_peerseqno; /* global variables */ - struct event *st_dpd_event; /* backpointer for DPD events */ - - u_int32_t st_seen_vendorid; /* Bit field about recognized Vendor ID */ -}; - -/* global variables */ - -extern u_int16_t pluto_port; /* Pluto's port */ - -extern bool states_use_connection(struct connection *c); - -/* state functions */ - -extern struct state *new_state(void); -extern void init_states(void); -extern void insert_state(struct state *st); -extern void unhash_state(struct state *st); -extern void release_whack(struct state *st); -extern void state_eroute_usage(ip_subnet *ours, ip_subnet *his - , unsigned long count, time_t nw); -extern void delete_state(struct state *st); -extern void delete_states_by_connection(struct connection *c, bool relations); - -extern struct state - *duplicate_state(struct state *st), - *find_state(const u_char *icookie - , const u_char *rcookie - , const ip_address *peer - , msgid_t msgid), - *state_with_serialno(so_serial_t sn), - *find_phase2_state_to_delete(const struct state *p1st, u_int8_t protoid - , ipsec_spi_t spi, bool *bogus), - *find_phase1_state(const struct connection *c, lset_t ok_states), - *find_sender(size_t packet_len, u_char *packet); - -extern void show_states_status(bool all, const char *name); -extern void for_each_state(void *(f)(struct state *, void *data), void *data); -extern ipsec_spi_t uniquify_his_cpi(ipsec_spi_t cpi, struct state *st); -extern void fmt_state(bool all, struct state *st, time_t n - , char *state_buf, size_t state_buf_len - , char *state_buf2, size_t state_buf_len2); -extern void delete_states_by_peer(ip_address *peer); - -#endif /* _STATE_H */ diff --git a/src/pluto/timer.c b/src/pluto/timer.c deleted file mode 100644 index 1d34d2c54..000000000 --- a/src/pluto/timer.c +++ /dev/null @@ -1,551 +0,0 @@ -/* timer event handling - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <time.h> -#include <unistd.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <sys/queue.h> - -#include <freeswan.h> - -#include <library.h> -#include <crypto/rngs/rng.h> - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "state.h" -#include "demux.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "kernel.h" -#include "server.h" -#include "log.h" -#include "timer.h" -#include "whack.h" -#include "nat_traversal.h" - -/** - * monotonic version of time(3) - */ -time_t now(void) -{ - return time_monotonic(NULL); -} - -/* This file has the event handling routines. Events are - * kept as a linked list of event structures. These structures - * have information like event type, expiration time and a pointer - * to event specific data (for example, to a state structure). - */ - -static struct event *evlist = (struct event *) NULL; - -/** - * This routine places an event in the event list. - */ -void event_schedule(enum event_type type, time_t tm, struct state *st) -{ - struct event *ev = malloc_thing(struct event); - - ev->ev_type = type; - ev->ev_time = tm + now(); - ev->ev_state = st; - - /* If the event is associated with a state, put a backpointer to the - * event in the state object, so we can find and delete the event - * if we need to (for example, if we receive a reply). - */ - if (st != NULL) - { - if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT) - { - passert(st->st_dpd_event == NULL); - st->st_dpd_event = ev; - } - else - { - passert(st->st_event == NULL); - st->st_event = ev; - } - } - - DBG(DBG_CONTROL, - if (st == NULL) - DBG_log("inserting event %N, timeout in %lu seconds" - , timer_event_names, type, (unsigned long)tm); - else - DBG_log("inserting event %N, timeout in %lu seconds for #%lu" - , timer_event_names, type, (unsigned long)tm - , ev->ev_state->st_serialno)); - - if (evlist == (struct event *) NULL - || evlist->ev_time >= ev->ev_time) - { - ev->ev_next = evlist; - evlist = ev; - } - else - { - struct event *evt; - - for (evt = evlist; evt->ev_next != NULL; evt = evt->ev_next) - if (evt->ev_next->ev_time >= ev->ev_time) - break; - -#ifdef NEVER /* this seems to be overkill */ - DBG(DBG_CONTROL, - if (evt->ev_state == NULL) - DBG_log("event added after event %N" - , timer_event_names, evt->ev_type); - else - DBG_log("event added after event %N for #%lu" - , timer_event_names, evt->ev_type, - , evt->ev_state->st_serialno)); -#endif /* NEVER */ - - ev->ev_next = evt->ev_next; - evt->ev_next = ev; - } -} - -/** - * Generate the secret value for responder cookies, and - * schedule an event for refresh. - */ -bool init_secret(void) -{ - rng_t *rng; - - rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - - if (rng == NULL) - { - plog("secret initialization failed, no RNG supported"); - return FALSE; - } - rng->get_bytes(rng, sizeof(secret_of_the_day), secret_of_the_day); - rng->destroy(rng); - event_schedule(EVENT_REINIT_SECRET, EVENT_REINIT_SECRET_DELAY, NULL); - return true; -} - -/** - * Handle the first event on the list. - */ -void handle_timer_event(void) -{ - time_t tm; - struct event *ev = evlist; - int type; - struct state *st; - connection_t *c = NULL; - ip_address peer; - - if (ev == (struct event *) NULL) /* Just paranoid */ - { - DBG(DBG_CONTROL, DBG_log("empty event list, yet we're called")); - return; - } - - type = ev->ev_type; - st = ev->ev_state; - - tm = now(); - - if (tm < ev->ev_time) - { - DBG(DBG_CONTROL, DBG_log("called while no event expired (%lu/%lu, %N)" - , (unsigned long)tm, (unsigned long)ev->ev_time - , timer_event_names, type)); - - /* This will happen if the most close-to-expire event was - * a retransmission or cleanup, and we received a packet - * at the same time as the event expired. Due to the processing - * order in call_server(), the packet processing will happen first, - * and the event will be removed. - */ - return; - } - - evlist = evlist->ev_next; /* Ok, we'll handle this event */ - - DBG(DBG_CONTROL, - if (evlist != (struct event *) NULL) - DBG_log("event after this is %N in %ld seconds" - , timer_event_names, evlist->ev_type - , (long) (evlist->ev_time - tm))); - - /* for state-associated events, pick up the state pointer - * and remove the backpointer from the state object. - * We'll eventually either schedule a new event, or delete the state. - */ - passert(GLOBALS_ARE_RESET()); - if (st != NULL) - { - c = st->st_connection; - if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT) - { - passert(st->st_dpd_event == ev); - st->st_dpd_event = NULL; - } - else - { - passert(st->st_event == ev); - st->st_event = NULL; - } - peer = c->spd.that.host_addr; - set_cur_state(st); - } - - switch (type) - { - case EVENT_REINIT_SECRET: - passert(st == NULL); - DBG(DBG_CONTROL, DBG_log("event EVENT_REINIT_SECRET handled")); - init_secret(); - break; - - case EVENT_LOG_DAILY: - daily_log_event(); - break; - - case EVENT_RETRANSMIT: - /* Time to retransmit, or give up. - * - * Generally, we'll only try to send the message - * MAXIMUM_RETRANSMISSIONS times. Each time we double - * our patience. - * - * As a special case, if this is the first initiating message - * of a Main Mode exchange, and we have been directed to try - * forever, we'll extend the number of retransmissions to - * MAXIMUM_RETRANSMISSIONS_INITIAL times, with all these - * extended attempts having the same patience. The intention - * is to reduce the bother when nobody is home. - */ - { - time_t delay = 0; - - DBG(DBG_CONTROL, DBG_log( - "handling event EVENT_RETRANSMIT for %s \"%s\" #%lu" - , ip_str(&peer), c->name, st->st_serialno)); - - if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS) - delay = EVENT_RETRANSMIT_DELAY_0 << (st->st_retransmit + 1); - else if (st->st_state == STATE_MAIN_I1 - && c->sa_keying_tries == 0 - && st->st_retransmit < MAXIMUM_RETRANSMISSIONS_INITIAL) - delay = EVENT_RETRANSMIT_DELAY_0 << MAXIMUM_RETRANSMISSIONS; - - if (delay != 0) - { - st->st_retransmit++; - whack_log(RC_RETRANSMISSION - , "%s: retransmission; will wait %lus for response" - , enum_name(&state_names, st->st_state) - , (unsigned long)delay); - send_packet(st, "EVENT_RETRANSMIT"); - event_schedule(EVENT_RETRANSMIT, delay, st); - } - else - { - /* check if we've tried rekeying enough times. - * st->st_try == 0 means that this should be the only try. - * c->sa_keying_tries == 0 means that there is no limit. - */ - unsigned long try = st->st_try; - unsigned long try_limit = c->sa_keying_tries; - const char *details = ""; - - switch (st->st_state) - { - case STATE_MAIN_I3: - details = ". Possible authentication failure:" - " no acceptable response to our" - " first encrypted message"; - break; - case STATE_MAIN_I1: - details = ". No response (or no acceptable response) to our" - " first IKE message"; - break; - case STATE_QUICK_I1: - if (c->newest_ipsec_sa == SOS_NOBODY) - details = ". No acceptable response to our" - " first Quick Mode message:" - " perhaps peer likes no proposal"; - break; - default: - break; - } - loglog(RC_NORETRANSMISSION - , "max number of retransmissions (%d) reached %s%s" - , st->st_retransmit - , enum_show(&state_names, st->st_state), details); - if (try != 0 && try != try_limit) - { - /* A lot like EVENT_SA_REPLACE, but over again. - * Since we know that st cannot be in use, - * we can delete it right away. - */ - char story[80]; /* arbitrary limit */ - - try++; - snprintf(story, sizeof(story), try_limit == 0 - ? "starting keying attempt %ld of an unlimited number" - : "starting keying attempt %ld of at most %ld" - , try, try_limit); - - if (st->st_whack_sock != NULL_FD) - { - /* Release whack because the observer will get bored. */ - loglog(RC_COMMENT, "%s, but releasing whack" - , story); - release_pending_whacks(st, story); - } - else - { - /* no whack: just log to syslog */ - plog("%s", story); - } - ipsecdoi_replace(st, try); - } - delete_state(st); - } - } - break; - - case EVENT_SA_REPLACE: - case EVENT_SA_REPLACE_IF_USED: - { - so_serial_t newest = IS_PHASE1(st->st_state) - ? c->newest_isakmp_sa : c->newest_ipsec_sa; - - if (newest != st->st_serialno - && newest != SOS_NOBODY) - { - /* not very interesting: no need to replace */ - DBG(DBG_LIFECYCLE - , plog("not replacing stale %s SA: #%lu will do" - , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec" - , newest)); - } - else if (type == EVENT_SA_REPLACE_IF_USED - && st->st_outbound_time <= tm - c->sa_rekey_margin) - { - /* we observed no recent use: no need to replace - * - * The sampling effects mean that st_outbound_time - * could be up to SHUNT_SCAN_INTERVAL more recent - * than actual traffic because the sampler looks at change - * over that interval. - * st_outbound_time could also not yet reflect traffic - * in the last SHUNT_SCAN_INTERVAL. - * We expect that SHUNT_SCAN_INTERVAL is smaller than - * c->sa_rekey_margin so that the effects of this will - * be unimportant. - * This is just an optimization: correctness is not - * at stake. - * - * Note: we are abusing the DBG mechanism to control - * normal log output. - */ - DBG(DBG_LIFECYCLE - , plog("not replacing stale %s SA: inactive for %lus" - , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec" - , (unsigned long)(tm - st->st_outbound_time))); - } - else - { - DBG(DBG_LIFECYCLE - , plog("replacing stale %s SA" - , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec")); - ipsecdoi_replace(st, 1); - } - delete_dpd_event(st); - event_schedule(EVENT_SA_EXPIRE, st->st_margin, st); - } - break; - - case EVENT_SA_EXPIRE: - { - const char *satype; - so_serial_t latest; - - if (IS_PHASE1(st->st_state)) - { - satype = "ISAKMP"; - latest = c->newest_isakmp_sa; - } - else - { - satype = "IPsec"; - latest = c->newest_ipsec_sa; - } - - if (st->st_serialno != latest) - { - /* not very interesting: already superseded */ - DBG(DBG_LIFECYCLE - , plog("%s SA expired (superseded by #%lu)" - , satype, latest)); - } - else - { - plog("%s SA expired (%s)", satype - , (c->policy & POLICY_DONT_REKEY) - ? "--dontrekey" - : "LATEST!" - ); - } - } - /* FALLTHROUGH */ - case EVENT_SO_DISCARD: - /* Delete this state object. It must be in the hash table. */ - delete_state(st); - break; - - case EVENT_DPD: - dpd_outI(st); - break; - case EVENT_DPD_TIMEOUT: - dpd_timeout(st); - break; - case EVENT_NAT_T_KEEPALIVE: - nat_traversal_ka_event(); - break; - default: - loglog(RC_LOG_SERIOUS, "INTERNAL ERROR: ignoring unknown expiring event %N" - , timer_event_names, type); - } - - free(ev); - reset_cur_state(); -} - -/** - * Return the time until the next event in the queue - * expires (never negative), or -1 if no jobs in queue. - */ -long next_event(void) -{ - time_t tm; - - if (evlist == (struct event *) NULL) - return -1; - - tm = now(); - - DBG(DBG_CONTROL, - if (evlist->ev_state == NULL) - DBG_log("next event %N in %ld seconds" - , timer_event_names, evlist->ev_type - , (long)evlist->ev_time - (long)tm); - else - DBG_log("next event %N in %ld seconds for #%lu" - , timer_event_names, evlist->ev_type - , (long)evlist->ev_time - (long)tm - , evlist->ev_state->st_serialno)); - - if (evlist->ev_time - tm <= 0) - return 0; - else - return evlist->ev_time - tm; -} - -/** - * Delete an event. - */ -void delete_event(struct state *st) -{ - if (st->st_event != (struct event *) NULL) - { - struct event **ev; - - for (ev = &evlist; ; ev = &(*ev)->ev_next) - { - if (*ev == NULL) - { - DBG(DBG_CONTROL, DBG_log("event %N to be deleted not found", - timer_event_names, st->st_event->ev_type)); - break; - } - if ((*ev) == st->st_event) - { - *ev = (*ev)->ev_next; - - if (st->st_event->ev_type == EVENT_RETRANSMIT) - { - st->st_retransmit = 0; - } - free(st->st_event); - st->st_event = (struct event *) NULL; - - break; - } - } - } -} - -/** - * Delete a DPD event. - */ -void delete_dpd_event(struct state *st) -{ - if (st->st_dpd_event != (struct event *) NULL) - { - struct event **ev; - - for (ev = &evlist; ; ev = &(*ev)->ev_next) - { - if (*ev == NULL) - { - DBG(DBG_CONTROL, DBG_log("event %N to be deleted not found", - timer_event_names, st->st_dpd_event->ev_type)); - break; - } - if ((*ev) == st->st_dpd_event) - { - *ev = (*ev)->ev_next; - free(st->st_dpd_event); - st->st_dpd_event = (struct event *) NULL; - break; - } - } - } -} - -/** - * Free remaining events - */ -void free_events(void) -{ - struct event *ev_tmp, *ev; - - ev = evlist; - evlist = NULL; - - while (ev) - { - ev_tmp = ev; - ev = ev->ev_next; - free(ev_tmp); - } -} - diff --git a/src/pluto/timer.h b/src/pluto/timer.h deleted file mode 100644 index c8e9b727c..000000000 --- a/src/pluto/timer.h +++ /dev/null @@ -1,34 +0,0 @@ -/* timing machinery - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -extern time_t now(void); /* careful version of time(2) */ - -struct state; /* forward declaration */ - -struct event -{ - time_t ev_time; - int ev_type; /* Event type */ - struct state *ev_state; /* Pointer to relevant state (if any) */ - struct event *ev_next; /* Pointer to next event */ -}; - -extern void event_schedule(enum event_type type, time_t tm, struct state *st); -extern void handle_timer_event(void); -extern long next_event(void); -extern void delete_event(struct state *st); -extern void delete_dpd_event(struct state *st); -extern void daily_log_event(void); -extern void free_events(void); -extern bool init_secret(void); diff --git a/src/pluto/vendor.c b/src/pluto/vendor.c deleted file mode 100644 index 6cc599d8d..000000000 --- a/src/pluto/vendor.c +++ /dev/null @@ -1,511 +0,0 @@ -/* ISAKMP VendorID - * Copyright (C) 2002-2005 Mathieu Lafon - Arkoon Network Security - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <sys/queue.h> -#include <freeswan.h> - -#include <library.h> -#include <crypto/hashers/hasher.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "connections.h" -#include "packet.h" -#include "demux.h" -#include "whack.h" -#include "vendor.h" -#include "kernel.h" -#include "nat_traversal.h" - -/** - * Unknown/Special VID: - * - * SafeNet SoftRemote 8.0.0: - * 47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310382e302e3020284275696c6420313029000000 - * >> 382e302e3020284275696c6420313029 = '8.0.0 (Build 10)' - * da8e937880010000 - * - * SafeNet SoftRemote 9.0.1 - * 47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310392e302e3120284275696c6420313229000000 - * >> 392e302e3120284275696c6420313229 = '9.0.1 (Build 12)' - * da8e937880010000 - * - * Netscreen: - * d6b45f82f24bacb288af59a978830ab7 - * cf49908791073fb46439790fdeb6aeed981101ab0000000500000300 - * - * Cisco: - * 1f07f70eaa6514d3b0fa96542a500300 (VPN 3000 version 3.0.0) - * 1f07f70eaa6514d3b0fa96542a500301 (VPN 3000 version 3.0.1) - * 1f07f70eaa6514d3b0fa96542a500305 (VPN 3000 version 3.0.5) - * 1f07f70eaa6514d3b0fa96542a500407 (VPN 3000 version 4.0.7) - * (Can you see the pattern?) - * afcad71368a1f1c96b8696fc77570100 (Non-RFC Dead Peer Detection ?) - * c32364b3b4f447eb17c488ab2a480a57 - * 6d761ddc26aceca1b0ed11fabbb860c4 - * 5946c258f99a1a57b03eb9d1759e0f24 (From a Cisco VPN 3k) - * ebbc5b00141d0c895e11bd395902d690 (From a Cisco VPN 3k) - * - * Microsoft L2TP (???): - * 47bbe7c993f1fc13b4e6d0db565c68e5010201010201010310382e312e3020284275696c6420313029000000 - * >> 382e312e3020284275696c6420313029 = '8.1.0 (Build 10)' - * 3025dbd21062b9e53dc441c6aab5293600000000 - * da8e937880010000 - * - * 3COM-superstack - * da8e937880010000 - * 404bf439522ca3f6 - * - - * If someone know what they mean, mail me. - */ - -#define MAX_LOG_VID_LEN 32 - -#define VID_KEEP 0x0000 -#define VID_MD5HASH 0x0001 -#define VID_STRING 0x0002 -#define VID_FSWAN_HASH 0x0004 - -#define VID_SUBSTRING_DUMPHEXA 0x0100 -#define VID_SUBSTRING_DUMPASCII 0x0200 -#define VID_SUBSTRING_MATCH 0x0400 -#define VID_SUBSTRING (VID_SUBSTRING_DUMPHEXA | VID_SUBSTRING_DUMPASCII | VID_SUBSTRING_MATCH) - -struct vid_struct { - enum known_vendorid id; - unsigned short flags; - const char *data; - const char *descr; - chunk_t vid; -}; - -#define DEC_MD5_VID_D(id,str,descr) \ - { VID_##id, VID_MD5HASH, str, descr, { NULL, 0 } }, -#define DEC_MD5_VID(id,str) \ - { VID_##id, VID_MD5HASH, str, NULL, { NULL, 0 } }, - -static struct vid_struct _vid_tab[] = { - - /* Implementation names */ - - { VID_OPENPGP, VID_STRING, "OpenPGP10171", "OpenPGP", { NULL, 0 } }, - - DEC_MD5_VID(KAME_RACOON, "KAME/racoon") - - { VID_MS_NT5, VID_MD5HASH | VID_SUBSTRING_DUMPHEXA, - "MS NT5 ISAKMPOAKLEY", NULL, { NULL, 0 } }, - - DEC_MD5_VID(SSH_SENTINEL, "SSH Sentinel") - DEC_MD5_VID(SSH_SENTINEL_1_1, "SSH Sentinel 1.1") - DEC_MD5_VID(SSH_SENTINEL_1_2, "SSH Sentinel 1.2") - DEC_MD5_VID(SSH_SENTINEL_1_3, "SSH Sentinel 1.3") - DEC_MD5_VID(SSH_SENTINEL_1_4, "SSH Sentinel 1.4") - DEC_MD5_VID(SSH_SENTINEL_1_4_1, "SSH Sentinel 1.4.1") - - /* These ones come from SSH vendors.txt */ - DEC_MD5_VID(SSH_IPSEC_1_1_0, - "Ssh Communications Security IPSEC Express version 1.1.0") - DEC_MD5_VID(SSH_IPSEC_1_1_1, - "Ssh Communications Security IPSEC Express version 1.1.1") - DEC_MD5_VID(SSH_IPSEC_1_1_2, - "Ssh Communications Security IPSEC Express version 1.1.2") - DEC_MD5_VID(SSH_IPSEC_1_2_1, - "Ssh Communications Security IPSEC Express version 1.2.1") - DEC_MD5_VID(SSH_IPSEC_1_2_2, - "Ssh Communications Security IPSEC Express version 1.2.2") - DEC_MD5_VID(SSH_IPSEC_2_0_0, - "SSH Communications Security IPSEC Express version 2.0.0") - DEC_MD5_VID(SSH_IPSEC_2_1_0, - "SSH Communications Security IPSEC Express version 2.1.0") - DEC_MD5_VID(SSH_IPSEC_2_1_1, - "SSH Communications Security IPSEC Express version 2.1.1") - DEC_MD5_VID(SSH_IPSEC_2_1_2, - "SSH Communications Security IPSEC Express version 2.1.2") - DEC_MD5_VID(SSH_IPSEC_3_0_0, - "SSH Communications Security IPSEC Express version 3.0.0") - DEC_MD5_VID(SSH_IPSEC_3_0_1, - "SSH Communications Security IPSEC Express version 3.0.1") - DEC_MD5_VID(SSH_IPSEC_4_0_0, - "SSH Communications Security IPSEC Express version 4.0.0") - DEC_MD5_VID(SSH_IPSEC_4_0_1, - "SSH Communications Security IPSEC Express version 4.0.1") - DEC_MD5_VID(SSH_IPSEC_4_1_0, - "SSH Communications Security IPSEC Express version 4.1.0") - DEC_MD5_VID(SSH_IPSEC_4_2_0, - "SSH Communications Security IPSEC Express version 4.2.0") - - /* note: md5('CISCO-UNITY') = 12f5f28c457168a9702d9fe274cc02d4 */ - { VID_CISCO_UNITY, VID_KEEP, NULL, "Cisco-Unity", - { "\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00", 16 } }, - - { VID_CISCO3K, VID_KEEP | VID_SUBSTRING_MATCH, NULL, "Cisco VPN 3000 Series" , - { "\x1f\x07\xf7\x0e\xaa\x65\x14\xd3\xb0\xfa\x96\x54\x2a\x50", 14 } }, - - { VID_CISCO_IOS, VID_KEEP | VID_SUBSTRING_MATCH, - NULL, "Cisco IOS Device", { "\x3e\x98\x40\x48", 4 } }, - - /* - * Timestep VID seen: - * - 54494d455354455020312053475720313532302033313520322e303145303133 - * = 'TIMESTEP 1 SGW 1520 315 2.01E013' - */ - { VID_TIMESTEP, VID_STRING | VID_SUBSTRING_DUMPASCII, "TIMESTEP", - NULL, { NULL, 0 } }, - - /* - * Netscreen: - * 4865617274426561745f4e6f74696679386b0100 (HeartBeat_Notify + 386b0100) - */ - { VID_MISC_HEARTBEAT_NOTIFY, VID_STRING | VID_SUBSTRING_DUMPHEXA, - "HeartBeat_Notify", "HeartBeat Notify", { NULL, 0 } }, - /* - * MacOS X - */ - { VID_MACOSX, VID_STRING|VID_SUBSTRING_DUMPHEXA, "Mac OSX 10.x", - "\x4d\xf3\x79\x28\xe9\xfc\x4f\xd1\xb3\x26\x21\x70\xd5\x15\xc6\x62", { NULL, 0 } }, - - /* NCP */ - { VID_NCP_SERVER, VID_KEEP | VID_SUBSTRING_MATCH, NULL, "NCP Server", - { "\xc6\xf5\x7a\xc3\x98\xf4\x93\x20\x81\x45\xb7\x58", 12 } }, - { VID_NCP_CLIENT, VID_KEEP | VID_SUBSTRING_MATCH, NULL, "NCP Client", - { "\xeb\x4c\x1b\x78\x8a\xfd\x4a\x9c\xb7\x73\x0a\x68", 12 } }, - - /* - * Windows Vista (and Windows Server 2008?) - */ - DEC_MD5_VID(VISTA_AUTHIP, "MS-Negotiation Discovery Capable") - DEC_MD5_VID(VISTA_AUTHIP2, "IKE CGA version 1") - DEC_MD5_VID(VISTA_AUTHIP3, "MS-MamieExists") - - /* - * strongSwan - */ - DEC_MD5_VID(STRONGSWAN, "strongSwan") - - DEC_MD5_VID(STRONGSWAN_4_3_5, "strongSwan 4.3.5") - DEC_MD5_VID(STRONGSWAN_4_3_4, "strongSwan 4.3.4") - DEC_MD5_VID(STRONGSWAN_4_3_3, "strongSwan 4.3.3") - DEC_MD5_VID(STRONGSWAN_4_3_2, "strongSwan 4.3.2") - DEC_MD5_VID(STRONGSWAN_4_3_1, "strongSwan 4.3.1") - DEC_MD5_VID(STRONGSWAN_4_3_0, "strongSwan 4.3.0") - DEC_MD5_VID(STRONGSWAN_4_2_17,"strongSwan 4.2.17") - DEC_MD5_VID(STRONGSWAN_4_2_16,"strongSwan 4.2.16") - DEC_MD5_VID(STRONGSWAN_4_2_15,"strongSwan 4.2.15") - DEC_MD5_VID(STRONGSWAN_4_2_14,"strongSwan 4.2.14") - DEC_MD5_VID(STRONGSWAN_4_2_13,"strongSwan 4.2.13") - DEC_MD5_VID(STRONGSWAN_4_2_12,"strongSwan 4.2.12") - DEC_MD5_VID(STRONGSWAN_4_2_11,"strongSwan 4.2.11") - DEC_MD5_VID(STRONGSWAN_4_2_10,"strongSwan 4.2.10") - DEC_MD5_VID(STRONGSWAN_4_2_9, "strongSwan 4.2.9") - DEC_MD5_VID(STRONGSWAN_4_2_8, "strongSwan 4.2.8") - DEC_MD5_VID(STRONGSWAN_4_2_7, "strongSwan 4.2.7") - DEC_MD5_VID(STRONGSWAN_4_2_6, "strongSwan 4.2.6") - DEC_MD5_VID(STRONGSWAN_4_2_5, "strongSwan 4.2.5") - DEC_MD5_VID(STRONGSWAN_4_2_4, "strongSwan 4.2.4") - DEC_MD5_VID(STRONGSWAN_4_2_3, "strongSwan 4.2.3") - DEC_MD5_VID(STRONGSWAN_4_2_2, "strongSwan 4.2.2") - DEC_MD5_VID(STRONGSWAN_4_2_1, "strongSwan 4.2.1") - DEC_MD5_VID(STRONGSWAN_4_2_0, "strongSwan 4.2.0") - DEC_MD5_VID(STRONGSWAN_4_1_11,"strongSwan 4.1.11") - DEC_MD5_VID(STRONGSWAN_4_1_10,"strongSwan 4.1.10") - DEC_MD5_VID(STRONGSWAN_4_1_9, "strongSwan 4.1.9") - DEC_MD5_VID(STRONGSWAN_4_1_8, "strongSwan 4.1.8") - DEC_MD5_VID(STRONGSWAN_4_1_7, "strongSwan 4.1.7") - DEC_MD5_VID(STRONGSWAN_4_1_6, "strongSwan 4.1.6") - DEC_MD5_VID(STRONGSWAN_4_1_5, "strongSwan 4.1.5") - DEC_MD5_VID(STRONGSWAN_4_1_4, "strongSwan 4.1.4") - DEC_MD5_VID(STRONGSWAN_4_1_3, "strongSwan 4.1.3") - DEC_MD5_VID(STRONGSWAN_4_1_2, "strongSwan 4.1.2") - DEC_MD5_VID(STRONGSWAN_4_1_1, "strongSwan 4.1.1") - DEC_MD5_VID(STRONGSWAN_4_1_0, "strongSwan 4.1.0") - - DEC_MD5_VID(STRONGSWAN_2_8_11,"strongSwan 2.8.11") - DEC_MD5_VID(STRONGSWAN_2_8_10,"strongSwan 2.8.10") - DEC_MD5_VID(STRONGSWAN_2_8_9, "strongSwan 2.8.9") - DEC_MD5_VID(STRONGSWAN_2_8_8, "strongSwan 2.8.8") - DEC_MD5_VID(STRONGSWAN_2_8_7, "strongSwan 2.8.7") - DEC_MD5_VID(STRONGSWAN_2_8_6, "strongSwan 2.8.6") - DEC_MD5_VID(STRONGSWAN_2_8_5, "strongSwan 2.8.5") - DEC_MD5_VID(STRONGSWAN_2_8_4, "strongSwan 2.8.4") - DEC_MD5_VID(STRONGSWAN_2_8_3, "strongSwan 2.8.3") - DEC_MD5_VID(STRONGSWAN_2_8_2, "strongSwan 2.8.2") - DEC_MD5_VID(STRONGSWAN_2_8_1, "strongSwan 2.8.1") - DEC_MD5_VID(STRONGSWAN_2_8_0, "strongSwan 2.8.0") - - /* NAT-Traversal */ - - DEC_MD5_VID(NATT_STENBERG_01, "draft-stenberg-ipsec-nat-traversal-01") - DEC_MD5_VID(NATT_STENBERG_02, "draft-stenberg-ipsec-nat-traversal-02") - DEC_MD5_VID(NATT_HUTTUNEN, "ESPThruNAT") - DEC_MD5_VID(NATT_HUTTUNEN_ESPINUDP, "draft-huttunen-ipsec-esp-in-udp-00.txt") - DEC_MD5_VID(NATT_IETF_00, "draft-ietf-ipsec-nat-t-ike-00") - DEC_MD5_VID(NATT_IETF_02, "draft-ietf-ipsec-nat-t-ike-02") - /* hash in draft-ietf-ipsec-nat-t-ike-02 contains '\n'... Accept both */ - DEC_MD5_VID_D(NATT_IETF_02_N, "draft-ietf-ipsec-nat-t-ike-02\n", "draft-ietf-ipsec-nat-t-ike-02_n") - DEC_MD5_VID(NATT_IETF_03, "draft-ietf-ipsec-nat-t-ike-03") - DEC_MD5_VID(NATT_RFC, "RFC 3947") - - /* misc */ - - { VID_MISC_XAUTH, VID_KEEP, NULL, "XAUTH", - { "\x09\x00\x26\x89\xdf\xd6\xb7\x12", 8 } }, - - { VID_MISC_DPD, VID_KEEP, NULL, "Dead Peer Detection", - { "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00", 16 } }, - - DEC_MD5_VID(MISC_FRAGMENTATION, "FRAGMENTATION") - - DEC_MD5_VID(INITIAL_CONTACT, "Vid-Initial-Contact") - - /** - * Cisco VPN 3000 - */ - { VID_MISC_FRAGMENTATION, VID_MD5HASH | VID_SUBSTRING_DUMPHEXA, - "FRAGMENTATION", NULL, { NULL, 0 } }, - - /* -- */ - { 0, 0, NULL, NULL, { NULL, 0 } } - -}; - -static const char _hexdig[] = "0123456789abcdef"; - -static int _vid_struct_init = 0; - -void init_vendorid(void) -{ - hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); - struct vid_struct *vid; - - for (vid = _vid_tab; vid->id; vid++) - { - if (vid->flags & VID_STRING) - { - /** VendorID is a string **/ - vid->vid = chunk_create((u_char *)vid->data, strlen(vid->data)); - vid->vid = chunk_clone(vid->vid); - } - else if (vid->flags & VID_MD5HASH) - { - chunk_t vid_data = { (u_char *)vid->data, strlen(vid->data) }; - - /** VendorID is a string to hash with MD5 **/ - hasher->allocate_hash(hasher, vid_data, &vid->vid); - } - - if (vid->descr == NULL) - { - /** Find something to display **/ - vid->descr = vid->data; - } - } - hasher->destroy(hasher); - _vid_struct_init = 1; -} - -void free_vendorid(void) -{ - struct vid_struct *vid; - - for (vid = _vid_tab; vid->id; vid++) - { - if (vid->flags & (VID_STRING | VID_MD5HASH | VID_FSWAN_HASH)) - { - free(vid->vid.ptr); - } - } -} - -static void handle_known_vendorid (struct msg_digest *md, const char *vidstr, - size_t len, struct vid_struct *vid) -{ - char vid_dump[128]; - bool vid_useful = FALSE; - size_t i, j; - - switch (vid->id) - { - /* Remote side is a strongSwan host */ - case VID_STRONGSWAN: - vid_useful = TRUE; - break; - - /* Remote side supports OpenPGP certificates */ - case VID_OPENPGP: - md->openpgp = TRUE; - vid_useful = TRUE; - break; - - /* Remote side is a Windows 2000+ host */ - case VID_MS_NT5: - md->ms_nt5 = TRUE; - vid_useful = TRUE; - break; - - /* - * Use most recent supported NAT-Traversal method and ignore the - * other ones (implementations will send all supported methods but - * only one will be used) - * - * Note: most recent == higher id in vendor.h - */ - case VID_NATT_IETF_00: - if (!nat_traversal_support_non_ike) - break; - if ((nat_traversal_enabled) && (!md->nat_traversal_vid)) - { - md->nat_traversal_vid = vid->id; - vid_useful = TRUE; - } - break; - case VID_NATT_IETF_02: - case VID_NATT_IETF_02_N: - case VID_NATT_IETF_03: - case VID_NATT_RFC: - if (nat_traversal_support_port_floating - && md->nat_traversal_vid < vid->id) - { - md->nat_traversal_vid = vid->id; - vid_useful = TRUE; - } - break; - - /* Remote side would like to do DPD with us on this connection */ - case VID_MISC_DPD: - md->dpd = TRUE; - vid_useful = TRUE; - break; - case VID_MISC_XAUTH: - vid_useful = TRUE; - break; - default: - break; - } - - if (vid->flags & VID_SUBSTRING_DUMPHEXA) - { - /* Dump description + Hexa */ - memset(vid_dump, 0, sizeof(vid_dump)); - snprintf(vid_dump, sizeof(vid_dump), "%s ", - vid->descr ? vid->descr : ""); - for (i = strlen(vid_dump), j = vid->vid.len; - j < len && i < sizeof(vid_dump) - 2; - i += 2, j++) - { - vid_dump[i] = _hexdig[(vidstr[j] >> 4) & 0xF]; - vid_dump[i+1] = _hexdig[vidstr[j] & 0xF]; - } - } - else if (vid->flags & VID_SUBSTRING_DUMPASCII) - { - /* Dump ASCII content */ - memset(vid_dump, 0, sizeof(vid_dump)); - for (i = 0; i < len && i < sizeof(vid_dump) - 1; i++) - { - vid_dump[i] = (isprint(vidstr[i])) ? vidstr[i] : '.'; - } - } - else - { - /* Dump description (descr) */ - snprintf(vid_dump, sizeof(vid_dump), "%s", - vid->descr ? vid->descr : ""); - } - - loglog(RC_LOG_SERIOUS, "%s Vendor ID payload [%s]", - vid_useful ? "received" : "ignoring", vid_dump); -} - -void handle_vendorid (struct msg_digest *md, const char *vid, size_t len) -{ - struct vid_struct *pvid; - - if (!_vid_struct_init) - init_vendorid(); - - /* - * Find known VendorID in _vid_tab - */ - for (pvid = _vid_tab; pvid->id; pvid++) - { - if (pvid->vid.ptr && vid && pvid->vid.len && len) - { - if (pvid->vid.len == len) - { - if (memeq(pvid->vid.ptr, vid, len)) - { - handle_known_vendorid(md, vid, len, pvid); - return; - } - } - else if ((pvid->vid.len < len) && (pvid->flags & VID_SUBSTRING)) - { - if (memeq(pvid->vid.ptr, vid, pvid->vid.len)) - { - handle_known_vendorid(md, vid, len, pvid); - return; - } - } - } - } - - /* - * Unknown VendorID. Log the beginning. - */ - { - char log_vid[2*MAX_LOG_VID_LEN+1]; - size_t i; - - memset(log_vid, 0, sizeof(log_vid)); - - for (i = 0; i < len && i < MAX_LOG_VID_LEN; i++) - { - log_vid[2*i] = _hexdig[(vid[i] >> 4) & 0xF]; - log_vid[2*i+1] = _hexdig[vid[i] & 0xF]; - } - loglog(RC_LOG_SERIOUS, "ignoring Vendor ID payload [%s%s]", - log_vid, (len>MAX_LOG_VID_LEN) ? "..." : ""); - } -} - -/** - * Add a vendor id payload to the msg - */ -bool out_vendorid (u_int8_t np, pb_stream *outs, enum known_vendorid vid) -{ - struct vid_struct *pvid; - - if (!_vid_struct_init) - init_vendorid(); - - for (pvid = _vid_tab; pvid->id && pvid->id != vid; pvid++); - - if (pvid->id != vid) - return STF_INTERNAL_ERROR; /* not found */ - if (!pvid->vid.ptr) - return STF_INTERNAL_ERROR; /* not initialized */ - - DBG(DBG_EMITTING, - DBG_log("out_vendorid(): sending [%s]", pvid->descr) - ) - return out_generic_raw(np, &isakmp_vendor_id_desc, outs, - pvid->vid.ptr, pvid->vid.len, "V_ID"); -} - diff --git a/src/pluto/vendor.h b/src/pluto/vendor.h deleted file mode 100644 index ac6b0d420..000000000 --- a/src/pluto/vendor.h +++ /dev/null @@ -1,137 +0,0 @@ -/* FreeS/WAN ISAKMP VendorID - * Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _VENDOR_H_ -#define _VENDOR_H_ - -enum known_vendorid { -/* 1 - 100 : Implementation names */ - VID_OPENPGP = 1, - VID_KAME_RACOON = 2, - VID_MS_NT5 = 3, - VID_SSH_SENTINEL = 4, - VID_SSH_SENTINEL_1_1 = 5, - VID_SSH_SENTINEL_1_2 = 6, - VID_SSH_SENTINEL_1_3 = 7, - VID_SSH_SENTINEL_1_4 = 8, - VID_SSH_SENTINEL_1_4_1 = 9, - VID_SSH_IPSEC_1_1_0 = 10, - VID_SSH_IPSEC_1_1_1 = 11, - VID_SSH_IPSEC_1_1_2 = 12, - VID_SSH_IPSEC_1_2_1 = 13, - VID_SSH_IPSEC_1_2_2 = 14, - VID_SSH_IPSEC_2_0_0 = 15, - VID_SSH_IPSEC_2_1_0 = 16, - VID_SSH_IPSEC_2_1_1 = 17, - VID_SSH_IPSEC_2_1_2 = 18, - VID_SSH_IPSEC_3_0_0 = 19, - VID_SSH_IPSEC_3_0_1 = 20, - VID_SSH_IPSEC_4_0_0 = 21, - VID_SSH_IPSEC_4_0_1 = 22, - VID_SSH_IPSEC_4_1_0 = 23, - VID_SSH_IPSEC_4_2_0 = 24, - VID_CISCO_UNITY = 25, - VID_CISCO3K = 26, - VID_CISCO_IOS = 27, - VID_TIMESTEP = 28, - VID_SAFENET = 29, - VID_MACOSX = 30, - VID_NCP_SERVER = 31, - VID_NCP_CLIENT = 32, - VID_VISTA_AUTHIP = 33, - VID_VISTA_AUTHIP2 = 34, - VID_VISTA_AUTHIP3 = 35, - - VID_STRONGSWAN = 36, - - VID_STRONGSWAN_2_8_0 = 37, - VID_STRONGSWAN_2_8_1 = 38, - VID_STRONGSWAN_2_8_2 = 39, - VID_STRONGSWAN_2_8_3 = 40, - VID_STRONGSWAN_2_8_4 = 41, - VID_STRONGSWAN_2_8_5 = 42, - VID_STRONGSWAN_2_8_6 = 43, - VID_STRONGSWAN_2_8_7 = 44, - VID_STRONGSWAN_2_8_8 = 45, - VID_STRONGSWAN_2_8_9 = 46, - VID_STRONGSWAN_2_8_10 = 47, - VID_STRONGSWAN_2_8_11 = 48, - - VID_STRONGSWAN_4_1_0 = 88, - VID_STRONGSWAN_4_1_1 = 89, - VID_STRONGSWAN_4_1_2 = 90, - VID_STRONGSWAN_4_1_3 = 91, - VID_STRONGSWAN_4_1_4 = 92, - VID_STRONGSWAN_4_1_5 = 93, - VID_STRONGSWAN_4_1_6 = 94, - VID_STRONGSWAN_4_1_7 = 95, - VID_STRONGSWAN_4_1_8 = 96, - VID_STRONGSWAN_4_1_9 = 97, - VID_STRONGSWAN_4_1_10 = 98, - VID_STRONGSWAN_4_1_11 = 99, - VID_STRONGSWAN_4_2_0 =100, - VID_STRONGSWAN_4_2_1 =101, - VID_STRONGSWAN_4_2_2 =102, - VID_STRONGSWAN_4_2_3 =103, - VID_STRONGSWAN_4_2_4 =104, - VID_STRONGSWAN_4_2_5 =105, - VID_STRONGSWAN_4_2_6 =106, - VID_STRONGSWAN_4_2_7 =107, - VID_STRONGSWAN_4_2_8 =108, - VID_STRONGSWAN_4_2_9 =109, - VID_STRONGSWAN_4_2_10 =110, - VID_STRONGSWAN_4_2_11 =111, - VID_STRONGSWAN_4_2_12 =112, - VID_STRONGSWAN_4_2_13 =113, - VID_STRONGSWAN_4_2_14 =114, - VID_STRONGSWAN_4_2_15 =115, - VID_STRONGSWAN_4_2_16 =116, - VID_STRONGSWAN_4_2_17 =117, - VID_STRONGSWAN_4_3_0 =118, - VID_STRONGSWAN_4_3_1 =119, - VID_STRONGSWAN_4_3_2 =120, - VID_STRONGSWAN_4_3_3 =121, - VID_STRONGSWAN_4_3_4 =122, - VID_STRONGSWAN_4_3_5 =123, - - /* 101 - 200 : NAT-Traversal */ - VID_NATT_STENBERG_01 =151, - VID_NATT_STENBERG_02 =152, - VID_NATT_HUTTUNEN =153, - VID_NATT_HUTTUNEN_ESPINUDP =154, - VID_NATT_IETF_00 =155, - VID_NATT_IETF_02_N =156, - VID_NATT_IETF_02 =157, - VID_NATT_IETF_03 =158, - VID_NATT_RFC =159, - - /* 201 - 300 : Misc */ - VID_MISC_XAUTH =201, - VID_MISC_DPD =202, - VID_MISC_HEARTBEAT_NOTIFY =203, - VID_MISC_FRAGMENTATION =204, - VID_INITIAL_CONTACT =205, - VID_CISCO3K_FRAGMENTATION =206 -}; - -void init_vendorid(void); -void free_vendorid(void); - -struct msg_digest; -void handle_vendorid (struct msg_digest *md, const char *vid, size_t len); - -bool out_vendorid (u_int8_t np, pb_stream *outs, enum known_vendorid vid); - -#endif /* _VENDOR_H_ */ - diff --git a/src/pluto/virtual.c b/src/pluto/virtual.c deleted file mode 100644 index 3e8d5fcba..000000000 --- a/src/pluto/virtual.c +++ /dev/null @@ -1,325 +0,0 @@ -/* FreeS/WAN Virtual IP Management - * Copyright (C) 2002 Mathieu Lafon - Arkoon Network Security - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <freeswan.h> - -#include <stdlib.h> -#include <string.h> -#include <sys/queue.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "connections.h" -#include "whack.h" -#include "virtual.h" - -#define F_VIRTUAL_NO 1 -#define F_VIRTUAL_DHCP 2 -#define F_VIRTUAL_IKE_CONFIG 4 -#define F_VIRTUAL_PRIVATE 8 -#define F_VIRTUAL_ALL 16 -#define F_VIRTUAL_HOST 32 - -struct virtual_t { - unsigned short flags; - unsigned short n_net; - ip_subnet net[0]; -}; - -static ip_subnet *private_net_ok=NULL, *private_net_ko=NULL; -static unsigned short private_net_ok_len=0, private_net_ko_len=0; - -/** - * read %v4:x.x.x.x/y or %v6:xxxxxxxxx/yy - * or %v4:!x.x.x.x/y if dstko not NULL - */ -static bool -_read_subnet(const char *src, size_t len, ip_subnet *dst, ip_subnet *dstko, - bool *isok) -{ - bool ok; - int af; - - if ((len > 4) && (strneq(src, "%v4:", 4))) - { - af = AF_INET; - } - else if ((len > 4) && (strneq(src, "%v6:", 4))) - { - af = AF_INET6; - } - else - { - return FALSE; - } - - ok = (src[4] != '!'); - src += ok ? 4 : 5; - len -= ok ? 4 : 5; - - if (!len) - return FALSE; - if (!ok && !dstko) - return FALSE; - - passert ( ((ok)?(dst):(dstko))!=NULL ); - - if (ttosubnet(src, len, af, ((ok)?(dst):(dstko)))) - { - return FALSE; - } - if (isok) - *isok = ok; - return TRUE; -} - -void -init_virtual_ip(const char *private_list) -{ - const char *next, *str=private_list; - unsigned short ign = 0, i_ok, i_ko; - ip_subnet sub; - bool ok; - - /** Count **/ - private_net_ok_len=0; - private_net_ko_len=0; - - while (str) - { - next = strchr(str,','); - if (!next) - next = str + strlen(str); - if (_read_subnet(str, next-str, &sub, &sub, &ok)) - if (ok) - private_net_ok_len++; - else - private_net_ko_len++; - else - ign++; - str = *next ? next+1 : NULL; - } - - if (!ign) - { - /** Allocate **/ - if (private_net_ok_len) - { - private_net_ok = (ip_subnet *)malloc(private_net_ok_len * sizeof(ip_subnet)); - } - if (private_net_ko_len) - { - private_net_ko = (ip_subnet *)malloc(private_net_ko_len * sizeof(ip_subnet)); - } - if ((private_net_ok_len && !private_net_ok) - || (private_net_ko_len && !private_net_ko)) - { - loglog(RC_LOG_SERIOUS, - "can't alloc in init_virtual_ip"); - free(private_net_ok); - private_net_ok = NULL; - free(private_net_ko); - private_net_ko = NULL; - } - else - { - /** Fill **/ - str = private_list; - i_ok = 0; - i_ko = 0; - - while (str) - { - next = strchr(str,','); - if (!next) - next = str + strlen(str); - if (_read_subnet(str, next-str, - &(private_net_ok[i_ok]), &(private_net_ko[i_ko]), &ok)) - { - if (ok) - i_ok++; - else - i_ko++; - } - str = *next ? next+1 : NULL; - } - } - } - else - loglog(RC_LOG_SERIOUS, - "%d bad entries in virtual_private - none loaded", ign); -} - -/** - * virtual string must be : - * {vhost,vnet}:[%method]* - * - * vhost = accept only a host (/32) - * vnet = accept any network - * - * %no = no virtual IP (accept public IP) - * %dhcp = accept DHCP SA (0.0.0.0/0) of affected IP [not implemented] - * %ike = accept affected IKE Config Mode IP [not implemented] - * %priv = accept system-wide private net list - * %v4:x = accept ipv4 in list 'x' - * %v6:x = accept ipv6 in list 'x' - * %all = accept all ips [only for testing] - * - * ex: vhost:%no,%dhcp,%priv,%v4:192.168.1.0/24 - */ -struct virtual_t -*create_virtual(const connection_t *c, const char *string) -{ - unsigned short flags=0, n_net=0, i; - const char *str = string, *next, *first_net=NULL; - ip_subnet sub; - struct virtual_t *v; - - if (!string || string[0] == '\0') - return NULL; - - if (strlen(string) >= 6 && strneq(string,"vhost:",6)) - { - flags |= F_VIRTUAL_HOST; - str += 6; - } - else if (strlen(string) >= 5 && strneq(string,"vnet:",5)) - str += 5; - else - goto fail; - - /** - * Parse string : fill flags & count subnets - */ - while ((str) && (*str)) - { - next = strchr(str,','); - if (!next) next = str + strlen(str); - if (next-str == 3 && strneq(str, "%no", 3)) - flags |= F_VIRTUAL_NO; -#if 0 - else if (next-str == 4 && strneq(str, "%ike", 4)) - flags |= F_VIRTUAL_IKE_CONFIG; - else if (next-str == 5 && strneq(str, "%dhcp", 5)) - flags |= F_VIRTUAL_DHCP; -#endif - else if (next-str == 5 && strneq(str, "%priv", 5)) - flags |= F_VIRTUAL_PRIVATE; - else if (next-str == 4 && strneq(str, "%all", 4)) - flags |= F_VIRTUAL_ALL; - else if (_read_subnet(str, next-str, &sub, NULL, NULL)) - { - n_net++; - if (!first_net) - first_net = str; - } - else - goto fail; - - str = *next ? next+1 : NULL; - } - - v = (struct virtual_t *)malloc(sizeof(struct virtual_t) + - (n_net * sizeof(ip_subnet))); - if (!v) goto fail; - - v->flags = flags; - v->n_net = n_net; - if (n_net && first_net) - { - /** - * Save subnets in newly allocated struct - */ - for (str = first_net, i = 0; str && *str; ) - { - next = strchr(str,','); - if (!next) next = str + strlen(str); - if (_read_subnet(str, next-str, &(v->net[i]), NULL, NULL)) - i++; - str = *next ? next+1 : NULL; - } - } - - return v; - -fail: - plog("invalid virtual string [%s] - " - "virtual selection disabled for connection '%s'", string, c->name); - return NULL; -} - -bool -is_virtual_end(const struct end *that) -{ - return ((that->virt)?TRUE:FALSE); -} - -bool -is_virtual_connection(const connection_t *c) -{ - return ((c->spd.that.virt)?TRUE:FALSE); -} - -static bool net_in_list(const ip_subnet *peer_net, const ip_subnet *list, - unsigned short len) -{ - unsigned short i; - - if (!list || !len) - return FALSE; - - for (i = 0; i < len; i++) - { - if (subnetinsubnet(peer_net, &(list[i]))) - return TRUE; - } - return FALSE; -} - -bool is_virtual_net_allowed(const connection_t *c, const ip_subnet *peer_net, - const ip_address *his_addr) -{ - if (c->spd.that.virt == NULL) - return FALSE; - - if ((c->spd.that.virt->flags & F_VIRTUAL_HOST) - && !subnetishost(peer_net)) - return FALSE; - - if ((c->spd.that.virt->flags & F_VIRTUAL_NO) - && subnetishost(peer_net) && addrinsubnet(his_addr, peer_net)) - return TRUE; - - if ((c->spd.that.virt->flags & F_VIRTUAL_PRIVATE) - && net_in_list(peer_net, private_net_ok, private_net_ok_len) - && !net_in_list(peer_net, private_net_ko, private_net_ko_len)) - return TRUE; - - if (c->spd.that.virt->n_net - && net_in_list(peer_net, c->spd.that.virt->net, c->spd.that.virt->n_net)) - return TRUE; - - if (c->spd.that.virt->flags & F_VIRTUAL_ALL) - { - /** %all must only be used for testing - log it **/ - loglog(RC_LOG_SERIOUS, "Warning - " - "v%s:%%all must only be used for testing", - (c->spd.that.virt->flags & F_VIRTUAL_HOST) ? "host" : "net"); - return TRUE; - } - - return FALSE; -} - diff --git a/src/pluto/virtual.h b/src/pluto/virtual.h deleted file mode 100644 index e64407c81..000000000 --- a/src/pluto/virtual.h +++ /dev/null @@ -1,29 +0,0 @@ -/* FreeS/WAN Virtual IP Management - * Copyright (C) 2002 Mathieu Lafon - Arkoon Network Security - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _VIRTUAL_IP_H -#define _VIRTUAL_IP_H - -extern void init_virtual_ip(const char *private_list); - -extern struct virtual_t *create_virtual(const struct connection *c, - const char *string); - -extern bool is_virtual_end(const struct end *that); -extern bool is_virtual_connection(const struct connection *c); -extern bool is_virtual_net_allowed(const struct connection *c, - const ip_subnet *peer_net, const ip_address *his_addr); - -#endif /* _VIRTUAL_IP_H */ - diff --git a/src/pluto/whack_attribute.c b/src/pluto/whack_attribute.c deleted file mode 100644 index 6a12f0c09..000000000 --- a/src/pluto/whack_attribute.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "whack_attribute.h" - -#include "log.h" - -/* these are defined as constants in constant.h but redefined as enum values in - * attributes/attributes.h */ -#undef INTERNAL_IP4_SERVER -#undef INTERNAL_IP6_SERVER - -#include <hydra.h> -#include <attributes/mem_pool.h> -#include <utils/linked_list.h> -#include <threading/rwlock.h> - -typedef struct private_whack_attribute_t private_whack_attribute_t; - -/** - * private data of whack_attribute - */ -struct private_whack_attribute_t { - - /** - * public functions - */ - whack_attribute_t public; - - /** - * list of pools, contains mem_pool_t - */ - linked_list_t *pools; - - /** - * rwlock to lock access to pools - */ - rwlock_t *lock; -}; - -/** - * global object - */ -whack_attribute_t *whack_attr; - -/** - * compare pools by name - */ -static bool pool_match(mem_pool_t *current, char *name) -{ - return name && streq(name, current->get_name(current)); -} - -/** - * find a pool by name - */ -static mem_pool_t *find_pool(private_whack_attribute_t *this, char *name) -{ - mem_pool_t *found; - if (this->pools->find_first(this->pools, (linked_list_match_t)pool_match, - (void**)&found, name) == SUCCESS) - { - return found; - } - return NULL; -} - -METHOD(attribute_provider_t, acquire_address, host_t*, - private_whack_attribute_t *this, char *name, identification_t *id, - host_t *requested) -{ - mem_pool_t *pool; - host_t *addr = NULL; - this->lock->read_lock(this->lock); - pool = find_pool(this, name); - if (pool) - { - addr = pool->acquire_address(pool, id, requested); - } - this->lock->unlock(this->lock); - return addr; -} - -METHOD(attribute_provider_t, release_address, bool, - private_whack_attribute_t *this, char *name, host_t *address, - identification_t *id) -{ - mem_pool_t *pool; - bool found = FALSE; - this->lock->read_lock(this->lock); - pool = find_pool(this, name); - if (pool) - { - found = pool->release_address(pool, address, id); - } - this->lock->unlock(this->lock); - return found; -} - -METHOD(whack_attribute_t, add_pool, bool, - private_whack_attribute_t *this, const char *name, - const whack_end_t *right) -{ - mem_pool_t *pool; - host_t *base = NULL; - u_int32_t bits = 0; - - /* named pool */ - if (right->sourceip_mask <= 0) - { - return FALSE; - } - - /* if %config, add an empty pool, otherwise */ - if (right->sourceip) - { - DBG(DBG_CONTROL, - DBG_log("adding virtual IP address pool '%s': %s/%d", - name, right->sourceip, right->sourceip_mask); - ); - base = host_create_from_string(right->sourceip, 0); - if (!base) - { - loglog(RC_LOG_SERIOUS, "virtual IP address invalid, discarded"); - return FALSE; - } - bits = right->sourceip_mask; - } - pool = mem_pool_create((char*)name, base, bits); - DESTROY_IF(base); - - this->lock->write_lock(this->lock); - this->pools->insert_last(this->pools, pool); - this->lock->unlock(this->lock); - return TRUE; -} - -METHOD(whack_attribute_t, del_pool, void, - private_whack_attribute_t *this, char *name) -{ - enumerator_t *enumerator; - mem_pool_t *pool; - - this->lock->write_lock(this->lock); - enumerator = this->pools->create_enumerator(this->pools); - while (enumerator->enumerate(enumerator, &pool)) - { - if (streq(name, pool->get_name(pool))) - { - DBG(DBG_CONTROL, - DBG_log("deleting virtual IP address pool '%s'", name) - ); - this->pools->remove_at(this->pools, enumerator); - pool->destroy(pool); - break; - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); -} - -/** - * Pool enumerator filter function, converts pool_t to name, size, ... - */ -static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name, - void *d1, u_int *size, void *d2, u_int *online, - void *d3, u_int *offline) -{ - mem_pool_t *pool = *poolp; - *name = pool->get_name(pool); - *size = pool->get_size(pool); - *online = pool->get_online(pool); - *offline = pool->get_offline(pool); - return TRUE; -} - -METHOD(whack_attribute_t, create_pool_enumerator, enumerator_t*, - private_whack_attribute_t *this) -{ - this->lock->read_lock(this->lock); - return enumerator_create_filter(this->pools->create_enumerator(this->pools), - (void*)pool_filter, - this->lock, (void*)this->lock->unlock); -} - -METHOD(whack_attribute_t, create_lease_enumerator, enumerator_t*, - private_whack_attribute_t *this, char *name) -{ - mem_pool_t *pool; - this->lock->read_lock(this->lock); - pool = find_pool(this, name); - if (!pool) - { - this->lock->unlock(this->lock); - return NULL; - } - return enumerator_create_cleaner(pool->create_lease_enumerator(pool), - (void*)this->lock->unlock, this->lock); -} - -/** - * see header file - */ -void whack_attribute_finalize() -{ - private_whack_attribute_t *this; - - if (whack_attr) - { - this = (private_whack_attribute_t*)whack_attr; - hydra->attributes->remove_provider(hydra->attributes, - &this->public.provider); - this->lock->destroy(this->lock); - this->pools->destroy_offset(this->pools, offsetof(mem_pool_t, destroy)); - free(this); - } -} - -/** - * see header file - */ -void whack_attribute_initialize() -{ - private_whack_attribute_t *this; - - INIT(this, - .public = { - .provider = { - .acquire_address = _acquire_address, - .release_address = _release_address, - .create_attribute_enumerator = enumerator_create_empty, - }, - .add_pool = _add_pool, - .del_pool = _del_pool, - .create_pool_enumerator = _create_pool_enumerator, - .create_lease_enumerator = _create_lease_enumerator, - }, - .pools = linked_list_create(), - .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), - ); - - hydra->attributes->add_provider(hydra->attributes, &this->public.provider); - - whack_attr = &this->public; -} - -/** - * list leases of a single pool - */ -static void pool_leases(char *pool, host_t *address, - identification_t *identification, - u_int size, u_int online, u_int offline) -{ - - enumerator_t *enumerator; - identification_t *id; - host_t *lease; - bool on, found = FALSE; - - whack_log(RC_COMMENT, "Leases in pool '%s', usage: %lu/%lu, %lu online", - pool, online + offline, size, online); - enumerator = whack_attr->create_lease_enumerator(whack_attr, pool); - while (enumerator && enumerator->enumerate(enumerator, &id, &lease, &on)) - { - if ((!address && !identification) || - (address && address->ip_equals(address, lease)) || - (identification && identification->equals(identification, id))) - { - whack_log(RC_COMMENT, " %15H %s '%Y'", - lease, on ? "online" : "offline", id); - found = TRUE; - } - } - enumerator->destroy(enumerator); - if (!found) - { - whack_log(RC_COMMENT, " no matching leases found"); - } -} - -/** - * see header file - */ -void list_leases(char *name, char *addr, char *id) -{ - identification_t *identification = NULL; - host_t *address = NULL; - bool found = FALSE; - enumerator_t *enumerator; - u_int size, online, offline; - char *pool; - - if (addr) - { - address = host_create_from_string(addr, 0); - } - if (id) - { - identification = identification_create_from_string(id); - } - - enumerator = whack_attr->create_pool_enumerator(whack_attr); - while (enumerator->enumerate(enumerator, &pool, &size, &online, &offline)) - { - if (!name || streq(name, pool)) - { - pool_leases(pool, address, identification, size, online, offline); - found = TRUE; - } - } - enumerator->destroy(enumerator); - if (!found) - { - if (name) - { - whack_log(RC_COMMENT, "pool '%s' not found", name); - } - else - { - whack_log(RC_COMMENT, "no pools found"); - } - } - DESTROY_IF(identification); - DESTROY_IF(address); -} - -/** - * see header file - */ -void show_pools(const char *name) -{ - enumerator_t *enumerator; - u_int size, online, offline; - char *pool; - bool first = TRUE; - - enumerator = whack_attr->create_pool_enumerator(whack_attr); - while (enumerator->enumerate(enumerator, &pool, &size, &online, &offline)) - { - if (name && !streq(name, pool)) - { - continue; - } - if (first) - { - first = FALSE; - whack_log(RC_COMMENT, "Virtual IP pools (size/online/offline):"); - } - whack_log(RC_COMMENT, "\"%s\": %u/%u/%u", pool, size, online, offline); - } - enumerator->destroy(enumerator); -} diff --git a/src/pluto/whack_attribute.h b/src/pluto/whack_attribute.h deleted file mode 100644 index 58441b973..000000000 --- a/src/pluto/whack_attribute.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup whack_attribute - * @{ @ingroup pluto - */ - -#ifndef WHACK_ATTRIBUTE_H_ -#define WHACK_ATTRIBUTE_H_ - -#include <whack.h> -#include <attributes/attribute_provider.h> - -typedef struct whack_attribute_t whack_attribute_t; - -/** - * Whack attribute provider (basically an in-memory IP address pool) - */ -struct whack_attribute_t { - - /** - * Implements attribute provider interface - */ - attribute_provider_t provider; - - /** - * Add a virtual IP address pool. - * - * @param name name of the pool - * @param right "right" end of whack message - * @return TRUE, if the pool was successfully added - */ - bool (*add_pool)(whack_attribute_t *this, const char *name, - const whack_end_t *right); - - /** - * Remove a virtual IP address pool. - * - * @param name name of the pool - */ - void (*del_pool)(whack_attribute_t *this, char *name); - - /** - * Create an enumerator over installed pools. - * - * Enumerator enumerates over - * char *pool, u_int size, u_int offline, u_int online. - * - * @return enumerator - */ - enumerator_t* (*create_pool_enumerator)(whack_attribute_t *this); - - /** - * Create an enumerator over the leases of a pool. - * - * Enumerator enumerates over - * identification_t *id, host_t *address, bool online - * - * @param name name of the pool to enumerate - * @return enumerator, NULL if pool not found - */ - enumerator_t* (*create_lease_enumerator)(whack_attribute_t *this, - char *name); -}; - -/** - * Global object to manage pools. Set between calls to - * whack_attribute_initialize() and whack_attribute_finalize(). - */ -extern whack_attribute_t *whack_attr; - -/** - * Initialize the whack attribute provider - */ -void whack_attribute_initialize(); - -/** - * Finalize the whack attribute provider - */ -void whack_attribute_finalize(); - -/** - * List the leases matching the given parameters. - * - * @param name name of the pool, NULL for all pools - * @param addr ip address of the lease to list, NULL to ignore - * @param id id of the lease to list, NULL to ignore - */ -void list_leases(char *name, char *addr, char *id); - -/** - * List either all pools or the pool with a given name - * - * @param name name of the pool, NULL for all pools - */ -void show_pools(const char *name); - -#endif /** WHACK_ATTRIBUTE_H_ @}*/ diff --git a/src/pluto/x509.c b/src/pluto/x509.c deleted file mode 100644 index f017e5775..000000000 --- a/src/pluto/x509.c +++ /dev/null @@ -1,463 +0,0 @@ -/* Support of X.509 certificates - * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann - * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss - * Copyright (C) 2002 Mario Strasser - * Copyright (C) 2000-2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <dirent.h> -#include <time.h> -#include <sys/types.h> - -#include <freeswan.h> - -#include <asn1/asn1.h> -#include <crypto/hashers/hasher.h> -#include <utils/enumerator.h> -#include <utils/identification.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "crl.h" -#include "ca.h" -#include "certs.h" -#include "keys.h" -#include "whack.h" -#include "fetch.h" -#include "ocsp.h" - -/** - * Check for equality between two key identifiers - */ -bool same_keyid(chunk_t a, chunk_t b) -{ - if (a.ptr == NULL || b.ptr == NULL) - { - return FALSE; - } - return chunk_equals(a, b); -} - -/** - * Stores a chained list of end certs and CA certs - */ -void store_x509certs(linked_list_t *certs, bool strict) -{ - cert_t *x509cert, *cacerts = NULL; - certificate_t *cert; - enumerator_t *enumerator; - - /* first extract CA certs, ignoring self-signed root CA certs */ - - enumerator = certs->create_enumerator(certs); - while (enumerator->enumerate(enumerator, &cert)) - { - x509_t *x509 = (x509_t*)cert; - x509_flag_t flags; - - flags = x509->get_flags(x509); - if (flags & X509_CA) - { - /* we don't accept self-signed CA certs */ - if (flags & X509_SELF_SIGNED) - { - plog("self-signed cacert rejected"); - } - else - { - /* insertion into temporary chain of candidate CA certs */ - x509cert = malloc_thing(cert_t); - *x509cert = cert_empty; - x509cert->cert = cert->get_ref(cert); - x509cert->next = cacerts; - cacerts = x509cert; - } - } - } - enumerator->destroy(enumerator); - - /* now verify the candidate CA certs */ - - while (cacerts) - { - cert_t *cert = cacerts; - - cacerts = cacerts->next; - - if (trust_authcert_candidate(cert, cacerts)) - { - add_authcert(cert, X509_CA); - } - else - { - plog("intermediate cacert rejected"); - cert_free(cert); - } - } - - /* now verify the end certificates */ - - enumerator = certs->create_enumerator(certs); - while (enumerator->enumerate(enumerator, &cert)) - { - time_t valid_until; - x509_t *x509 = (x509_t*)cert; - - if (!(x509->get_flags(x509) & X509_CA)) - { - x509cert = malloc_thing(cert_t); - *x509cert = cert_empty; - x509cert->cert = cert->get_ref(cert); - - if (verify_x509cert(x509cert, strict, &valid_until)) - { - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log("public key validated") - ) - add_public_key_from_cert(x509cert, valid_until, DAL_SIGNED); - } - else - { - plog("X.509 certificate rejected"); - cert_free(x509cert); - } - } - } - enumerator->destroy(enumerator); -} - -/** - * Check if a signature over binary blob is genuine - */ -bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, - certificate_t *issuer_cert) -{ - bool success; - public_key_t *key; - signature_scheme_t scheme; - - scheme = signature_scheme_from_oid(algorithm); - if (scheme == SIGN_UNKNOWN) - { - return FALSE; - } - - key = issuer_cert->get_public_key(issuer_cert); - if (key == NULL) - { - return FALSE; - } - success = key->verify(key, scheme, tbs, sig); - key->destroy(key); - - return success; -} - -/** - * Build an ASN.1 encoded PKCS#1 signature over a binary blob - */ -chunk_t x509_build_signature(chunk_t tbs, int algorithm, private_key_t *key, - bool bit_string) -{ - chunk_t signature; - signature_scheme_t scheme = signature_scheme_from_oid(algorithm); - - if (scheme == SIGN_UNKNOWN || !key->sign(key, scheme, tbs, &signature)) - { - return chunk_empty; - } - return (bit_string) ? asn1_bitstring("m", signature) - : asn1_wrap(ASN1_OCTET_STRING, "m", signature); -} - -/** - * Verifies a X.509 certificate - */ -bool verify_x509cert(cert_t *cert, bool strict, time_t *until) -{ - int pathlen, pathlen_constraint; - - *until = 0; - - for (pathlen = -1; pathlen <= X509_MAX_PATH_LEN; pathlen++) - { - certificate_t *certificate = cert->cert; - identification_t *subject = certificate->get_subject(certificate); - identification_t *issuer = certificate->get_issuer(certificate); - x509_t *x509 = (x509_t*)certificate; - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - cert_t *issuer_cert; - time_t notBefore, notAfter; - bool valid; - - DBG(DBG_CONTROL, - DBG_log("subject: '%Y'", subject); - DBG_log("issuer: '%Y'", issuer); - if (authKeyID.ptr) - { - DBG_log("authkey: %#B", &authKeyID); - } - ) - - valid = certificate->get_validity(certificate, NULL, - ¬Before, ¬After); - if (*until == UNDEFINED_TIME || notAfter < *until) - { - *until = notAfter; - } - if (!valid) - { - plog("certificate is invalid (valid from %T to %T)", - ¬Before, FALSE, ¬After, FALSE); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate is valid") - ) - - lock_authcert_list("verify_x509cert"); - issuer_cert = get_authcert(issuer, authKeyID, X509_CA); - if (issuer_cert == NULL) - { - plog("issuer cacert not found"); - unlock_authcert_list("verify_x509cert"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("issuer cacert found") - ) - - if (!certificate->issued_by(certificate, issuer_cert->cert)) - { - plog("certificate signature is invalid"); - unlock_authcert_list("verify_x509cert"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate signature is valid") - ) - unlock_authcert_list("verify_x509cert"); - - /* check path length constraint */ - pathlen_constraint = x509->get_constraint(x509, X509_PATH_LEN); - if (pathlen_constraint != X509_NO_CONSTRAINT && - pathlen > pathlen_constraint) - { - plog("path length of %d violates constraint of %d", - pathlen, pathlen_constraint); - return FALSE; - } - - /* check if cert is a self-signed root ca */ - if (pathlen >= 0 && (x509->get_flags(x509) & X509_SELF_SIGNED)) - { - DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca with a path length of %d", - pathlen) - ) - return TRUE; - } - else - { - time_t nextUpdate = *until; - time_t revocationDate = UNDEFINED_TIME; - crl_reason_t revocationReason = CRL_REASON_UNSPECIFIED; - - /* first check certificate revocation using ocsp */ - cert_status_t status = verify_by_ocsp(cert, &nextUpdate - , &revocationDate, &revocationReason); - - /* if ocsp service is not available then fall back to crl */ - if ((status == CERT_UNDEFINED) - || (status == CERT_UNKNOWN && strict)) - { - status = verify_by_crl(cert, &nextUpdate, &revocationDate - , &revocationReason); - } - - switch (status) - { - case CERT_GOOD: - /* if status information is stale */ - if (strict && nextUpdate < time(NULL)) - { - DBG(DBG_CONTROL, - DBG_log("certificate is good but status is stale") - ) - remove_x509_public_key(cert); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate is good") - ) - - /* with strict crl policy the public key must have the same - * lifetime as the validity of the ocsp status or crl lifetime - */ - if (strict && nextUpdate < *until) - { - *until = nextUpdate; - } - break; - case CERT_REVOKED: - plog("certificate was revoked on %T, reason: %N" - , &revocationDate, TRUE - , crl_reason_names, revocationReason); - remove_x509_public_key(cert); - return FALSE; - case CERT_UNKNOWN: - case CERT_UNDEFINED: - default: - plog("certificate status unknown"); - if (strict) - { - remove_x509_public_key(cert); - return FALSE; - } - break; - } - } - - /* go up one step in the trust chain */ - cert = issuer_cert; - } - plog("maximum path length of %d exceeded", X509_MAX_PATH_LEN); - return FALSE; -} - -/** - * List all X.509 certs in a chained list - */ -void list_x509cert_chain(const char *caption, cert_t* cert, - x509_flag_t flags, bool utc) -{ - bool first = TRUE; - time_t now; - - /* determine the current time */ - time(&now); - - while (cert) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - - if (certificate->get_type(certificate) == CERT_X509 && - (flags == X509_NONE || (flags & x509->get_flags(x509)))) - { - enumerator_t *enumerator; - char buf[BUF_LEN]; - char *pos = buf; - int len = BUF_LEN, pathlen; - bool first_altName = TRUE; - identification_t *id; - time_t notBefore, notAfter; - public_key_t *key; - chunk_t serial, keyid, subjkey, authkey; - - if (first) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 %s Certificates:", caption); - first = FALSE; - } - whack_log(RC_COMMENT, " "); - - enumerator = x509->create_subjectAltName_enumerator(x509); - while (enumerator->enumerate(enumerator, &id)) - { - int written; - - if (first_altName) - { - written = snprintf(pos, len, "%Y", id); - first_altName = FALSE; - } - else - { - written = snprintf(pos, len, ", %Y", id); - } - if (written < 0 || written >= len) - { - break; - } - pos += written; - len -= written; - } - enumerator->destroy(enumerator); - if (!first_altName) - { - whack_log(RC_COMMENT, " altNames: %s", buf); - } - - whack_log(RC_COMMENT, " subject: \"%Y\"", - certificate->get_subject(certificate)); - whack_log(RC_COMMENT, " issuer: \"%Y\"", - certificate->get_issuer(certificate)); - serial = chunk_skip_zero(x509->get_serial(x509)); - whack_log(RC_COMMENT, " serial: %#B", &serial); - - /* list validity */ - certificate->get_validity(certificate, &now, ¬Before, ¬After); - whack_log(RC_COMMENT, " validity: not before %T %s", - ¬Before, utc, - (notBefore < now)?"ok":"fatal (not valid yet)"); - whack_log(RC_COMMENT, " not after %T %s", - ¬After, utc, - check_expiry(notAfter, CA_CERT_WARNING_INTERVAL, TRUE)); - - key = certificate->get_public_key(certificate); - if (key) - { - whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", - key_type_names, key->get_type(key), - key->get_keysize(key), - cert->smartcard ? ", on smartcard" : - (has_private_key(cert)? ", has private key" : "")); - - if (key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &keyid)) - { - whack_log(RC_COMMENT, " keyid: %#B", &keyid); - } - if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &subjkey)) - { - whack_log(RC_COMMENT, " subjkey: %#B", &subjkey); - } - key->destroy(key); - } - - /* list optional authorityKeyIdentifier */ - authkey = x509->get_authKeyIdentifier(x509); - if (authkey.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &authkey); - } - - /* list optional pathLenConstraint */ - pathlen = x509->get_constraint(x509, X509_PATH_LEN); - if (pathlen != X509_NO_CONSTRAINT) - { - whack_log(RC_COMMENT, " pathlen: %d", pathlen); - } - - } - cert = cert->next; - } -} - diff --git a/src/pluto/x509.h b/src/pluto/x509.h deleted file mode 100644 index 3101724a6..000000000 --- a/src/pluto/x509.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Support of X.509 certificates - * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann - * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss - * Copyright (C) 2002 Mario Strasser - * Copyright (C) 2000-2009 Andreas Steffen, Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _X509_H -#define _X509_H - -#include <utils/identification.h> -#include <utils/linked_list.h> -#include <credentials/keys/private_key.h> -#include <credentials/certificates/x509.h> - -#include "constants.h" -#include "certs.h" - -#define X509_MAX_PATH_LEN 7 - -extern bool same_keyid(chunk_t a, chunk_t b); -extern bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, - certificate_t *issuer_cert); -extern chunk_t x509_build_signature(chunk_t tbs, int algorithm, - private_key_t *key, bool bit_string); -extern bool verify_x509cert(cert_t *cert, bool strict, time_t *until); -extern void store_x509certs(linked_list_t *certs, bool strict); -extern void list_x509cert_chain(const char *caption, cert_t* cert, - x509_flag_t flags, bool utc); -extern void list_x509_end_certs(bool utc); - -#endif /* _X509_H */ diff --git a/src/pluto/xauth/xauth_manager.c b/src/pluto/xauth/xauth_manager.c deleted file mode 100644 index 2e57ccefa..000000000 --- a/src/pluto/xauth/xauth_manager.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "xauth_manager.h" - -typedef struct private_xauth_manager_t private_xauth_manager_t; - -/** - * private data of xauth_manager - */ -struct private_xauth_manager_t { - - /** - * public functions - */ - xauth_manager_t public; - - /** - * list of registered secret providers - */ - linked_list_t *providers; - - /** - * list of registered secret verifiers - */ - linked_list_t *verifiers; -}; - -METHOD(xauth_manager_t, get_secret, bool, - private_xauth_manager_t *this, connection_t *c, chunk_t *secret) -{ - xauth_provider_t *provider; - enumerator_t *enumerator; - bool success = FALSE; - - *secret = chunk_empty; - - enumerator = this->providers->create_enumerator(this->providers); - while (enumerator->enumerate(enumerator, &provider)) - { - if (provider->get_secret(provider, c, secret)) - { - success = TRUE; - break; - } - } - enumerator->destroy(enumerator); - return success; -} - -METHOD(xauth_manager_t, verify_secret, bool, - private_xauth_manager_t *this, connection_t *c, chunk_t secret) -{ - xauth_verifier_t *verifier; - enumerator_t *enumerator; - bool success = FALSE; - - enumerator = this->verifiers->create_enumerator(this->verifiers); - while (enumerator->enumerate(enumerator, &verifier)) - { - if (verifier->verify_secret(verifier, c, secret)) - { - success = TRUE; - break; - } - } - enumerator->destroy(enumerator); - return success; -} - -METHOD(xauth_manager_t, add_provider, void, - private_xauth_manager_t *this, xauth_provider_t *provider) -{ - this->providers->insert_last(this->providers, provider); -} - -METHOD(xauth_manager_t, add_verifier, void, - private_xauth_manager_t *this, xauth_verifier_t *verifier) -{ - this->verifiers->insert_last(this->verifiers, verifier); -} - -METHOD(xauth_manager_t, destroy, void, - private_xauth_manager_t *this) -{ - this->providers->destroy_offset(this->providers, - offsetof(xauth_provider_t, destroy)); - this->verifiers->destroy_offset(this->verifiers, - offsetof(xauth_verifier_t, destroy)); - free(this); -} - -/* - * Described in header. - */ -xauth_manager_t *xauth_manager_create() -{ - private_xauth_manager_t *this; - - INIT(this, - .public = { - .get_secret = _get_secret, - .verify_secret = _verify_secret, - .add_provider = _add_provider, - .add_verifier = _add_verifier, - .destroy = _destroy, - } - ); - - this->providers = linked_list_create(); - this->verifiers = linked_list_create(); - - return &this->public; -} - diff --git a/src/pluto/xauth/xauth_manager.h b/src/pluto/xauth/xauth_manager.h deleted file mode 100644 index 843eb2ff0..000000000 --- a/src/pluto/xauth/xauth_manager.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_manager xauth_manager - * @{ @ingroup xauth - */ - -#ifndef XAUTH_MANAGER_H_ -#define XAUTH_MANAGER_H_ - -#include "xauth_provider.h" -#include "xauth_verifier.h" - -typedef struct xauth_manager_t xauth_manager_t; - -/** - * An xauth_manager registers xauth_providers and xauth_verifiers. - */ -struct xauth_manager_t { - - /** - * Register an xauth_provider - * - * @param provider xauth_provider to be registered - */ - void (*add_provider)(xauth_manager_t *this, xauth_provider_t *provider); - - /** - * Register an xauth_verifier - * - * @param verifier xauth_verifier to be registered - */ - void (*add_verifier)(xauth_manager_t *this, xauth_verifier_t *verifier); - - /** - * Use registered providers to retrieve an XAUTH user secret - * based on connection information. - * - * @param c connection information - * @param secret secret if found, chunk_empty otherwise - * @return TRUE if a matching secret was found - */ - bool (*get_secret)(xauth_manager_t *this, connection_t *c, chunk_t *secret); - - /** - * Use registered verifiers to verify an XAUTH user secret - * based on connection information - * - * @param c connection information - * @param secret secret to be compared - * @return TRUE if secret matches - */ - bool (*verify_secret)(xauth_manager_t *this, connection_t *c, chunk_t secret); - - /** - * Destroy an xauth_verifier instance. - */ - void (*destroy)(xauth_manager_t *this); -}; - -/** - * Create an xauth_manager instance. - */ -xauth_manager_t *xauth_manager_create(); - -#endif /** XAUTH_MANAGER_H_ @}*/ - diff --git a/src/pluto/xauth/xauth_provider.h b/src/pluto/xauth/xauth_provider.h deleted file mode 100644 index 90adbff50..000000000 --- a/src/pluto/xauth/xauth_provider.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_provider xauth_provider - * @{ @ingroup xauth - */ - -#ifndef XAUTH_PROVIDER_H_ -#define XAUTH_PROVIDER_H_ - -#include <library.h> - -#include <connections.h> - -typedef struct xauth_provider_t xauth_provider_t; - -/** - * An xauth provider retrieves xauth user secrets on the client side. - */ -struct xauth_provider_t { - - /** - * Retrieve an XAUTH user secret based on connection information. - * - * @param c connection information - * @param secret secret if found, chunk_empty otherwise - * @return TRUE if a matching secret was found - */ - bool (*get_secret)(xauth_provider_t *this, connection_t *c, chunk_t *secret); - - /** - * Destroy an xauth_provider instance. - */ - void (*destroy)(xauth_provider_t *this); -}; - -/** - * Create an xauth_provider instance. - */ -xauth_provider_t *xauth_provider_create(); - -#endif /** XAUTH_PROVIDER_H_ @}*/ - diff --git a/src/pluto/xauth/xauth_verifier.h b/src/pluto/xauth/xauth_verifier.h deleted file mode 100644 index 7c9ff3a7f..000000000 --- a/src/pluto/xauth/xauth_verifier.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_verifier xauth_verifier - * @{ @ingroup xauth - */ - -#ifndef XAUTH_VERIFIER_H_ -#define XAUTH_VERIFIER_H_ - -#include <library.h> - -#include <connections.h> - -typedef struct xauth_verifier_t xauth_verifier_t; - -/** - * An xauth verifier verifies xauth user secrets on the server side. - */ -struct xauth_verifier_t { - - /** - * Verify an XAUTH user secret base on connection information - * - * @param c connection information - * @param secret secret to be compared - * @return TRUE if secret matches - */ - bool (*verify_secret)(xauth_verifier_t *this, connection_t *c, chunk_t secret); - - /** - * Destroy an xauth_verifier instance. - */ - void (*destroy)(xauth_verifier_t *this); -}; - -/** - * Create an xauth_verifier instance. - */ -xauth_verifier_t *xauth_verifier_create(); - -#endif /** XAUTH_VERIFIER_H_ @}*/ - |