diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2009-06-23 11:25:24 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2009-06-23 11:25:24 +0000 |
commit | 41787e147279ff0695e9d759487266a60b80867b (patch) | |
tree | 8f28566c8fd7106c80d2536d2df540dbb4499cc5 /src/pluto | |
parent | c3e7f611ea8273c6b3909cb006ade4903a74aad0 (diff) | |
download | vyos-strongswan-41787e147279ff0695e9d759487266a60b80867b.tar.gz vyos-strongswan-41787e147279ff0695e9d759487266a60b80867b.zip |
[svn-upgrade] Integrating new upstream version, strongswan (4.3.2)
Diffstat (limited to 'src/pluto')
122 files changed, 37886 insertions, 46595 deletions
diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am index f788bc3d1..01237305b 100644 --- a/src/pluto/Makefile.am +++ b/src/pluto/Makefile.am @@ -7,7 +7,6 @@ ipsec_PROGRAMS = pluto _pluto_adns pluto_SOURCES = \ ac.c ac.h \ alg_info.c alg_info.h \ -asn1.c asn1.h \ ca.c ca.h \ certs.c certs.h \ connections.c connections.h \ @@ -19,11 +18,8 @@ db_ops.c db_ops.h \ defs.c defs.h \ demux.c demux.h \ dnskey.c dnskey.h \ -dsa.c dsa.h \ -elgamal.c elgamal.h \ fetch.c fetch.h \ foodgroups.c foodgroups.h \ -gcryptfix.c gcryptfix.h \ id.c id.h \ ike_alg.c ike_alg.h \ ipsec_doi.c ipsec_doi.h \ @@ -36,23 +32,16 @@ kernel_pfkey.c kernel_pfkey.h \ keys.c keys.h \ lex.c lex.h \ log.c log.h \ -md2.c md2.h \ -md5.c md5.h \ modecfg.c modecfg.h \ -mp_defs.c mp_defs.h \ nat_traversal.c nat_traversal.h \ ocsp.c ocsp.h \ packet.c packet.h \ pem.c pem.h \ -pgp.c pgp.h \ -pkcs1.c pkcs1.h \ +pgpcert.c pgpcert.h \ pkcs7.c pkcs7.h \ plutomain.c \ -primegen.c smallprime.c \ rcv_whack.c rcv_whack.h \ -rnd.c rnd.h \ server.c server.h \ -sha1.c sha1.h \ smartcard.c smartcard.h \ spdb.c spdb.h \ state.c state.h \ @@ -61,22 +50,17 @@ vendor.c vendor.h \ virtual.c virtual.h \ xauth.c xauth.h \ x509.c x509.h \ -alg/ike_alg_aes.c alg/ike_alg_blowfish.c alg/ike_alg_twofish.c \ -alg/ike_alg_serpent.c alg/ike_alg_sha2.c alg/ike_alginit.c \ rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h _pluto_adns_SOURCES = adns.c adns.h -LIBSTRONGSWANDIR=$(top_srcdir)/src/libstrongswan +LIBSTRONGSWANDIR=$(top_builddir)/src/libstrongswan LIBFREESWANDIR=$(top_builddir)/src/libfreeswan -LIBCRYPTODIR=$(top_builddir)/src/libcrypto - INCLUDES = \ -I${linuxdir} \ --I$(LIBSTRONGSWANDIR)\ +-I$(top_srcdir)/src/libstrongswan \ -I$(top_srcdir)/src/libfreeswan \ --I$(top_srcdir)/src/libcrypto \ -I$(top_srcdir)/src/whack AM_CFLAGS = \ @@ -84,24 +68,23 @@ AM_CFLAGS = \ -DIPSEC_CONFDIR=\"${confdir}\" \ -DIPSEC_PIDDIR=\"${piddir}\" \ -DSHARED_SECRETS_FILE=\"${confdir}/ipsec.secrets\" \ +-DIPSEC_PLUGINDIR=\"${plugindir}\" \ +-DPLUGINS=\""${pluto_plugins}\"" \ +-DSTRONGSWAN_CONF=\"${strongswan_conf}\" \ -DKERNEL26_SUPPORT -DKERNEL26_HAS_KAME_DUPLICATES \ -DPLUTO -DKLIPS -DDEBUG pluto_LDADD = \ -oid.o \ +$(LIBSTRONGSWANDIR)/libstrongswan.la \ $(LIBFREESWANDIR)/libfreeswan.a \ -$(LIBCRYPTODIR)/libcrypto.a \ --lgmp -lresolv -lpthread -ldl +-lresolv -lpthread $(DLLIB) _pluto_adns_LDADD = \ $(LIBFREESWANDIR)/libfreeswan.a \ --lresolv -ldl +-lresolv $(DLLIB) dist_man_MANS = pluto.8 ipsec.secrets.5 -oid.o : $(LIBSTRONGSWANDIR)/asn1/oid.c $(LIBSTRONGSWANDIR)/asn1/oid.h - $(COMPILE) -c -o $@ $< - # This compile option activates the sending of a strongSwan VID if USE_VENDORID AM_CFLAGS += -DVENDORID @@ -122,23 +105,16 @@ if USE_NAT_TRANSPORT AM_CFLAGS += -DI_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT endif -# This compile option activates dynamic URL fetching using libcurl -if USE_CURL - pluto_LDADD += -lcurl - AM_CFLAGS += -DLIBCURL -endif - -# This compile option activates dynamic LDAP CRL fetching -if USE_LDAP - pluto_LDADD += -lldap -llber - AM_CFLAGS += -DLIBLDAP -endif - # This compile option activates smartcard support if USE_SMARTCARD AM_CFLAGS += -DSMARTCARD endif +# This compile option activates the integrity test of libstrongswan +if USE_INTEGRITY_TEST + AM_CFLAGS += -DINTEGRITY_TEST +endif + if USE_CAPABILITIES pluto_LDADD += -lcap endif diff --git a/src/pluto/Makefile.in b/src/pluto/Makefile.in index 457f93d9f..01bda8540 100644 --- a/src/pluto/Makefile.in +++ b/src/pluto/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.10.1 from Makefile.am. +# Makefile.in generated by automake 1.10.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -50,21 +50,16 @@ ipsec_PROGRAMS = pluto$(EXEEXT) _pluto_adns$(EXEEXT) # This compile option activates NAT traversal with IPSec transport mode @USE_NAT_TRANSPORT_TRUE@am__append_4 = -DI_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT -# This compile option activates dynamic URL fetching using libcurl -@USE_CURL_TRUE@am__append_5 = -lcurl -@USE_CURL_TRUE@am__append_6 = -DLIBCURL - -# This compile option activates dynamic LDAP CRL fetching -@USE_LDAP_TRUE@am__append_7 = -lldap -llber -@USE_LDAP_TRUE@am__append_8 = -DLIBLDAP - # This compile option activates smartcard support -@USE_SMARTCARD_TRUE@am__append_9 = -DSMARTCARD -@USE_CAPABILITIES_TRUE@am__append_10 = -lcap -@USE_THREADS_TRUE@am__append_11 = -DTHREADS +@USE_SMARTCARD_TRUE@am__append_5 = -DSMARTCARD + +# This compile option activates the integrity test of libstrongswan +@USE_INTEGRITY_TEST_TRUE@am__append_6 = -DINTEGRITY_TEST +@USE_CAPABILITIES_TRUE@am__append_7 = -lcap +@USE_THREADS_TRUE@am__append_8 = -DTHREADS subdir = src/pluto DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in TODO + $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ @@ -77,34 +72,28 @@ ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(ipsec_PROGRAMS) am__pluto_adns_OBJECTS = adns.$(OBJEXT) _pluto_adns_OBJECTS = $(am__pluto_adns_OBJECTS) -_pluto_adns_DEPENDENCIES = $(LIBFREESWANDIR)/libfreeswan.a -am_pluto_OBJECTS = ac.$(OBJEXT) alg_info.$(OBJEXT) asn1.$(OBJEXT) \ - ca.$(OBJEXT) certs.$(OBJEXT) connections.$(OBJEXT) \ - constants.$(OBJEXT) cookie.$(OBJEXT) crl.$(OBJEXT) \ - crypto.$(OBJEXT) db_ops.$(OBJEXT) defs.$(OBJEXT) \ - demux.$(OBJEXT) dnskey.$(OBJEXT) dsa.$(OBJEXT) \ - elgamal.$(OBJEXT) fetch.$(OBJEXT) foodgroups.$(OBJEXT) \ - gcryptfix.$(OBJEXT) id.$(OBJEXT) ike_alg.$(OBJEXT) \ - ipsec_doi.$(OBJEXT) kernel.$(OBJEXT) kernel_alg.$(OBJEXT) \ - kernel_netlink.$(OBJEXT) kernel_noklips.$(OBJEXT) \ - kernel_pfkey.$(OBJEXT) keys.$(OBJEXT) lex.$(OBJEXT) \ - log.$(OBJEXT) md2.$(OBJEXT) md5.$(OBJEXT) modecfg.$(OBJEXT) \ - mp_defs.$(OBJEXT) nat_traversal.$(OBJEXT) ocsp.$(OBJEXT) \ - packet.$(OBJEXT) pem.$(OBJEXT) pgp.$(OBJEXT) pkcs1.$(OBJEXT) \ - pkcs7.$(OBJEXT) plutomain.$(OBJEXT) primegen.$(OBJEXT) \ - smallprime.$(OBJEXT) rcv_whack.$(OBJEXT) rnd.$(OBJEXT) \ - server.$(OBJEXT) sha1.$(OBJEXT) smartcard.$(OBJEXT) \ - spdb.$(OBJEXT) state.$(OBJEXT) timer.$(OBJEXT) \ - vendor.$(OBJEXT) virtual.$(OBJEXT) xauth.$(OBJEXT) \ - x509.$(OBJEXT) ike_alg_aes.$(OBJEXT) \ - ike_alg_blowfish.$(OBJEXT) ike_alg_twofish.$(OBJEXT) \ - ike_alg_serpent.$(OBJEXT) ike_alg_sha2.$(OBJEXT) \ - ike_alginit.$(OBJEXT) -pluto_OBJECTS = $(am_pluto_OBJECTS) am__DEPENDENCIES_1 = -pluto_DEPENDENCIES = oid.o $(LIBFREESWANDIR)/libfreeswan.a \ - $(LIBCRYPTODIR)/libcrypto.a $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +_pluto_adns_DEPENDENCIES = $(LIBFREESWANDIR)/libfreeswan.a \ + $(am__DEPENDENCIES_1) +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) \ + dnskey.$(OBJEXT) fetch.$(OBJEXT) foodgroups.$(OBJEXT) \ + id.$(OBJEXT) ike_alg.$(OBJEXT) ipsec_doi.$(OBJEXT) \ + kernel.$(OBJEXT) kernel_alg.$(OBJEXT) kernel_netlink.$(OBJEXT) \ + kernel_noklips.$(OBJEXT) kernel_pfkey.$(OBJEXT) keys.$(OBJEXT) \ + lex.$(OBJEXT) log.$(OBJEXT) modecfg.$(OBJEXT) \ + nat_traversal.$(OBJEXT) ocsp.$(OBJEXT) packet.$(OBJEXT) \ + pem.$(OBJEXT) pgpcert.$(OBJEXT) pkcs7.$(OBJEXT) \ + plutomain.$(OBJEXT) rcv_whack.$(OBJEXT) server.$(OBJEXT) \ + smartcard.$(OBJEXT) spdb.$(OBJEXT) state.$(OBJEXT) \ + timer.$(OBJEXT) vendor.$(OBJEXT) virtual.$(OBJEXT) \ + xauth.$(OBJEXT) x509.$(OBJEXT) +pluto_OBJECTS = $(am_pluto_OBJECTS) +pluto_DEPENDENCIES = $(LIBSTRONGSWANDIR)/libstrongswan.la \ + $(LIBFREESWANDIR)/libfreeswan.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles @@ -141,6 +130,7 @@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -163,6 +153,9 @@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ @@ -174,6 +167,7 @@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ @@ -187,6 +181,8 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ @@ -247,6 +243,7 @@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ piddir = @piddir@ plugindir = @plugindir@ +pluto_plugins = @pluto_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ @@ -258,6 +255,7 @@ srcdir = @srcdir@ strongswan_conf = @strongswan_conf@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ xml_CFLAGS = @xml_CFLAGS@ @@ -265,7 +263,6 @@ xml_LIBS = @xml_LIBS@ pluto_SOURCES = \ ac.c ac.h \ alg_info.c alg_info.h \ -asn1.c asn1.h \ ca.c ca.h \ certs.c certs.h \ connections.c connections.h \ @@ -277,11 +274,8 @@ db_ops.c db_ops.h \ defs.c defs.h \ demux.c demux.h \ dnskey.c dnskey.h \ -dsa.c dsa.h \ -elgamal.c elgamal.h \ fetch.c fetch.h \ foodgroups.c foodgroups.h \ -gcryptfix.c gcryptfix.h \ id.c id.h \ ike_alg.c ike_alg.h \ ipsec_doi.c ipsec_doi.h \ @@ -294,23 +288,16 @@ kernel_pfkey.c kernel_pfkey.h \ keys.c keys.h \ lex.c lex.h \ log.c log.h \ -md2.c md2.h \ -md5.c md5.h \ modecfg.c modecfg.h \ -mp_defs.c mp_defs.h \ nat_traversal.c nat_traversal.h \ ocsp.c ocsp.h \ packet.c packet.h \ pem.c pem.h \ -pgp.c pgp.h \ -pkcs1.c pkcs1.h \ +pgpcert.c pgpcert.h \ pkcs7.c pkcs7.h \ plutomain.c \ -primegen.c smallprime.c \ rcv_whack.c rcv_whack.h \ -rnd.c rnd.h \ server.c server.h \ -sha1.c sha1.h \ smartcard.c smartcard.h \ spdb.c spdb.h \ state.c state.h \ @@ -319,34 +306,33 @@ vendor.c vendor.h \ virtual.c virtual.h \ xauth.c xauth.h \ x509.c x509.h \ -alg/ike_alg_aes.c alg/ike_alg_blowfish.c alg/ike_alg_twofish.c \ -alg/ike_alg_serpent.c alg/ike_alg_sha2.c alg/ike_alginit.c \ rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h _pluto_adns_SOURCES = adns.c adns.h -LIBSTRONGSWANDIR = $(top_srcdir)/src/libstrongswan +LIBSTRONGSWANDIR = $(top_builddir)/src/libstrongswan LIBFREESWANDIR = $(top_builddir)/src/libfreeswan -LIBCRYPTODIR = $(top_builddir)/src/libcrypto INCLUDES = \ -I${linuxdir} \ --I$(LIBSTRONGSWANDIR)\ +-I$(top_srcdir)/src/libstrongswan \ -I$(top_srcdir)/src/libfreeswan \ --I$(top_srcdir)/src/libcrypto \ -I$(top_srcdir)/src/whack AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" -DIPSEC_CONFDIR=\"${confdir}\" \ -DIPSEC_PIDDIR=\"${piddir}\" \ -DSHARED_SECRETS_FILE=\"${confdir}/ipsec.secrets\" \ - -DKERNEL26_SUPPORT -DKERNEL26_HAS_KAME_DUPLICATES -DPLUTO \ - -DKLIPS -DDEBUG $(am__append_1) $(am__append_2) \ - $(am__append_3) $(am__append_4) $(am__append_6) \ - $(am__append_8) $(am__append_9) $(am__append_11) -pluto_LDADD = oid.o $(LIBFREESWANDIR)/libfreeswan.a \ - $(LIBCRYPTODIR)/libcrypto.a -lgmp -lresolv -lpthread -ldl \ - $(am__append_5) $(am__append_7) $(am__append_10) + -DIPSEC_PLUGINDIR=\"${plugindir}\" \ + -DPLUGINS=\""${pluto_plugins}\"" \ + -DSTRONGSWAN_CONF=\"${strongswan_conf}\" -DKERNEL26_SUPPORT \ + -DKERNEL26_HAS_KAME_DUPLICATES -DPLUTO -DKLIPS -DDEBUG \ + $(am__append_1) $(am__append_2) $(am__append_3) \ + $(am__append_4) $(am__append_5) $(am__append_6) \ + $(am__append_8) +pluto_LDADD = $(LIBSTRONGSWANDIR)/libstrongswan.la \ + $(LIBFREESWANDIR)/libfreeswan.a -lresolv -lpthread $(DLLIB) \ + $(am__append_7) _pluto_adns_LDADD = \ $(LIBFREESWANDIR)/libfreeswan.a \ --lresolv -ldl +-lresolv $(DLLIB) dist_man_MANS = pluto.8 ipsec.secrets.5 all: all-am @@ -357,8 +343,8 @@ $(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 \ - && exit 0; \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ @@ -426,7 +412,6 @@ distclean-compile: @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)/asn1.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@ @@ -438,19 +423,10 @@ distclean-compile: @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)/dsa.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elgamal.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)/gcryptfix.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg_aes.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg_blowfish.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg_serpent.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg_sha2.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg_twofish.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alginit.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@ @@ -460,24 +436,16 @@ distclean-compile: @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)/md2.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modecfg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp_defs.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)/pem.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgp.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs1.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgpcert.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs7.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plutomain.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/primegen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcv_whack.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rnd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smallprime.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@ @@ -508,90 +476,6 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< -ike_alg_aes.o: alg/ike_alg_aes.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_aes.o -MD -MP -MF $(DEPDIR)/ike_alg_aes.Tpo -c -o ike_alg_aes.o `test -f 'alg/ike_alg_aes.c' || echo '$(srcdir)/'`alg/ike_alg_aes.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alg_aes.Tpo $(DEPDIR)/ike_alg_aes.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_aes.c' object='ike_alg_aes.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 ike_alg_aes.o `test -f 'alg/ike_alg_aes.c' || echo '$(srcdir)/'`alg/ike_alg_aes.c - -ike_alg_aes.obj: alg/ike_alg_aes.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_aes.obj -MD -MP -MF $(DEPDIR)/ike_alg_aes.Tpo -c -o ike_alg_aes.obj `if test -f 'alg/ike_alg_aes.c'; then $(CYGPATH_W) 'alg/ike_alg_aes.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_aes.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alg_aes.Tpo $(DEPDIR)/ike_alg_aes.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_aes.c' object='ike_alg_aes.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 ike_alg_aes.obj `if test -f 'alg/ike_alg_aes.c'; then $(CYGPATH_W) 'alg/ike_alg_aes.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_aes.c'; fi` - -ike_alg_blowfish.o: alg/ike_alg_blowfish.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_blowfish.o -MD -MP -MF $(DEPDIR)/ike_alg_blowfish.Tpo -c -o ike_alg_blowfish.o `test -f 'alg/ike_alg_blowfish.c' || echo '$(srcdir)/'`alg/ike_alg_blowfish.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alg_blowfish.Tpo $(DEPDIR)/ike_alg_blowfish.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_blowfish.c' object='ike_alg_blowfish.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 ike_alg_blowfish.o `test -f 'alg/ike_alg_blowfish.c' || echo '$(srcdir)/'`alg/ike_alg_blowfish.c - -ike_alg_blowfish.obj: alg/ike_alg_blowfish.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_blowfish.obj -MD -MP -MF $(DEPDIR)/ike_alg_blowfish.Tpo -c -o ike_alg_blowfish.obj `if test -f 'alg/ike_alg_blowfish.c'; then $(CYGPATH_W) 'alg/ike_alg_blowfish.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_blowfish.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alg_blowfish.Tpo $(DEPDIR)/ike_alg_blowfish.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_blowfish.c' object='ike_alg_blowfish.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 ike_alg_blowfish.obj `if test -f 'alg/ike_alg_blowfish.c'; then $(CYGPATH_W) 'alg/ike_alg_blowfish.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_blowfish.c'; fi` - -ike_alg_twofish.o: alg/ike_alg_twofish.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_twofish.o -MD -MP -MF $(DEPDIR)/ike_alg_twofish.Tpo -c -o ike_alg_twofish.o `test -f 'alg/ike_alg_twofish.c' || echo '$(srcdir)/'`alg/ike_alg_twofish.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alg_twofish.Tpo $(DEPDIR)/ike_alg_twofish.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_twofish.c' object='ike_alg_twofish.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 ike_alg_twofish.o `test -f 'alg/ike_alg_twofish.c' || echo '$(srcdir)/'`alg/ike_alg_twofish.c - -ike_alg_twofish.obj: alg/ike_alg_twofish.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_twofish.obj -MD -MP -MF $(DEPDIR)/ike_alg_twofish.Tpo -c -o ike_alg_twofish.obj `if test -f 'alg/ike_alg_twofish.c'; then $(CYGPATH_W) 'alg/ike_alg_twofish.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_twofish.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alg_twofish.Tpo $(DEPDIR)/ike_alg_twofish.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_twofish.c' object='ike_alg_twofish.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 ike_alg_twofish.obj `if test -f 'alg/ike_alg_twofish.c'; then $(CYGPATH_W) 'alg/ike_alg_twofish.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_twofish.c'; fi` - -ike_alg_serpent.o: alg/ike_alg_serpent.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_serpent.o -MD -MP -MF $(DEPDIR)/ike_alg_serpent.Tpo -c -o ike_alg_serpent.o `test -f 'alg/ike_alg_serpent.c' || echo '$(srcdir)/'`alg/ike_alg_serpent.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alg_serpent.Tpo $(DEPDIR)/ike_alg_serpent.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_serpent.c' object='ike_alg_serpent.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 ike_alg_serpent.o `test -f 'alg/ike_alg_serpent.c' || echo '$(srcdir)/'`alg/ike_alg_serpent.c - -ike_alg_serpent.obj: alg/ike_alg_serpent.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_serpent.obj -MD -MP -MF $(DEPDIR)/ike_alg_serpent.Tpo -c -o ike_alg_serpent.obj `if test -f 'alg/ike_alg_serpent.c'; then $(CYGPATH_W) 'alg/ike_alg_serpent.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_serpent.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alg_serpent.Tpo $(DEPDIR)/ike_alg_serpent.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_serpent.c' object='ike_alg_serpent.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 ike_alg_serpent.obj `if test -f 'alg/ike_alg_serpent.c'; then $(CYGPATH_W) 'alg/ike_alg_serpent.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_serpent.c'; fi` - -ike_alg_sha2.o: alg/ike_alg_sha2.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_sha2.o -MD -MP -MF $(DEPDIR)/ike_alg_sha2.Tpo -c -o ike_alg_sha2.o `test -f 'alg/ike_alg_sha2.c' || echo '$(srcdir)/'`alg/ike_alg_sha2.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alg_sha2.Tpo $(DEPDIR)/ike_alg_sha2.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_sha2.c' object='ike_alg_sha2.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 ike_alg_sha2.o `test -f 'alg/ike_alg_sha2.c' || echo '$(srcdir)/'`alg/ike_alg_sha2.c - -ike_alg_sha2.obj: alg/ike_alg_sha2.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alg_sha2.obj -MD -MP -MF $(DEPDIR)/ike_alg_sha2.Tpo -c -o ike_alg_sha2.obj `if test -f 'alg/ike_alg_sha2.c'; then $(CYGPATH_W) 'alg/ike_alg_sha2.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_sha2.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alg_sha2.Tpo $(DEPDIR)/ike_alg_sha2.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alg_sha2.c' object='ike_alg_sha2.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 ike_alg_sha2.obj `if test -f 'alg/ike_alg_sha2.c'; then $(CYGPATH_W) 'alg/ike_alg_sha2.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alg_sha2.c'; fi` - -ike_alginit.o: alg/ike_alginit.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alginit.o -MD -MP -MF $(DEPDIR)/ike_alginit.Tpo -c -o ike_alginit.o `test -f 'alg/ike_alginit.c' || echo '$(srcdir)/'`alg/ike_alginit.c -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alginit.Tpo $(DEPDIR)/ike_alginit.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alginit.c' object='ike_alginit.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 ike_alginit.o `test -f 'alg/ike_alginit.c' || echo '$(srcdir)/'`alg/ike_alginit.c - -ike_alginit.obj: alg/ike_alginit.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_alginit.obj -MD -MP -MF $(DEPDIR)/ike_alginit.Tpo -c -o ike_alginit.obj `if test -f 'alg/ike_alginit.c'; then $(CYGPATH_W) 'alg/ike_alginit.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alginit.c'; fi` -@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/ike_alginit.Tpo $(DEPDIR)/ike_alginit.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='alg/ike_alginit.c' object='ike_alginit.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 ike_alginit.obj `if test -f 'alg/ike_alginit.c'; then $(CYGPATH_W) 'alg/ike_alginit.c'; else $(CYGPATH_W) '$(srcdir)/alg/ike_alginit.c'; fi` - mostlyclean-libtool: -rm -f *.lo @@ -608,8 +492,8 @@ install-man5: $(man5_MANS) $(man_MANS) esac; \ done; \ for i in $$list; do \ - if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ - else file=$$i; fi; \ + if test -f $$i; then file=$$i; \ + else file=$(srcdir)/$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 5*) ;; \ @@ -653,8 +537,8 @@ install-man8: $(man8_MANS) $(man_MANS) esac; \ done; \ for i in $$list; do \ - if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ - else file=$$i; fi; \ + if test -f $$i; then file=$$i; \ + else file=$(srcdir)/$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ case "$$ext" in \ 8*) ;; \ @@ -693,7 +577,7 @@ ID: $(HEADERS) $(SOURCES) $(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; nonemtpy = 1; } \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS @@ -871,9 +755,6 @@ uninstall-man: uninstall-man5 uninstall-man8 uninstall-ipsecPROGRAMS uninstall-man uninstall-man5 \ uninstall-man8 - -oid.o : $(LIBSTRONGSWANDIR)/asn1/oid.c $(LIBSTRONGSWANDIR)/asn1/oid.h - $(COMPILE) -c -o $@ $< # 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/TODO b/src/pluto/TODO deleted file mode 100644 index 1c22b2f5c..000000000 --- a/src/pluto/TODO +++ /dev/null @@ -1,129 +0,0 @@ -Pluto TODO list -=============== -RCSID $Id: TODO 3269 2007-10-08 20:03:02Z andreas $ - -- should all log entries that are for errors say ERROR? - -- Add a "plug-in" facility so that others can add features without - changing the mainline code. This is how X509/LDAP/biometric stuff - might be added. - -- (internal change only) routines for outputting payloads should plug - "np" into the previous payload so that a payload generating routine - need not know what the next payload will be. This may be more bother - than it is worth. - -- notifications, in and out - + delete - + first contact - + last contact? (not part of drafts, but would be nice) - -- Make DNS usage for asynchronous (non-blocking) - + looking up KEY and TXT records during negotiation - + perhaps not for whack command arguments and ipsec.secrets since the - library code uses gethostbyname - -- check that ipsec auto and whack to agree on what is worth reporting - -- Should Pluto (rather than ipsec manual) install %passthrough conns? - That way Pluto would know of them. - -- For responding to Road Warriors, how can we decide if the RW has - gone away? The rekeying event is perhaps too imprecise. Even if - rekeying event is good enough, how do we know if the route should be - torn down? Perhaps limiting a Phase 1 ID to one IP address would - help (limiting a client subnet to one peer already helps). Perhaps - (in some rate-limited way) we can take an ICMP host unreachable - as a hint to do some authenticated and reliable probe. - -- it is annoying that Pluto and auto have different models for public keys. - + auto specifies one per connection - + Pluto allows one to be specified per id - Two connections with the same id are going to use the same key: - the one of the last conn to be added! - - I think auto ought to be fixed. It is hard for Pluto to warn when - there is a conflict since the deletion of a connection doesn't - prompt auto to tell pluto to delete the public key. - -- different connections with the same host IP addresses are randomly - interchangeable until the ID payload is received. At least for the - Responder case (and eventually for the opportunistic Initiator). - Worse, all Road Warriors must be considered to have the - indistinguishable IP addresses. This affects ISAKMP SA negotiation. - Currently, there is little flexibility in this negotiation, so the - problem is limited to the specification of acceptable authentication - method(s). Correct, but more work than seems worthwhile, would be - to select the conn based on what is proposed. - - Warning about such confusion at connection definition time isn't great - because there is no confusion when explicitly initiated (a particular - conn is specified). Warning for a Road Warrior conn is possible - since it cannot be initiated (and has been implemented). - -- characterize and ameliorate DOS attacks. Lots of rate limiting. - -- look at John Denker's wish list: http://www.quintillion.com/moat/wish.list - -- use of random numbers needs to be audited. - -- unknown (not just unimplemented) transforms cause a negotiation to - fail. Only the transform should be rejected. - -- we need better policy control. Our present flags need to be - modulated (forbid, allow, offer, require) - -- HS will specify how --copyright and --version should behave - -- HS will initiate project-wide terminology replacing ISAKMP SA, IPSEC - SA, Protection Suite, Phase 1, Main Mode, Phase 2, Quick Mode, ... - Simplicity and clarity will be a goal. - -- interface discovery ought to match what is specified in ipsec.conf. - This probably means grokking /proc/net/ipsec_tncfg. Documented in - ipsec_tncfg(5). This won't do for Hugh's debugging setup. - - -Protocol Issues -=============== - -Notification and delete payloads seem to be "escape hatches" for the -protocols. As such, anything implemented using them seems to be -kludged without being well designed or well situated or well -constrained in the protocols. Often the precise meaning (if any) or -usage is under specified. An implementation is allowed to ignore -them, so they cannot really matter (but they too often do). Their -specification ought to be scrutinized by a protocol guru. - -Any extra payload in last main mode message is not protected (not -authenticated by hash). - -Should notification payloads be interpreted before or after the normal -payloads (i.e. understood in the context of, executed in the context of). - -What is the precise result of an INITIAL_CONNECTION? What is a -"system" (eg. does Phase 1 Identity count)? What is "earlier" or -"before" (simultaneous negotiation is possible, with time being only a -partial order)? Could it be used for FINAL_CONTACT (needed too)? - -Blasting out a pile of UDP messages, especially to a particular -destination, is likely to provoke message loss. The exchanges are -just that, so they individually are self-throttling. But what about -multiple exchanges simultaneously? What about notifications (example: -when shutting down, a flurry of delete notifications are likely). -Should the RFCs be designed to protect against this problem? - -draft-jenkins-ipsec-rekeying-03.txt rekeying is way too complicated. -Our solution looks sound and simple (we have the Responder install the -incoming IPSEC SA before sending its first reply). In "2.2.1.4 -Responder Pre-Set-up Security Hole", the draft claims that setting up -the IPSEC SA early leaves the Responder open to replay attacks. I -think that this is wrong: the Message Id, since it must not be reused, -serves to prove that this isn't a replay. - -The details for notification messages suggested by -draft-ietf-ipsec-notifymsg-02.txt are over-complicated, just to make -them machine-comprehensible. I think this is over-engineering, -justified only if another level of negotiation is contemplated (ugh!). -Plain text is probably sufficient for informing humans (I admit that -there is a problem with I18N). diff --git a/src/pluto/ac.c b/src/pluto/ac.c index 6745ff484..3b5df9738 100644 --- a/src/pluto/ac.c +++ b/src/pluto/ac.c @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: ac.c 4632 2008-11-11 18:37:19Z martin $ */ #include <stdlib.h> @@ -25,10 +23,11 @@ #include <freeswan.h> -#include "constants.h" -#include "defs.h" -#include "asn1.h" +#include <utils.h> +#include <asn1/asn1.h> +#include <asn1/asn1_parser.h> #include <asn1/oid.h> + #include "ac.h" #include "x509.h" #include "crl.h" @@ -38,971 +37,947 @@ #include "whack.h" #include "fetch.h" -/* chained list of X.509 attribute certificates */ - +/** + * Chained list of X.509 attribute certificates + */ static x509acert_t *x509acerts = NULL; -/* chained list of ietfAttributes */ - +/** + * Chained list of ietfAttributes + */ static ietfAttrList_t *ietfAttributes = NULL; -/* ASN.1 definition of ietfAttrSyntax */ - +/** + * ASN.1 definition of ietfAttrSyntax + */ static const asn1Object_t ietfAttrSyntaxObjects[] = { - { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | - ASN1_BODY }, /* 1 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ - { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */ - { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT | - ASN1_BODY }, /* 4 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ - { 2, "oid", ASN1_OID, ASN1_OPT | - ASN1_BODY }, /* 6 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ - { 2, "string", ASN1_UTF8STRING, ASN1_OPT | - ASN1_BODY }, /* 8 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 1, "end loop", ASN1_EOC, ASN1_END } /* 10 */ + { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | + ASN1_BODY }, /* 1 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ + { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */ + { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT | + ASN1_BODY }, /* 4 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ + { 2, "oid", ASN1_OID, ASN1_OPT | + ASN1_BODY }, /* 6 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ + { 2, "string", ASN1_UTF8STRING, ASN1_OPT | + ASN1_BODY }, /* 8 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ + { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; -#define IETF_ATTR_OCTETS 4 -#define IETF_ATTR_OID 6 -#define IETF_ATTR_STRING 8 -#define IETF_ATTR_ROOF 11 - -/* ASN.1 definition of roleSyntax */ +#define IETF_ATTR_OCTETS 4 +#define IETF_ATTR_OID 6 +#define IETF_ATTR_STRING 8 +/** + * ASN.1 definition of roleSyntax + */ static const asn1Object_t roleSyntaxObjects[] = { - { 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | - ASN1_OBJ }, /* 1 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ - { 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ } /* 3 */ + { 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | + ASN1_OBJ }, /* 1 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ + { 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ }, /* 3 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; -#define ROLE_ROOF 4 - -/* ASN.1 definition of an X509 attribute certificate */ - +/** + * ASN.1 definition of an X509 attribute certificate + */ static const asn1Object_t acObjects[] = { - { 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ - { 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "version", ASN1_INTEGER, ASN1_DEF | - ASN1_BODY }, /* 2 */ - { 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ - { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */ - { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ - { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */ - { 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | - ASN1_BODY }, /* 7 */ - { 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ - { 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT | - ASN1_OBJ }, /* 10 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ - { 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */ - { 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13*/ - { 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT | - ASN1_BODY }, /* 14 */ - { 4, "end opt", ASN1_EOC, ASN1_END }, /* 15*/ - { 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */ - { 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */ - { 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT | - ASN1_OBJ }, /* 19 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ - { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */ - { 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ - { 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */ - { 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */ - { 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | - ASN1_BODY }, /* 25 */ - { 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */ - { 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */ - { 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */ - { 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */ - { 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT | - ASN1_BODY }, /* 31 */ - { 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */ - { 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */ - { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */ - { 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */ - { 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */ - { 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */ - { 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */ - { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */ - { 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */ - { 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */ - { 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */ - { 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */ - { 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */ - { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */ - { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */ - { 4, "critical", ASN1_BOOLEAN, ASN1_DEF | - ASN1_BODY }, /* 50 */ - { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */ - { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 54 */ + { 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "version", ASN1_INTEGER, ASN1_DEF | + ASN1_BODY }, /* 2 */ + { 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ + { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */ + { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ + { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */ + { 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | + ASN1_BODY }, /* 7 */ + { 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */ + { 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ + { 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT | + ASN1_OBJ }, /* 10 */ + { 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ + { 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */ + { 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13 */ + { 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT | + ASN1_BODY }, /* 14 */ + { 4, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ + { 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */ + { 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */ + { 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */ + { 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT | + ASN1_OBJ }, /* 19 */ + { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ + { 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */ + { 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ + { 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */ + { 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */ + { 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT | + ASN1_BODY }, /* 25 */ + { 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ + { 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */ + { 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */ + { 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */ + { 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */ + { 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT | + ASN1_BODY }, /* 31 */ + { 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */ + { 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */ + { 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */ + { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */ + { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */ + { 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */ + { 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */ + { 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */ + { 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */ + { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */ + { 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */ + { 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */ + { 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */ + { 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */ + { 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */ + { 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */ + { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */ + { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */ + { 4, "critical", ASN1_BOOLEAN, ASN1_DEF | + ASN1_BODY }, /* 50 */ + { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */ + { 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */ + { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 54 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; -#define AC_OBJ_CERTIFICATE 0 -#define AC_OBJ_CERTIFICATE_INFO 1 -#define AC_OBJ_VERSION 2 -#define AC_OBJ_HOLDER_ISSUER 5 -#define AC_OBJ_HOLDER_SERIAL 6 -#define AC_OBJ_ENTITY_NAME 10 -#define AC_OBJ_ISSUER_NAME 19 -#define AC_OBJ_ISSUER 23 -#define AC_OBJ_SIG_ALG 35 -#define AC_OBJ_SERIAL_NUMBER 36 -#define AC_OBJ_NOT_BEFORE 38 -#define AC_OBJ_NOT_AFTER 39 -#define AC_OBJ_ATTRIBUTE_TYPE 42 -#define AC_OBJ_ATTRIBUTE_VALUE 44 -#define AC_OBJ_EXTN_ID 49 -#define AC_OBJ_CRITICAL 50 -#define AC_OBJ_EXTN_VALUE 51 -#define AC_OBJ_ALGORITHM 53 -#define AC_OBJ_SIGNATURE 54 -#define AC_OBJ_ROOF 55 +#define AC_OBJ_CERTIFICATE 0 +#define AC_OBJ_CERTIFICATE_INFO 1 +#define AC_OBJ_VERSION 2 +#define AC_OBJ_HOLDER_ISSUER 5 +#define AC_OBJ_HOLDER_SERIAL 6 +#define AC_OBJ_ENTITY_NAME 10 +#define AC_OBJ_ISSUER_NAME 19 +#define AC_OBJ_ISSUER 23 +#define AC_OBJ_SIG_ALG 35 +#define AC_OBJ_SERIAL_NUMBER 36 +#define AC_OBJ_NOT_BEFORE 38 +#define AC_OBJ_NOT_AFTER 39 +#define AC_OBJ_ATTRIBUTE_TYPE 42 +#define AC_OBJ_ATTRIBUTE_VALUE 44 +#define AC_OBJ_EXTN_ID 49 +#define AC_OBJ_CRITICAL 50 +#define AC_OBJ_EXTN_VALUE 51 +#define AC_OBJ_ALGORITHM 53 +#define AC_OBJ_SIGNATURE 54 const x509acert_t empty_ac = { - NULL , /* *next */ - 0 , /* installed */ - { NULL, 0 }, /* certificate */ - { NULL, 0 }, /* certificateInfo */ - 1 , /* version */ - /* holder */ - /* baseCertificateID */ - { NULL, 0 }, /* holderIssuer */ - { NULL, 0 }, /* holderSerial */ - /* entityName */ - { NULL, 0 }, /* generalNames */ - /* v2Form */ - { NULL, 0 }, /* issuerName */ - /* signature */ - OID_UNKNOWN, /* sigAlg */ - { NULL, 0 }, /* serialNumber */ - /* attrCertValidityPeriod */ - 0 , /* notBefore */ - 0 , /* notAfter */ - /* attributes */ - NULL , /* charging */ - NULL , /* groups */ - /* extensions */ - { NULL, 0 }, /* authKeyID */ - { NULL, 0 }, /* authKeySerialNumber */ - FALSE , /* noRevAvail */ - /* signatureAlgorithm */ - OID_UNKNOWN, /* algorithm */ - { NULL, 0 }, /* signature */ + NULL , /* *next */ + 0 , /* installed */ + { NULL, 0 }, /* certificate */ + { NULL, 0 }, /* certificateInfo */ + 1 , /* version */ + /* holder */ + /* baseCertificateID */ + { NULL, 0 }, /* holderIssuer */ + { NULL, 0 }, /* holderSerial */ + /* entityName */ + { NULL, 0 }, /* generalNames */ + /* v2Form */ + { NULL, 0 }, /* issuerName */ + /* signature */ + OID_UNKNOWN, /* sigAlg */ + { NULL, 0 }, /* serialNumber */ + /* attrCertValidityPeriod */ + 0 , /* notBefore */ + 0 , /* notAfter */ + /* attributes */ + NULL , /* charging */ + NULL , /* groups */ + /* extensions */ + { NULL, 0 }, /* authKeyID */ + { NULL, 0 }, /* authKeySerialNumber */ + FALSE , /* noRevAvail */ + /* signatureAlgorithm */ + OID_UNKNOWN, /* algorithm */ + { NULL, 0 }, /* signature */ }; -/* compare two ietfAttributes, returns zero if a equals b +/** + * compare two ietfAttributes, returns zero if a equals b * negative/positive if a is earlier/later in the alphabet than b */ -static int -cmp_ietfAttr(ietfAttr_t *a,ietfAttr_t *b) +static int cmp_ietfAttr(ietfAttr_t *a,ietfAttr_t *b) { - int cmp_len, len, cmp_value; + int cmp_len, len, cmp_value; - /* cannot compare OID with STRING or OCTETS attributes */ - if (a->kind == IETF_ATTRIBUTE_OID && b->kind != IETF_ATTRIBUTE_OID) - return 1; - - cmp_len = a->value.len - b->value.len; - len = (cmp_len < 0)? a->value.len : b->value.len; - cmp_value = memcmp(a->value.ptr, b->value.ptr, len); + /* cannot compare OID with STRING or OCTETS attributes */ + if (a->kind == IETF_ATTRIBUTE_OID && b->kind != IETF_ATTRIBUTE_OID) + return 1; + + cmp_len = a->value.len - b->value.len; + len = (cmp_len < 0)? a->value.len : b->value.len; + cmp_value = memcmp(a->value.ptr, b->value.ptr, len); - return (cmp_value == 0)? cmp_len : cmp_value; + return (cmp_value == 0)? cmp_len : cmp_value; } -/* +/** * add an ietfAttribute to the chained list */ -static ietfAttr_t* -add_ietfAttr(ietfAttr_t *attr) +static ietfAttr_t* add_ietfAttr(ietfAttr_t *attr) { - ietfAttrList_t **listp = &ietfAttributes; - ietfAttrList_t *list = *listp; - int cmp = -1; - - while (list != NULL) - { - cmp = cmp_ietfAttr(attr, list->attr); - if (cmp <= 0) - break; - listp = &list->next; - list = *listp; - } - - if (cmp == 0) - { - /* attribute already exists, increase count */ - pfree(attr); - list->attr->count++; - return list->attr; - } - else - { - ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList"); - - /* new attribute, unshare value */ - attr->value.ptr = clone_bytes(attr->value.ptr, attr->value.len - , "attr value"); - attr->count = 1; - time(&attr->installed); - - el->attr = attr; - el->next = list; - *listp = el; - - return attr; - } + ietfAttrList_t **listp = &ietfAttributes; + ietfAttrList_t *list = *listp; + int cmp = -1; + + while (list != NULL) + { + cmp = cmp_ietfAttr(attr, list->attr); + if (cmp <= 0) + break; + listp = &list->next; + list = *listp; + } + + if (cmp == 0) + { + /* attribute already exists, increase count */ + free(attr); + list->attr->count++; + return list->attr; + } + else + { + ietfAttrList_t *el = malloc_thing(ietfAttrList_t); + + /* new attribute, unshare value */ + attr->value = chunk_clone(attr->value); + attr->count = 1; + time(&attr->installed); + + el->attr = attr; + el->next = list; + *listp = el; + + return attr; + } } -/* +/** * decodes a comma separated list of group attributes */ -void -decode_groups(char *groups, ietfAttrList_t **listp) +void decode_groups(char *groups, ietfAttrList_t **listp) { - if (groups == NULL) - return; + if (groups == NULL) + return; - while (strlen(groups) > 0) - { - char *end; - char *next = strchr(groups, ','); + while (strlen(groups) > 0) + { + char *end; + char *next = strchr(groups, ','); - if (next == NULL) - end = next = groups + strlen(groups); - else - end = next++; + if (next == NULL) + end = next = groups + strlen(groups); + else + end = next++; - /* eat preceeding whitespace */ - while (groups < end && *groups == ' ') - groups++; + /* eat preceeding whitespace */ + while (groups < end && *groups == ' ') + groups++; - /* eat trailing whitespace */ - while (end > groups && *(end-1) == ' ') - end--; + /* eat trailing whitespace */ + while (end > groups && *(end-1) == ' ') + end--; - if (groups < end) - { - ietfAttr_t *attr = alloc_thing(ietfAttr_t, "ietfAttr"); - ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList"); + if (groups < end) + { + ietfAttr_t *attr = malloc_thing(ietfAttr_t); + ietfAttrList_t *el = malloc_thing(ietfAttrList_t); - attr->kind = IETF_ATTRIBUTE_STRING; - attr->value.ptr = groups; - attr->value.len = end - groups; - attr->count = 0; + attr->kind = IETF_ATTRIBUTE_STRING; + attr->value.ptr = groups; + attr->value.len = end - groups; + attr->count = 0; - el->attr = add_ietfAttr(attr); - el->next = *listp; - *listp = el; - } + el->attr = add_ietfAttr(attr); + el->next = *listp; + *listp = el; + } - groups = next; - } + groups = next; + } } -static bool -same_attribute(const ietfAttr_t *a, const ietfAttr_t *b) +static bool same_attribute(const ietfAttr_t *a, const ietfAttr_t *b) { - return (a->kind == b->kind && a->value.len == b->value.len - && memcmp(a->value.ptr, b->value.ptr, b->value.len) == 0); + return (a->kind == b->kind && a->value.len == b->value.len + && memeq(a->value.ptr, b->value.ptr, b->value.len)); } -bool -group_membership(const ietfAttrList_t *peer_list - , const char *conn - , const ietfAttrList_t *conn_list) +bool group_membership(const ietfAttrList_t *peer_list + , const char *conn + , const ietfAttrList_t *conn_list) { - if (conn_list == NULL) - return TRUE; - - while (peer_list != NULL) - { - const ietfAttr_t *peer_attr = peer_list->attr; - const ietfAttrList_t *list = conn_list; + if (conn_list == NULL) + return TRUE; - while (list != NULL) + while (peer_list != NULL) { - ietfAttr_t *conn_attr = list->attr; + const ietfAttr_t *peer_attr = peer_list->attr; + const ietfAttrList_t *list = conn_list; - if (same_attribute(conn_attr, peer_attr)) - { + while (list != NULL) + { + ietfAttr_t *conn_attr = list->attr; + + if (same_attribute(conn_attr, peer_attr)) + { + DBG(DBG_CONTROL, + DBG_log("%s: peer matches group '%.*s'" + , conn + , (int)peer_attr->value.len, peer_attr->value.ptr) + ) + return TRUE; + } + list = list->next; + } + peer_list = peer_list->next; + } DBG(DBG_CONTROL, - DBG_log("%s: peer matches group '%.*s'" - , conn - , (int)peer_attr->value.len, peer_attr->value.ptr) + DBG_log("%s: peer doesn't match any group", conn) ) - return TRUE; - } - list = list->next; - } - peer_list = peer_list->next; - } - DBG(DBG_CONTROL, - DBG_log("%s: peer doesn't match any group", conn) - ) - return FALSE; + return FALSE; } - -void -unshare_ietfAttrList(ietfAttrList_t **listp) +void unshare_ietfAttrList(ietfAttrList_t **listp) { - ietfAttrList_t *list = *listp; - - while (list != NULL) - { - ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList"); - - el->attr = list->attr; - el->attr->count++; - el->next = NULL; - *listp = el; - listp = &el->next; - list = list->next; - } + ietfAttrList_t *list = *listp; + + while (list != NULL) + { + ietfAttrList_t *el = malloc_thing(ietfAttrList_t); + + el->attr = list->attr; + el->attr->count++; + el->next = NULL; + *listp = el; + listp = &el->next; + list = list->next; + } } -/* - * parses ietfAttrSyntax +/** + * Parses ietfAttrSyntax */ -static ietfAttrList_t* -parse_ietfAttrSyntax(chunk_t blob, int level0) +static ietfAttrList_t* parse_ietfAttrSyntax(chunk_t blob, int level0) { - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - ietfAttrList_t *list = NULL; + asn1_parser_t *parser; + chunk_t object; + int objectID; - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); + ietfAttrList_t *list = NULL; - while (objectID < IETF_ATTR_ROOF) - { - if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx)) - return NULL; + parser = asn1_parser_create(ietfAttrSyntaxObjects, blob); + parser->set_top_level(parser, level0); - switch (objectID) + while (parser->iterate(parser, &objectID, &object)) { - case IETF_ATTR_OCTETS: - case IETF_ATTR_OID: - case IETF_ATTR_STRING: - { - ietfAttr_t *attr = alloc_thing(ietfAttr_t, "ietfAttr"); - ietfAttrList_t *el = alloc_thing(ietfAttrList_t, "ietfAttrList"); - - attr->kind = (objectID - IETF_ATTR_OCTETS) / 2; - attr->value = object; - attr->count = 0; - - el->attr = add_ietfAttr(attr); - el->next = list; - list = el; - } - break; - default: - break; + switch (objectID) + { + case IETF_ATTR_OCTETS: + case IETF_ATTR_OID: + case IETF_ATTR_STRING: + { + ietfAttr_t *attr = malloc_thing(ietfAttr_t); + ietfAttrList_t *el = malloc_thing(ietfAttrList_t); + + attr->kind = (objectID - IETF_ATTR_OCTETS) / 2; + attr->value = object; + attr->count = 0; + + el->attr = add_ietfAttr(attr); + el->next = list; + list = el; + } + break; + default: + break; + } } - objectID++; - } - return list; + parser->destroy(parser); + return list; } -/* - * parses roleSyntax + +/** + * Parses roleSyntax */ -static void -parse_roleSyntax(chunk_t blob, int level0) +static void parse_roleSyntax(chunk_t blob, int level0) { - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; + asn1_parser_t *parser; + chunk_t object; + int objectID; - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); + parser = asn1_parser_create(roleSyntaxObjects, blob); + parser->set_top_level(parser, level0); - while (objectID < ROLE_ROOF) - { - if (!extract_object(roleSyntaxObjects, &objectID, &object, &level, &ctx)) - return; - - switch (objectID) { - default: - break; + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + default: + break; + } } - objectID++; - } + parser->destroy(parser); } -/* +/** * Parses an X.509 attribute certificate */ -bool -parse_ac(chunk_t blob, x509acert_t *ac) +bool parse_ac(chunk_t blob, x509acert_t *ac) { - asn1_ctx_t ctx; - bool critical; - chunk_t object; - u_int level; - int objectID = 0; - int type = OID_UNKNOWN; - int extn_oid = OID_UNKNOWN; - - asn1_init(&ctx, blob, 0, FALSE, DBG_RAW); + asn1_parser_t *parser; + chunk_t object; + int objectID; + int type = OID_UNKNOWN; + int extn_oid = OID_UNKNOWN; + bool success = FALSE; + bool critical; - while (objectID < AC_OBJ_ROOF) { + parser = asn1_parser_create(acObjects, blob); - if (!extract_object(acObjects, &objectID, &object, &level, &ctx)) - return FALSE; + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser)+1; - /* those objects which will parsed further need the next higher level */ - level++; + switch (objectID) + { + case AC_OBJ_CERTIFICATE: + ac->certificate = object; + break; + case AC_OBJ_CERTIFICATE_INFO: + ac->certificateInfo = object; + break; + case AC_OBJ_VERSION: + ac->version = (object.len) ? (1 + (u_int)*object.ptr) : 1; + DBG(DBG_PARSING, + DBG_log(" v%d", ac->version); + ) + if (ac->version != 2) + { + plog("v%d attribute certificates are not supported" + , ac->version); + goto end; + } + break; + case AC_OBJ_HOLDER_ISSUER: + ac->holderIssuer = get_directoryName(object, level, FALSE); + break; + case AC_OBJ_HOLDER_SERIAL: + ac->holderSerial = object; + break; + case AC_OBJ_ENTITY_NAME: + ac->entityName = get_directoryName(object, level, TRUE); + break; + case AC_OBJ_ISSUER_NAME: + ac->issuerName = get_directoryName(object, level, FALSE); + break; + case AC_OBJ_SIG_ALG: + ac->sigAlg = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case AC_OBJ_SERIAL_NUMBER: + ac->serialNumber = object; + break; + case AC_OBJ_NOT_BEFORE: + ac->notBefore = asn1_to_time(&object, ASN1_GENERALIZEDTIME); + break; + case AC_OBJ_NOT_AFTER: + ac->notAfter = asn1_to_time(&object, ASN1_GENERALIZEDTIME); + break; + case AC_OBJ_ATTRIBUTE_TYPE: + type = asn1_known_oid(object); + break; + case AC_OBJ_ATTRIBUTE_VALUE: + { + switch (type) { + case OID_AUTHENTICATION_INFO: + DBG(DBG_PARSING, + DBG_log(" need to parse authenticationInfo") + ) + break; + case OID_ACCESS_IDENTITY: + DBG(DBG_PARSING, + DBG_log(" need to parse accessIdentity") + ) + break; + case OID_CHARGING_IDENTITY: + ac->charging = parse_ietfAttrSyntax(object, level); + break; + case OID_GROUP: + ac->groups = parse_ietfAttrSyntax(object, level); + break; + case OID_ROLE: + parse_roleSyntax(object, level); + break; + default: + break; + } + } + break; + case AC_OBJ_EXTN_ID: + extn_oid = asn1_known_oid(object); + break; + case AC_OBJ_CRITICAL: + critical = object.len && *object.ptr; + DBG(DBG_PARSING, + DBG_log(" %s",(critical)?"TRUE":"FALSE"); + ) + break; + case AC_OBJ_EXTN_VALUE: + { + switch (extn_oid) { + case OID_CRL_DISTRIBUTION_POINTS: + DBG(DBG_PARSING, + DBG_log(" need to parse crlDistributionPoints") + ) + break; + case OID_AUTHORITY_KEY_ID: + parse_authorityKeyIdentifier(object, level + , &ac->authKeyID, &ac->authKeySerialNumber); + break; + case OID_TARGET_INFORMATION: + DBG(DBG_PARSING, + DBG_log(" need to parse targetInformation") + ) + break; + case OID_NO_REV_AVAIL: + ac->noRevAvail = TRUE; + break; + default: + break; + } + } + break; + case AC_OBJ_ALGORITHM: + ac->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case AC_OBJ_SIGNATURE: + ac->signature = object; + break; - switch (objectID) - { - case AC_OBJ_CERTIFICATE: - ac->certificate = object; - break; - case AC_OBJ_CERTIFICATE_INFO: - ac->certificateInfo = object; - break; - case AC_OBJ_VERSION: - ac->version = (object.len) ? (1 + (u_int)*object.ptr) : 1; - DBG(DBG_PARSING, - DBG_log(" v%d", ac->version); - ) - if (ac->version != 2) - { - plog("v%d attribute certificates are not supported" - , ac->version); - return FALSE; - } - break; - case AC_OBJ_HOLDER_ISSUER: - ac->holderIssuer = get_directoryName(object, level, FALSE); - break; - case AC_OBJ_HOLDER_SERIAL: - ac->holderSerial = object; - break; - case AC_OBJ_ENTITY_NAME: - ac->entityName = get_directoryName(object, level, TRUE); - break; - case AC_OBJ_ISSUER_NAME: - ac->issuerName = get_directoryName(object, level, FALSE); - break; - case AC_OBJ_SIG_ALG: - ac->sigAlg = parse_algorithmIdentifier(object, level, NULL); - break; - case AC_OBJ_SERIAL_NUMBER: - ac->serialNumber = object; - break; - case AC_OBJ_NOT_BEFORE: - ac->notBefore = asn1totime(&object, ASN1_GENERALIZEDTIME); - break; - case AC_OBJ_NOT_AFTER: - ac->notAfter = asn1totime(&object, ASN1_GENERALIZEDTIME); - break; - case AC_OBJ_ATTRIBUTE_TYPE: - type = known_oid(object); - break; - case AC_OBJ_ATTRIBUTE_VALUE: - { - switch (type) { - case OID_AUTHENTICATION_INFO: - DBG(DBG_PARSING, - DBG_log(" need to parse authenticationInfo") - ) - break; - case OID_ACCESS_IDENTITY: - DBG(DBG_PARSING, - DBG_log(" need to parse accessIdentity") - ) - break; - case OID_CHARGING_IDENTITY: - ac->charging = parse_ietfAttrSyntax(object, level); - break; - case OID_GROUP: - ac->groups = parse_ietfAttrSyntax(object, level); - break; - case OID_ROLE: - parse_roleSyntax(object, level); - break; - default: - break; - } - } - break; - case AC_OBJ_EXTN_ID: - extn_oid = known_oid(object); - break; - case AC_OBJ_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - break; - case AC_OBJ_EXTN_VALUE: - { - switch (extn_oid) { - case OID_CRL_DISTRIBUTION_POINTS: - DBG(DBG_PARSING, - DBG_log(" need to parse crlDistributionPoints") - ) - break; - case OID_AUTHORITY_KEY_ID: - parse_authorityKeyIdentifier(object, level - , &ac->authKeyID, &ac->authKeySerialNumber); - break; - case OID_TARGET_INFORMATION: - DBG(DBG_PARSING, - DBG_log(" need to parse targetInformation") - ) - break; - case OID_NO_REV_AVAIL: - ac->noRevAvail = TRUE; - break; default: - break; + break; } - } - break; - case AC_OBJ_ALGORITHM: - ac->algorithm = parse_algorithmIdentifier(object, level, NULL); - break; - case AC_OBJ_SIGNATURE: - ac->signature = object; - break; - - default: - break; } - objectID++; - } - time(&ac->installed); - return TRUE; + success = parser->success(parser); + time(&ac->installed); + +end: + parser->destroy(parser); + return success; } -/* - * release an ietfAttribute, free it if count reaches zero +/** + * Release an ietfAttribute, free it if count reaches zero */ -static void -release_ietfAttr(ietfAttr_t* attr) +static void release_ietfAttr(ietfAttr_t* attr) { - if (--attr->count == 0) - { - ietfAttrList_t **plist = &ietfAttributes; - ietfAttrList_t *list = *plist; - - while (list->attr != attr) + if (--attr->count == 0) { - plist = &list->next; - list = *plist; + ietfAttrList_t **plist = &ietfAttributes; + ietfAttrList_t *list = *plist; + + while (list->attr != attr) + { + plist = &list->next; + list = *plist; + } + *plist = list->next; + + free(attr->value.ptr); + free(attr); + free(list); } - *plist = list->next; - - pfree(attr->value.ptr); - pfree(attr); - pfree(list); - } } -/* - * free an ietfAttrList +/** + * Free an ietfAttrList */ -void -free_ietfAttrList(ietfAttrList_t* list) +void free_ietfAttrList(ietfAttrList_t* list) { - while (list != NULL) - { - ietfAttrList_t *el = list; - - release_ietfAttr(el->attr); - list = list->next; - pfree(el); - } + while (list != NULL) + { + ietfAttrList_t *el = list; + + release_ietfAttr(el->attr); + list = list->next; + free(el); + } } -/* - * free a X.509 attribute certificate +/** + * Free a X.509 attribute certificate */ -void -free_acert(x509acert_t *ac) +void free_acert(x509acert_t *ac) { - if (ac != NULL) - { - free_ietfAttrList(ac->charging); - free_ietfAttrList(ac->groups); - pfreeany(ac->certificate.ptr); - pfree(ac); - } + if (ac != NULL) + { + free_ietfAttrList(ac->charging); + free_ietfAttrList(ac->groups); + free(ac->certificate.ptr); + free(ac); + } } -/* - * free first X.509 attribute certificate in the chained list +/** + * Free first X.509 attribute certificate in the chained list */ -static void -free_first_acert(void) +static void free_first_acert(void) { - x509acert_t *first = x509acerts; - x509acerts = first->next; - free_acert(first); + x509acert_t *first = x509acerts; + x509acerts = first->next; + free_acert(first); } -/* +/** * Free all attribute certificates in the chained list */ -void -free_acerts(void) -{ - while (x509acerts != NULL) - free_first_acert(); +void free_acerts(void) +{ + while (x509acerts != NULL) + free_first_acert(); } -/* - * get a X.509 attribute certificate for a given holder +/** + * Get a X.509 attribute certificate for a given holder */ -x509acert_t* -get_x509acert(chunk_t issuer, chunk_t serial) +x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial) { - x509acert_t *ac = x509acerts; - x509acert_t *prev_ac = NULL; + x509acert_t *ac = x509acerts; + x509acert_t *prev_ac = NULL; - while (ac != NULL) - { - if (same_dn(issuer, ac->holderIssuer) - && same_serial(serial, ac->holderSerial)) + while (ac != NULL) { - if (ac!= x509acerts) - { - /* bring the certificate up front */ - prev_ac->next = ac->next; - ac->next = x509acerts; - x509acerts = ac; - } - return ac; + if (same_dn(issuer, ac->holderIssuer) + && same_serial(serial, ac->holderSerial)) + { + if (ac!= x509acerts) + { + /* bring the certificate up front */ + prev_ac->next = ac->next; + ac->next = x509acerts; + x509acerts = ac; + } + return ac; + } + prev_ac = ac; + ac = ac->next; } - prev_ac = ac; - ac = ac->next; - } - return NULL; + return NULL; } -/* - * add a X.509 attribute certificate to the chained list +/** + * Add a X.509 attribute certificate to the chained list */ -static void -add_acert(x509acert_t *ac) +static void add_acert(x509acert_t *ac) { - x509acert_t *old_ac = get_x509acert(ac->holderIssuer, ac->holderSerial); + x509acert_t *old_ac = get_x509acert(ac->holderIssuer, ac->holderSerial); - if (old_ac != NULL) - { - if (ac->notBefore >old_ac->notBefore) - { - /* delete the old attribute cert */ - free_first_acert(); - DBG(DBG_CONTROL, - DBG_log("attribute cert is newer - existing cert deleted") - ) - } - else + if (old_ac != NULL) { - DBG(DBG_CONTROL, - DBG_log("attribute cert is not newer - existing cert kept"); - ) - free_acert(ac); - return; + if (ac->notBefore >old_ac->notBefore) + { + /* delete the old attribute cert */ + free_first_acert(); + DBG(DBG_CONTROL, + DBG_log("attribute cert is newer - existing cert deleted") + ) + } + else + { + DBG(DBG_CONTROL, + DBG_log("attribute cert is not newer - existing cert kept"); + ) + free_acert(ac); + return; + } } - } - plog("attribute cert added"); + plog("attribute cert added"); - /* insert new attribute cert at the root of the chain */ - ac->next = x509acerts; - x509acerts = ac; + /* insert new attribute cert at the root of the chain */ + ac->next = x509acerts; + x509acerts = ac; } -/* verify the validity of an attribute certificate by +/** + * Verify the validity of an attribute certificate by * checking the notBefore and notAfter dates */ -static err_t -check_ac_validity(const x509acert_t *ac) +static err_t check_ac_validity(const x509acert_t *ac) { - time_t current_time; - - time(¤t_time); - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" not before : %s", timetoa(&ac->notBefore, TRUE)); - DBG_log(" current time: %s", timetoa(¤t_time, TRUE)); - DBG_log(" not after : %s", timetoa(&ac->notAfter, TRUE)); - ) - - if (current_time < ac->notBefore) - return "attribute certificate is not valid yet"; - if (current_time > ac->notAfter) - return "attribute certificate has expired"; - else - return NULL; + time_t current_time; + + time(¤t_time); + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log(" not before : %T", &ac->notBefore, TRUE); + DBG_log(" current time: %T", ¤t_time, TRUE); + DBG_log(" not after : %T", &ac->notAfter, TRUE); + ) + + if (current_time < ac->notBefore) + return "attribute certificate is not valid yet"; + if (current_time > ac->notAfter) + return "attribute certificate has expired"; + else + return NULL; } -/* +/** * verifies a X.509 attribute certificate */ -bool -verify_x509acert(x509acert_t *ac, bool strict) +bool verify_x509acert(x509acert_t *ac, bool strict) { - u_char buf[BUF_LEN]; - x509cert_t *aacert; - err_t ugh = NULL; - time_t valid_until = ac->notAfter; - - DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, ac->entityName); - DBG_log("holder: '%s'",buf); - dntoa(buf, BUF_LEN, ac->issuerName); - DBG_log("issuer: '%s'",buf); - ) - - ugh = check_ac_validity(ac); - - if (ugh != NULL) - { - plog("%s", ugh); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("attribute certificate is valid") - ) - - lock_authcert_list("verify_x509acert"); - aacert = get_authcert(ac->issuerName, ac->authKeySerialNumber - , ac->authKeyID, AUTH_AA); - unlock_authcert_list("verify_x509acert"); - - if (aacert == NULL) - { - plog("issuer aacert not found"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("issuer aacert found") - ) - - if (!check_signature(ac->certificateInfo, ac->signature - , ac->algorithm, ac->algorithm, aacert)) - { - plog("attribute certificate signature is invalid"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("attribute certificate signature is valid"); - ) + u_char buf[BUF_LEN]; + x509cert_t *aacert; + err_t ugh = NULL; + time_t valid_until = ac->notAfter; - return verify_x509cert(aacert, strict, &valid_until); + DBG(DBG_CONTROL, + dntoa(buf, BUF_LEN, ac->entityName); + DBG_log("holder: '%s'",buf); + dntoa(buf, BUF_LEN, ac->issuerName); + DBG_log("issuer: '%s'",buf); + ) + + ugh = check_ac_validity(ac); + + if (ugh != NULL) + { + plog("%s", ugh); + return FALSE; + } + DBG(DBG_CONTROL, + DBG_log("attribute certificate is valid") + ) + + lock_authcert_list("verify_x509acert"); + aacert = get_authcert(ac->issuerName, ac->authKeySerialNumber + , ac->authKeyID, AUTH_AA); + unlock_authcert_list("verify_x509acert"); + + if (aacert == NULL) + { + plog("issuer aacert not found"); + return FALSE; + } + DBG(DBG_CONTROL, + DBG_log("issuer aacert found") + ) + + if (!x509_check_signature(ac->certificateInfo, ac->signature, ac->algorithm, + aacert)) + { + plog("attribute certificate signature is invalid"); + return FALSE; + } + DBG(DBG_CONTROL, + DBG_log("attribute certificate signature is valid"); + ) + + return verify_x509cert(aacert, strict, &valid_until); } -/* +/** * Loads X.509 attribute certificates */ -void -load_acerts(void) +void load_acerts(void) { - u_char buf[BUF_LEN]; - - /* change directory to specified path */ - u_char *save_dir = getcwd(buf, BUF_LEN); - - if (!chdir(A_CERT_PATH)) - { - struct dirent **filelist; - int n; + u_char buf[BUF_LEN]; - plog("Changing to directory '%s'",A_CERT_PATH); - n = scandir(A_CERT_PATH, &filelist, file_select, alphasort); + /* change directory to specified path */ + u_char *save_dir = getcwd(buf, BUF_LEN); - if (n > 0) + if (!chdir(A_CERT_PATH)) { - while (n--) - { - chunk_t blob = empty_chunk; - bool pgp = FALSE; + struct dirent **filelist; + int n; + + plog("Changing to directory '%s'",A_CERT_PATH); + n = scandir(A_CERT_PATH, &filelist, file_select, alphasort); - if (load_coded_file(filelist[n]->d_name, NULL, "acert", &blob, &pgp)) + if (n > 0) { - x509acert_t *ac = alloc_thing(x509acert_t, "x509acert"); - - *ac = empty_ac; - - if (parse_ac(blob, ac) - && verify_x509acert(ac, FALSE)) - add_acert(ac); - else - free_acert(ac); + while (n--) + { + chunk_t blob = chunk_empty; + bool pgp = FALSE; + + if (load_coded_file(filelist[n]->d_name, NULL, "acert", &blob, &pgp)) + { + x509acert_t *ac = malloc_thing(x509acert_t); + + *ac = empty_ac; + + if (parse_ac(blob, ac) + && verify_x509acert(ac, FALSE)) + add_acert(ac); + else + free_acert(ac); + } + free(filelist[n]); + } + free(filelist); } - free(filelist[n]); - } - free(filelist); } - } - /* restore directory path */ - ignore_result(chdir(save_dir)); + /* restore directory path */ + ignore_result(chdir(save_dir)); } -/* +/** * lists group attributes separated by commas on a single line */ -void -format_groups(const ietfAttrList_t *list, char *buf, int len) +void format_groups(const ietfAttrList_t *list, char *buf, int len) { - bool first_group = TRUE; - - while (list != NULL && len > 0) - { - ietfAttr_t *attr = list->attr; + bool first_group = TRUE; - if (attr->kind == IETF_ATTRIBUTE_OCTETS - || attr->kind == IETF_ATTRIBUTE_STRING) + while (list != NULL && len > 0) { - int written = snprintf(buf, len, "%s%.*s" - , (first_group)? "" : ", " - , (int)attr->value.len, attr->value.ptr); - - first_group = FALSE; - - /* return value of snprintf() up to glibc 2.0.6 */ - if (written < 0) - break; - - buf += written; - len -= written; + ietfAttr_t *attr = list->attr; + + if (attr->kind == IETF_ATTRIBUTE_OCTETS + || attr->kind == IETF_ATTRIBUTE_STRING) + { + int written = snprintf(buf, len, "%s%.*s" + , (first_group)? "" : ", " + , (int)attr->value.len, attr->value.ptr); + + first_group = FALSE; + + /* return value of snprintf() up to glibc 2.0.6 */ + if (written < 0) + break; + + buf += written; + len -= written; + } + list = list->next; } - list = list->next; - } } -/* +/** * list all X.509 attribute certificates in the chained list */ -void -list_acerts(bool utc) +void list_acerts(bool utc) { - x509acert_t *ac = x509acerts; - time_t now; - - /* determine the current time */ - time(&now); + x509acert_t *ac = x509acerts; + time_t now; - if (ac != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:"); - whack_log(RC_COMMENT, " "); - } + /* determine the current time */ + time(&now); - while (ac != NULL) - { - u_char buf[BUF_LEN]; - - whack_log(RC_COMMENT, "%s",timetoa(&ac->installed, utc)); - if (ac->entityName.ptr != NULL) + if (ac != NULL) { - dntoa(buf, BUF_LEN, ac->entityName); - whack_log(RC_COMMENT, " holder: '%s'", buf); + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:"); + whack_log(RC_COMMENT, " "); } - if (ac->holderIssuer.ptr != NULL) - { - dntoa(buf, BUF_LEN, ac->holderIssuer); - whack_log(RC_COMMENT, " hissuer: '%s'", buf); - } - if (ac->holderSerial.ptr != NULL) - { - datatot(ac->holderSerial.ptr, ac->holderSerial.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " hserial: %s", buf); - } - if (ac->groups != NULL) - { - format_groups(ac->groups, buf, BUF_LEN); - whack_log(RC_COMMENT, " groups: %s", buf); - } - dntoa(buf, BUF_LEN, ac->issuerName); - whack_log(RC_COMMENT, " issuer: '%s'", buf); - datatot(ac->serialNumber.ptr, ac->serialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " serial: %s", buf); - whack_log(RC_COMMENT, " validity: not before %s %s", - timetoa(&ac->notBefore, utc), - (ac->notBefore < now)?"ok":"fatal (not valid yet)"); - whack_log(RC_COMMENT, " not after %s %s", - timetoa(&ac->notAfter, utc), - check_expiry(ac->notAfter, ACERT_WARNING_INTERVAL, TRUE)); - if (ac->authKeyID.ptr != NULL) - { - datatot(ac->authKeyID.ptr, ac->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); - } - if (ac->authKeySerialNumber.ptr != NULL) + + while (ac != NULL) { - datatot(ac->authKeySerialNumber.ptr, ac->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); - } + u_char buf[BUF_LEN]; + + whack_log(RC_COMMENT, "%T", &ac->installed, utc); + if (ac->entityName.ptr != NULL) + { + dntoa(buf, BUF_LEN, ac->entityName); + whack_log(RC_COMMENT, " holder: '%s'", buf); + } + if (ac->holderIssuer.ptr != NULL) + { + dntoa(buf, BUF_LEN, ac->holderIssuer); + whack_log(RC_COMMENT, " hissuer: '%s'", buf); + } + if (ac->holderSerial.ptr != NULL) + { + datatot(ac->holderSerial.ptr, ac->holderSerial.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " hserial: %s", buf); + } + if (ac->groups != NULL) + { + format_groups(ac->groups, buf, BUF_LEN); + whack_log(RC_COMMENT, " groups: %s", buf); + } + dntoa(buf, BUF_LEN, ac->issuerName); + whack_log(RC_COMMENT, " issuer: '%s'", buf); + datatot(ac->serialNumber.ptr, ac->serialNumber.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " serial: %s", buf); + whack_log(RC_COMMENT, " validity: not before %T %s", + &ac->notBefore, utc, + (ac->notBefore < now)?"ok":"fatal (not valid yet)"); + whack_log(RC_COMMENT, " not after %T %s", + &ac->notAfter, utc, + check_expiry(ac->notAfter, ACERT_WARNING_INTERVAL, TRUE)); + if (ac->authKeyID.ptr != NULL) + { + datatot(ac->authKeyID.ptr, ac->authKeyID.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " authkey: %s", buf); + } + if (ac->authKeySerialNumber.ptr != NULL) + { + datatot(ac->authKeySerialNumber.ptr, ac->authKeySerialNumber.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " aserial: %s", buf); + } - ac = ac->next; - } + ac = ac->next; + } } -/* +/** * list all group attributes in alphabetical order */ -void -list_groups(bool utc) +void list_groups(bool utc) { - ietfAttrList_t *list = ietfAttributes; - - if (list != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of Group Attributes:"); - whack_log(RC_COMMENT, " "); - } - - while (list != NULL) - { - ietfAttr_t *attr = list->attr; - - whack_log(RC_COMMENT, "%s, count: %d", timetoa(&attr->installed, utc), - attr->count); + ietfAttrList_t *list = ietfAttributes; - switch (attr->kind) + if (list != NULL) { - case IETF_ATTRIBUTE_OCTETS: - case IETF_ATTRIBUTE_STRING: - whack_log(RC_COMMENT, " %.*s", (int)attr->value.len, attr->value.ptr); - break; - case IETF_ATTRIBUTE_OID: - whack_log(RC_COMMENT, " OID"); - break; - default: - break; - } - - list = list->next; - } + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of Group Attributes:"); + whack_log(RC_COMMENT, " "); + } + + while (list != NULL) + { + ietfAttr_t *attr = list->attr; + + whack_log(RC_COMMENT, "%T, count: %d", &attr->installed, utc, attr->count); + + switch (attr->kind) + { + case IETF_ATTRIBUTE_OCTETS: + case IETF_ATTRIBUTE_STRING: + whack_log(RC_COMMENT, " %.*s", (int)attr->value.len, attr->value.ptr); + break; + case IETF_ATTRIBUTE_OID: + whack_log(RC_COMMENT, " OID"); + break; + default: + break; + } + + list = list->next; + } } diff --git a/src/pluto/ac.h b/src/pluto/ac.h index d60ad25af..bee016143 100644 --- a/src/pluto/ac.h +++ b/src/pluto/ac.h @@ -1,7 +1,7 @@ /* Support of X.509 attribute certificates * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler * Copyright (C) 2003 Martin Berner, Lukas Suter - + * * 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 @@ -12,8 +12,6 @@ * 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. - * - * RCSID $Id: ac.h 3253 2007-10-06 21:39:00Z andreas $ */ #ifndef _AC_H @@ -22,9 +20,9 @@ /* definition of ietfAttribute kinds */ typedef enum { - IETF_ATTRIBUTE_OCTETS = 0, - IETF_ATTRIBUTE_OID = 1, - IETF_ATTRIBUTE_STRING = 2 + IETF_ATTRIBUTE_OCTETS = 0, + IETF_ATTRIBUTE_OID = 1, + IETF_ATTRIBUTE_STRING = 2 } ietfAttribute_t; /* access structure for an ietfAttribute */ @@ -32,17 +30,17 @@ typedef enum { typedef struct ietfAttr ietfAttr_t; struct ietfAttr { - time_t installed; - int count; + time_t installed; + int count; ietfAttribute_t kind; - chunk_t value; + chunk_t value; }; typedef struct ietfAttrList ietfAttrList_t; struct ietfAttrList { ietfAttrList_t *next; - ietfAttr_t *attr; + ietfAttr_t *attr; }; @@ -52,31 +50,31 @@ typedef struct x509acert x509acert_t; struct x509acert { x509acert_t *next; - time_t installed; - chunk_t certificate; - chunk_t certificateInfo; - u_int version; - /* holder */ - /* baseCertificateID */ - chunk_t holderIssuer; - chunk_t holderSerial; - chunk_t entityName; - /* v2Form */ - chunk_t issuerName; - /* signature */ + time_t installed; + chunk_t certificate; + chunk_t certificateInfo; + u_int version; + /* holder */ + /* baseCertificateID */ + chunk_t holderIssuer; + chunk_t holderSerial; + chunk_t entityName; + /* v2Form */ + chunk_t issuerName; + /* signature */ int sigAlg; - chunk_t serialNumber; - /* attrCertValidityPeriod */ + chunk_t serialNumber; + /* attrCertValidityPeriod */ time_t notBefore; time_t notAfter; - /* attributes */ + /* attributes */ ietfAttrList_t *charging; ietfAttrList_t *groups; - /* extensions */ + /* extensions */ chunk_t authKeyID; chunk_t authKeySerialNumber; - bool noRevAvail; - /* signatureAlgorithm */ + bool noRevAvail; + /* signatureAlgorithm */ int algorithm; chunk_t signature; }; @@ -88,7 +86,7 @@ extern void unshare_ietfAttrList(ietfAttrList_t **listp); extern void free_ietfAttrList(ietfAttrList_t *list); extern void decode_groups(char *groups, ietfAttrList_t **listp); extern bool group_membership(const ietfAttrList_t *my_list - , const char *conn, const ietfAttrList_t *conn_list); + , const char *conn, const ietfAttrList_t *conn_list); extern bool parse_ac(chunk_t blob, x509acert_t *ac); extern bool verify_x509acert(x509acert_t *ac, bool strict); extern x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial); diff --git a/src/pluto/adns.c b/src/pluto/adns.c index a721d8837..95e22b96f 100644 --- a/src/pluto/adns.c +++ b/src/pluto/adns.c @@ -10,11 +10,9 @@ * 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. - * - * RCSID $Id: adns.c 3252 2007-10-06 21:24:50Z andreas $ */ -#ifndef USE_LWRES /* whole file! */ +#ifndef USE_LWRES /* whole file! */ /* This program executes as multiple processes. The Master process * receives queries (struct adns_query messages) from Pluto and distributes @@ -58,7 +56,7 @@ #include <netinet/in.h> #include <arpa/nameser.h> #include <resolv.h> -#include <netdb.h> /* ??? for h_errno */ +#include <netdb.h> /* ??? for h_errno */ #include <freeswan.h> @@ -70,11 +68,11 @@ #endif #include "constants.h" -#include "adns.h" /* needs <resolv.h> */ +#include "adns.h" /* needs <resolv.h> */ /* shared by all processes */ -static const char *name; /* program name, for messages */ +static const char *name; /* program name, for messages */ static bool debug = FALSE; @@ -88,43 +86,43 @@ static bool debug = FALSE; 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; + size_t n = 0; + size_t goal = minlen; - do { - ssize_t m = read(fd, stuff + n, goal - n); + 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 (m == -1) { - if (debug) - fprintf(stderr, "%lu : [%lu, %lu]\n" - , (unsigned long)goal - , (unsigned long)minlen, (unsigned long)maxlen); - return HES_BAD_LEN; + if (errno != EINTR) + { + syslog(LOG_ERR, "Input error on pipe: %s", strerror(errno)); + return HES_IO_ERROR_IN; + } } - } - } - } while (n < goal); + 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; + return HES_CONTINUE; } /* Write a variable-length record to a pipe. @@ -135,27 +133,27 @@ read_pipe(int fd, unsigned char *stuff, size_t minlen, size_t maxlen) 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; + size_t len = *(const size_t *)(const void *)stuff; + size_t n = 0; - do { - ssize_t m = write(fd, stuff + n, len - n); + 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; + 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 ****************/ @@ -171,14 +169,14 @@ write_pipe(int fd, const unsigned char *stuff) */ #if (__RES) <= 19960801 -# define OLD_RESOLVER 1 +# 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) + res_query(dname, class, type, answer, anslen) # define res_nclose(statp) res_close() static struct __res_state *statp = &_res; @@ -193,75 +191,75 @@ static res_state statp = &my_res_state; 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; - } + 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; + statp->options |= RES_ROTATE; #endif - statp->options |= RES_DEBUG; - } + statp->options |= RES_DEBUG; + } - for (;;) - { - struct adns_query q; - struct adns_answer a; + for (;;) + { + struct adns_query q; + struct adns_answer a; - enum helper_exit_status r = read_pipe(qfd, (unsigned char *)&q - , sizeof(q), sizeof(q)); + 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 (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; - } + 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.amagic = ADNS_A_MAGIC; + a.serial = q.serial; - a.result = res_nquery(statp, q.name_buf, C_IN, q.type, a.ans, sizeof(a.ans)); - a.h_errno_val = h_errno; + 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); + 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 */ + 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); + /* 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 */ - } + 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 */ +#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 */ +# 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 */ + 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]; @@ -270,300 +268,300 @@ static struct worker_info *wi_roof = wi; /* request FIFO */ struct query_list { - struct query_list *next; - struct adns_query aq; + 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 *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) + 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) { - syslog(LOG_ERR, "fork(2) error creating first worker: %s", strerror(errno)); - exit(HES_FORK); + /* 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])); } - 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++) + else { - close(w->qfd); - close(w->afd); + /* parent */ + struct worker_info *w = wi_roof++; + + w->pid = p; + w->busy = FALSE; + close(qfds[0]); + close(afds[1]); + return TRUE; } - 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; + pid_t p; + int status; - close(w->qfd); - w->qfd = NULL_FD; + close(w->qfd); + w->qfd = NULL_FD; - close(w->afd); - w->afd = 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? */ + /* 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; - } + 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; + struct query_list *q = free_queries; + enum helper_exit_status r; - /* find an unused queue entry */ - if (q == NULL) - { - q = malloc(sizeof(*q)); + /* find an unused queue entry */ if (q == NULL) { - syslog(LOG_ERR, "malloc(3) failed"); - exit(HES_MALLOC); + 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; + { + free_queries = q->next; + } + + r = read_pipe(PLUTO_QFD, (unsigned char *)&q->aq + , sizeof(q->aq), sizeof(q->aq)); - /* See if any worker available */ - for (w = wi; ; w++) + if (r == HES_OK) { - 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; - } + /* 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; + 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); - } + 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) + for (;;) { - 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; - } - } + 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! */ + 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)) + 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) { - answer(w); - ndes--; + 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. @@ -574,42 +572,42 @@ master(void) static void adns_usage(const char *fmt, const char *arg) { - const char **sp = ipsec_copyright_notice(); + const char **sp = ipsec_copyright_notice(); - fprintf(stderr, "INTERNAL TO PLUTO: DO NOT EXECUTE\n"); + fprintf(stderr, "INTERNAL TO PLUTO: DO NOT EXECUTE\n"); - fprintf(stderr, fmt, arg); - fprintf(stderr, "\n%s\n", ipsec_version_string()); + fprintf(stderr, fmt, arg); + fprintf(stderr, "\nstrongSwan "VERSION"\n"); - for (; *sp != NULL; sp++) - fprintf(stderr, "%s\n", *sp); + for (; *sp != NULL; sp++) + fprintf(stderr, "%s\n", *sp); - syslog(LOG_ERR, fmt, arg); - exit(HES_INVOCATION); + syslog(LOG_ERR, fmt, arg); + exit(HES_INVOCATION); } int main(int argc UNUSED, char **argv) { - int i = 1; + int i = 1; - name = argv[0]; + name = argv[0]; - while (i < argc) - { - if (streq(argv[i], "-d")) + while (i < argc) { - i++; - debug = TRUE; - } - else - { - adns_usage("unexpected argument \"%s\"", argv[i]); - /*NOTREACHED*/ + if (streq(argv[i], "-d")) + { + i++; + debug = TRUE; + } + else + { + adns_usage("unexpected argument \"%s\"", argv[i]); + /*NOTREACHED*/ + } } - } - return master(); + return master(); } #endif /* !USE_LWRES */ diff --git a/src/pluto/adns.h b/src/pluto/adns.h index f2d0b28bd..f564be232 100644 --- a/src/pluto/adns.h +++ b/src/pluto/adns.h @@ -10,11 +10,9 @@ * 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. - * - * RCSID $Id: adns.h 3252 2007-10-06 21:24:50Z andreas $ */ -#ifndef USE_LWRES /* whole file! */ +#ifndef USE_LWRES /* whole file! */ /* The interface in RHL6.x and BIND distribution 8.2.2 are different, * so we build some of our own :-( @@ -38,38 +36,38 @@ */ 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 */ + 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 */ + 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 */ + 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 /* !USE_LWRES */ diff --git a/src/pluto/alg/ike_alg_aes.c b/src/pluto/alg/ike_alg_aes.c deleted file mode 100644 index c635af723..000000000 --- a/src/pluto/alg/ike_alg_aes.c +++ /dev/null @@ -1,68 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stddef.h> -#include <sys/types.h> -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "libaes/aes_cbc.h" -#include "alg_info.h" -#include "ike_alg.h" - -#define AES_CBC_BLOCK_SIZE (128/BITS_PER_BYTE) -#define AES_KEY_MIN_LEN 128 -#define AES_KEY_DEF_LEN 128 -#define AES_KEY_MAX_LEN 256 - -static void -do_aes(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc) -{ - aes_context aes_ctx; - char iv_bak[AES_CBC_BLOCK_SIZE]; - char *new_iv = NULL; /* logic will avoid copy to NULL */ - - aes_set_key(&aes_ctx, key, key_size, 0); - - /* - * my AES cbc does not touch passed IV (optimization for - * ESP handling), so I must "emulate" des-like IV - * crunching - */ - if (!enc) - memcpy(new_iv=iv_bak, (char*) buf + buf_len - AES_CBC_BLOCK_SIZE - , AES_CBC_BLOCK_SIZE); - - SS_AES_cbc_encrypt(&aes_ctx, buf, buf, buf_len, iv, enc); - - if (enc) - new_iv = (char*) buf + buf_len-AES_CBC_BLOCK_SIZE; - - memcpy(iv, new_iv, AES_CBC_BLOCK_SIZE); -} - -struct encrypt_desc algo_aes = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_AES_CBC, - algo_next: NULL, - enc_ctxsize: sizeof(aes_context), - enc_blocksize: AES_CBC_BLOCK_SIZE, - keyminlen: AES_KEY_MIN_LEN, - keydeflen: AES_KEY_DEF_LEN, - keymaxlen: AES_KEY_MAX_LEN, - do_crypt: do_aes, -}; - -int ike_alg_aes_init(void); - -int -ike_alg_aes_init(void) -{ - int ret = ike_alg_register_enc(&algo_aes); - return ret; -} -/* -IKE_ALG_INIT_NAME: ike_alg_aes_init -*/ diff --git a/src/pluto/alg/ike_alg_blowfish.c b/src/pluto/alg/ike_alg_blowfish.c deleted file mode 100644 index 2bbef051b..000000000 --- a/src/pluto/alg/ike_alg_blowfish.c +++ /dev/null @@ -1,52 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stddef.h> -#include <sys/types.h> -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "libblowfish/blowfish.h" -#include "alg_info.h" -#include "ike_alg.h" - -#define BLOWFISH_CBC_BLOCK_SIZE 8 /* block size */ -#define BLOWFISH_KEY_MIN_LEN 128 -#define BLOWFISH_KEY_MAX_LEN 448 - - -static void -do_blowfish(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc) -{ - BF_KEY bf_ctx; - - BF_set_key(&bf_ctx, key_size , key); - BF_cbc_encrypt(buf, buf, buf_len, &bf_ctx, iv, enc); -} - -struct encrypt_desc algo_blowfish = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_BLOWFISH_CBC, - algo_next: NULL, - enc_ctxsize: sizeof(BF_KEY), - enc_blocksize: BLOWFISH_CBC_BLOCK_SIZE, - keyminlen: BLOWFISH_KEY_MIN_LEN, - keydeflen: BLOWFISH_KEY_MIN_LEN, - keymaxlen: BLOWFISH_KEY_MAX_LEN, - do_crypt: do_blowfish, -}; - -int ike_alg_blowfish_init(void); - -int -ike_alg_blowfish_init(void) -{ - int ret = ike_alg_register_enc(&algo_blowfish); - - return ret; -} -/* -IKE_ALG_INIT_NAME: ike_alg_blowfish_init -*/ diff --git a/src/pluto/alg/ike_alg_serpent.c b/src/pluto/alg/ike_alg_serpent.c deleted file mode 100644 index fb01caa41..000000000 --- a/src/pluto/alg/ike_alg_serpent.c +++ /dev/null @@ -1,70 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stddef.h> -#include <sys/types.h> -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "libserpent/serpent_cbc.h" -#include "alg_info.h" -#include "ike_alg.h" - -#define SERPENT_CBC_BLOCK_SIZE (128/BITS_PER_BYTE) -#define SERPENT_KEY_MIN_LEN 128 -#define SERPENT_KEY_DEF_LEN 128 -#define SERPENT_KEY_MAX_LEN 256 - -static void -do_serpent(u_int8_t *buf, size_t buf_size, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc) -{ - serpent_context serpent_ctx; - char iv_bak[SERPENT_CBC_BLOCK_SIZE]; - char *new_iv = NULL; /* logic will avoid copy to NULL */ - - - serpent_set_key(&serpent_ctx, key, key_size); - /* - * my SERPENT cbc does not touch passed IV (optimization for - * ESP handling), so I must "emulate" des-like IV - * crunching - */ - if (!enc) - memcpy(new_iv=iv_bak, - (char*) buf + buf_size-SERPENT_CBC_BLOCK_SIZE, - SERPENT_CBC_BLOCK_SIZE); - - serpent_cbc_encrypt(&serpent_ctx, buf, buf, buf_size, iv, enc); - - if (enc) - new_iv = (char*) buf + buf_size-SERPENT_CBC_BLOCK_SIZE; - - memcpy(iv, new_iv, SERPENT_CBC_BLOCK_SIZE); -} - -struct encrypt_desc encrypt_desc_serpent = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_SERPENT_CBC, - algo_next: NULL, - enc_ctxsize: sizeof(struct serpent_context), - enc_blocksize: SERPENT_CBC_BLOCK_SIZE, - keyminlen: SERPENT_KEY_MIN_LEN, - keydeflen: SERPENT_KEY_DEF_LEN, - keymaxlen: SERPENT_KEY_MAX_LEN, - do_crypt: do_serpent, -}; - -int ike_alg_serpent_init(void); - -int -ike_alg_serpent_init(void) -{ - int ret = ike_alg_register_enc(&encrypt_desc_serpent); - - return ret; -} -/* -IKE_ALG_INIT_NAME: ike_alg_serpent_init -*/ diff --git a/src/pluto/alg/ike_alg_sha2.c b/src/pluto/alg/ike_alg_sha2.c deleted file mode 100644 index 6b7c8438c..000000000 --- a/src/pluto/alg/ike_alg_sha2.c +++ /dev/null @@ -1,634 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stddef.h> -#include <sys/types.h> -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "libsha2/sha2.h" -#include "alg_info.h" -#include "ike_alg.h" - -static void -sha256_hash_final(u_char *hash, sha256_context *ctx) -{ - sha256_final(ctx); - memcpy(hash, ctx->sha_out, SHA2_256_DIGEST_SIZE); -} - -static void -sha384_hash_final(u_char *hash, sha512_context *ctx) -{ - sha512_final(ctx); - memcpy(hash, ctx->sha_out, SHA2_384_DIGEST_SIZE); -} - -static void -sha512_hash_final(u_char *hash, sha512_context *ctx) -{ - sha512_final(ctx); - memcpy(hash, ctx->sha_out, SHA2_512_DIGEST_SIZE); -} - -/* SHA-256 hash test vectors - * from "The Secure Hash Algorithm Validation System (SHAVS)" - * July 22, 2004, Lawrence E. Bassham III, NIST - */ - -static const u_char sha256_short2_msg[] = { - 0x19 -}; - -static const u_char sha256_short2_msg_digest[] = { - 0x68, 0xaa, 0x2e, 0x2e, 0xe5, 0xdf, 0xf9, 0x6e, - 0x33, 0x55, 0xe6, 0xc7, 0xee, 0x37, 0x3e, 0x3d, - 0x6a, 0x4e, 0x17, 0xf7, 0x5f, 0x95, 0x18, 0xd8, - 0x43, 0x70, 0x9c, 0x0c, 0x9b, 0xc3, 0xe3, 0xd4 -}; - -static const u_char sha256_short4_msg[] = { - 0xe3, 0xd7, 0x25, 0x70, 0xdc, 0xdd, 0x78, 0x7c, - 0xe3, 0x88, 0x7a, 0xb2, 0xcd, 0x68, 0x46, 0x52 -}; - -static const u_char sha256_short4_msg_digest[] = { - 0x17, 0x5e, 0xe6, 0x9b, 0x02, 0xba, 0x9b, 0x58, - 0xe2, 0xb0, 0xa5, 0xfd, 0x13, 0x81, 0x9c, 0xea, - 0x57, 0x3f, 0x39, 0x40, 0xa9, 0x4f, 0x82, 0x51, - 0x28, 0xcf, 0x42, 0x09, 0xbe, 0xab, 0xb4, 0xe8 -}; - -static const u_char sha256_long2_msg[] = { - 0x83, 0x26, 0x75, 0x4e, 0x22, 0x77, 0x37, 0x2f, - 0x4f, 0xc1, 0x2b, 0x20, 0x52, 0x7a, 0xfe, 0xf0, - 0x4d, 0x8a, 0x05, 0x69, 0x71, 0xb1, 0x1a, 0xd5, - 0x71, 0x23, 0xa7, 0xc1, 0x37, 0x76, 0x00, 0x00, - 0xd7, 0xbe, 0xf6, 0xf3, 0xc1, 0xf7, 0xa9, 0x08, - 0x3a, 0xa3, 0x9d, 0x81, 0x0d, 0xb3, 0x10, 0x77, - 0x7d, 0xab, 0x8b, 0x1e, 0x7f, 0x02, 0xb8, 0x4a, - 0x26, 0xc7, 0x73, 0x32, 0x5f, 0x8b, 0x23, 0x74, - 0xde, 0x7a, 0x4b, 0x5a, 0x58, 0xcb, 0x5c, 0x5c, - 0xf3, 0x5b, 0xce, 0xe6, 0xfb, 0x94, 0x6e, 0x5b, - 0xd6, 0x94, 0xfa, 0x59, 0x3a, 0x8b, 0xeb, 0x3f, - 0x9d, 0x65, 0x92, 0xec, 0xed, 0xaa, 0x66, 0xca, - 0x82, 0xa2, 0x9d, 0x0c, 0x51, 0xbc, 0xf9, 0x33, - 0x62, 0x30, 0xe5, 0xd7, 0x84, 0xe4, 0xc0, 0xa4, - 0x3f, 0x8d, 0x79, 0xa3, 0x0a, 0x16, 0x5c, 0xba, - 0xbe, 0x45, 0x2b, 0x77, 0x4b, 0x9c, 0x71, 0x09, - 0xa9, 0x7d, 0x13, 0x8f, 0x12, 0x92, 0x28, 0x96, - 0x6f, 0x6c, 0x0a, 0xdc, 0x10, 0x6a, 0xad, 0x5a, - 0x9f, 0xdd, 0x30, 0x82, 0x57, 0x69, 0xb2, 0xc6, - 0x71, 0xaf, 0x67, 0x59, 0xdf, 0x28, 0xeb, 0x39, - 0x3d, 0x54, 0xd6 -}; - -static const u_char sha256_long2_msg_digest[] = { - 0x97, 0xdb, 0xca, 0x7d, 0xf4, 0x6d, 0x62, 0xc8, - 0xa4, 0x22, 0xc9, 0x41, 0xdd, 0x7e, 0x83, 0x5b, - 0x8a, 0xd3, 0x36, 0x17, 0x63, 0xf7, 0xe9, 0xb2, - 0xd9, 0x5f, 0x4f, 0x0d, 0xa6, 0xe1, 0xcc, 0xbc -}; - -static const hash_testvector_t sha256_hash_testvectors[] = { - { sizeof(sha256_short2_msg), sha256_short2_msg, sha256_short2_msg_digest }, - { sizeof(sha256_short4_msg), sha256_short4_msg, sha256_short4_msg_digest }, - { sizeof(sha256_long2_msg), sha256_long2_msg, sha256_long2_msg_digest }, - { 0, NULL, NULL } -}; - -/* SHA-384 hash test vectors - * from "The Secure Hash Algorithm Validation System (SHAVS)" - * July 22, 2004, Lawrence E. Bassham III, NIST - */ - -static const u_char sha384_short2_msg[] = { - 0xb9 -}; - -static const u_char sha384_short2_msg_digest[] = { - 0xbc, 0x80, 0x89, 0xa1, 0x90, 0x07, 0xc0, 0xb1, - 0x41, 0x95, 0xf4, 0xec, 0xc7, 0x40, 0x94, 0xfe, - 0xc6, 0x4f, 0x01, 0xf9, 0x09, 0x29, 0x28, 0x2c, - 0x2f, 0xb3, 0x92, 0x88, 0x15, 0x78, 0x20, 0x8a, - 0xd4, 0x66, 0x82, 0x8b, 0x1c, 0x6c, 0x28, 0x3d, - 0x27, 0x22, 0xcf, 0x0a, 0xd1, 0xab, 0x69, 0x38 -}; - -static const u_char sha384_short4_msg[] = { - 0xa4, 0x1c, 0x49, 0x77, 0x79, 0xc0, 0x37, 0x5f, - 0xf1, 0x0a, 0x7f, 0x4e, 0x08, 0x59, 0x17, 0x39 -}; - -static const u_char sha384_short4_msg_digest[] = { - 0xc9, 0xa6, 0x84, 0x43, 0xa0, 0x05, 0x81, 0x22, - 0x56, 0xb8, 0xec, 0x76, 0xb0, 0x05, 0x16, 0xf0, - 0xdb, 0xb7, 0x4f, 0xab, 0x26, 0xd6, 0x65, 0x91, - 0x3f, 0x19, 0x4b, 0x6f, 0xfb, 0x0e, 0x91, 0xea, - 0x99, 0x67, 0x56, 0x6b, 0x58, 0x10, 0x9c, 0xbc, - 0x67, 0x5c, 0xc2, 0x08, 0xe4, 0xc8, 0x23, 0xf7 -}; - -static const u_char sha384_long2_msg[] = { - 0x39, 0x96, 0x69, 0xe2, 0x8f, 0x6b, 0x9c, 0x6d, - 0xbc, 0xbb, 0x69, 0x12, 0xec, 0x10, 0xff, 0xcf, - 0x74, 0x79, 0x03, 0x49, 0xb7, 0xdc, 0x8f, 0xbe, - 0x4a, 0x8e, 0x7b, 0x3b, 0x56, 0x21, 0xdb, 0x0f, - 0x3e, 0x7d, 0xc8, 0x7f, 0x82, 0x32, 0x64, 0xbb, - 0xe4, 0x0d, 0x18, 0x11, 0xc9, 0xea, 0x20, 0x61, - 0xe1, 0xc8, 0x4a, 0xd1, 0x0a, 0x23, 0xfa, 0xc1, - 0x72, 0x7e, 0x72, 0x02, 0xfc, 0x3f, 0x50, 0x42, - 0xe6, 0xbf, 0x58, 0xcb, 0xa8, 0xa2, 0x74, 0x6e, - 0x1f, 0x64, 0xf9, 0xb9, 0xea, 0x35, 0x2c, 0x71, - 0x15, 0x07, 0x05, 0x3c, 0xf4, 0xe5, 0x33, 0x9d, - 0x52, 0x86, 0x5f, 0x25, 0xcc, 0x22, 0xb5, 0xe8, - 0x77, 0x84, 0xa1, 0x2f, 0xc9, 0x61, 0xd6, 0x6c, - 0xb6, 0xe8, 0x95, 0x73, 0x19, 0x9a, 0x2c, 0xe6, - 0x56, 0x5c, 0xbd, 0xf1, 0x3d, 0xca, 0x40, 0x38, - 0x32, 0xcf, 0xcb, 0x0e, 0x8b, 0x72, 0x11, 0xe8, - 0x3a, 0xf3, 0x2a, 0x11, 0xac, 0x17, 0x92, 0x9f, - 0xf1, 0xc0, 0x73, 0xa5, 0x1c, 0xc0, 0x27, 0xaa, - 0xed, 0xef, 0xf8, 0x5a, 0xad, 0x7c, 0x2b, 0x7c, - 0x5a, 0x80, 0x3e, 0x24, 0x04, 0xd9, 0x6d, 0x2a, - 0x77, 0x35, 0x7b, 0xda, 0x1a, 0x6d, 0xae, 0xed, - 0x17, 0x15, 0x1c, 0xb9, 0xbc, 0x51, 0x25, 0xa4, - 0x22, 0xe9, 0x41, 0xde, 0x0c, 0xa0, 0xfc, 0x50, - 0x11, 0xc2, 0x3e, 0xcf, 0xfe, 0xfd, 0xd0, 0x96, - 0x76, 0x71, 0x1c, 0xf3, 0xdb, 0x0a, 0x34, 0x40, - 0x72, 0x0e ,0x16, 0x15, 0xc1, 0xf2, 0x2f, 0xbc, - 0x3c, 0x72, 0x1d, 0xe5, 0x21, 0xe1, 0xb9, 0x9b, - 0xa1, 0xbd, 0x55, 0x77, 0x40, 0x86, 0x42, 0x14, - 0x7e, 0xd0, 0x96 -}; - -static const u_char sha384_long2_msg_digest[] = { - 0x4f, 0x44, 0x0d, 0xb1, 0xe6, 0xed, 0xd2, 0x89, - 0x9f, 0xa3, 0x35, 0xf0, 0x95, 0x15, 0xaa, 0x02, - 0x5e, 0xe1, 0x77, 0xa7, 0x9f, 0x4b, 0x4a, 0xaf, - 0x38, 0xe4, 0x2b, 0x5c, 0x4d, 0xe6, 0x60, 0xf5, - 0xde, 0x8f, 0xb2, 0xa5, 0xb2, 0xfb, 0xd2, 0xa3, - 0xcb, 0xff, 0xd2, 0x0c, 0xff, 0x12, 0x88, 0xc0 -}; - -static const hash_testvector_t sha384_hash_testvectors[] = { - { sizeof(sha384_short2_msg), sha384_short2_msg, sha384_short2_msg_digest }, - { sizeof(sha384_short4_msg), sha384_short4_msg, sha384_short4_msg_digest }, - { sizeof(sha384_long2_msg), sha384_long2_msg, sha384_long2_msg_digest }, - { 0, NULL, NULL } -}; - -/* SHA-512 hash test vectors - * from "The Secure Hash Algorithm Validation System (SHAVS)" - * July 22, 2004, Lawrence E. Bassham III, NIST - */ - -static const u_char sha512_short2_msg[] = { - 0xd0 -}; - -static const u_char sha512_short2_msg_digest[] = { - 0x99, 0x92, 0x20, 0x29, 0x38, 0xe8, 0x82, 0xe7, - 0x3e, 0x20, 0xf6, 0xb6, 0x9e, 0x68, 0xa0, 0xa7, - 0x14, 0x90, 0x90, 0x42, 0x3d, 0x93, 0xc8, 0x1b, - 0xab, 0x3f, 0x21, 0x67, 0x8d, 0x4a, 0xce, 0xee, - 0xe5, 0x0e, 0x4e, 0x8c, 0xaf, 0xad, 0xa4, 0xc8, - 0x5a, 0x54, 0xea, 0x83, 0x06, 0x82, 0x6c, 0x4a, - 0xd6, 0xe7, 0x4c, 0xec, 0xe9, 0x63, 0x1b, 0xfa, - 0x8a, 0x54, 0x9b, 0x4a, 0xb3, 0xfb, 0xba, 0x15 -}; - -static const u_char sha512_short4_msg[] = { - 0x8d, 0x4e, 0x3c, 0x0e, 0x38, 0x89, 0x19, 0x14, - 0x91, 0x81, 0x6e, 0x9d, 0x98, 0xbf, 0xf0, 0xa0 -}; - -static const u_char sha512_short4_msg_digest[] = { - 0xcb, 0x0b, 0x67, 0xa4, 0xb8, 0x71, 0x2c, 0xd7, - 0x3c, 0x9a, 0xab, 0xc0, 0xb1, 0x99, 0xe9, 0x26, - 0x9b, 0x20, 0x84, 0x4a, 0xfb, 0x75, 0xac, 0xbd, - 0xd1, 0xc1, 0x53, 0xc9, 0x82, 0x89, 0x24, 0xc3, - 0xdd, 0xed, 0xaa, 0xfe, 0x66, 0x9c, 0x5f, 0xdd, - 0x0b, 0xc6, 0x6f, 0x63, 0x0f, 0x67, 0x73, 0x98, - 0x82, 0x13, 0xeb, 0x1b, 0x16, 0xf5, 0x17, 0xad, - 0x0d, 0xe4, 0xb2, 0xf0, 0xc9, 0x5c, 0x90, 0xf8 -}; - -static const u_char sha512_long2_msg[] = { - 0xa5, 0x5f, 0x20, 0xc4, 0x11, 0xaa, 0xd1, 0x32, - 0x80, 0x7a, 0x50, 0x2d, 0x65, 0x82, 0x4e, 0x31, - 0xa2, 0x30, 0x54, 0x32, 0xaa, 0x3d, 0x06, 0xd3, - 0xe2, 0x82, 0xa8, 0xd8, 0x4e, 0x0d, 0xe1, 0xde, - 0x69, 0x74, 0xbf, 0x49, 0x54, 0x69, 0xfc, 0x7f, - 0x33, 0x8f, 0x80, 0x54, 0xd5, 0x8c, 0x26, 0xc4, - 0x93, 0x60, 0xc3, 0xe8, 0x7a, 0xf5, 0x65, 0x23, - 0xac, 0xf6, 0xd8, 0x9d, 0x03, 0xe5, 0x6f, 0xf2, - 0xf8, 0x68, 0x00, 0x2b, 0xc3, 0xe4, 0x31, 0xed, - 0xc4, 0x4d, 0xf2, 0xf0, 0x22, 0x3d, 0x4b, 0xb3, - 0xb2, 0x43, 0x58, 0x6e, 0x1a, 0x7d, 0x92, 0x49, - 0x36, 0x69, 0x4f, 0xcb, 0xba, 0xf8, 0x8d, 0x95, - 0x19, 0xe4, 0xeb, 0x50, 0xa6, 0x44, 0xf8, 0xe4, - 0xf9, 0x5e, 0xb0, 0xea, 0x95, 0xbc, 0x44, 0x65, - 0xc8, 0x82, 0x1a, 0xac, 0xd2, 0xfe, 0x15, 0xab, - 0x49, 0x81, 0x16, 0x4b, 0xbb, 0x6d, 0xc3, 0x2f, - 0x96, 0x90, 0x87, 0xa1, 0x45, 0xb0, 0xd9, 0xcc, - 0x9c, 0x67, 0xc2, 0x2b, 0x76, 0x32, 0x99, 0x41, - 0x9c, 0xc4, 0x12, 0x8b, 0xe9, 0xa0, 0x77, 0xb3, - 0xac, 0xe6, 0x34, 0x06, 0x4e, 0x6d, 0x99, 0x28, - 0x35, 0x13, 0xdc, 0x06, 0xe7, 0x51, 0x5d, 0x0d, - 0x73, 0x13, 0x2e, 0x9a, 0x0d, 0xc6, 0xd3, 0xb1, - 0xf8, 0xb2, 0x46, 0xf1, 0xa9, 0x8a, 0x3f, 0xc7, - 0x29, 0x41, 0xb1, 0xe3, 0xbb, 0x20, 0x98, 0xe8, - 0xbf, 0x16, 0xf2, 0x68, 0xd6, 0x4f, 0x0b, 0x0f, - 0x47, 0x07, 0xfe, 0x1e, 0xa1, 0xa1, 0x79, 0x1b, - 0xa2, 0xf3, 0xc0, 0xc7, 0x58, 0xe5, 0xf5, 0x51, - 0x86, 0x3a, 0x96, 0xc9, 0x49, 0xad, 0x47, 0xd7, - 0xfb, 0x40, 0xd2 -}; - -static const u_char sha512_long2_msg_digest[] = { - 0xc6, 0x65, 0xbe, 0xfb, 0x36, 0xda, 0x18, 0x9d, - 0x78, 0x82, 0x2d, 0x10, 0x52, 0x8c, 0xbf, 0x3b, - 0x12, 0xb3, 0xee, 0xf7, 0x26, 0x03, 0x99, 0x09, - 0xc1, 0xa1, 0x6a, 0x27, 0x0d, 0x48, 0x71, 0x93, - 0x77, 0x96, 0x6b, 0x95, 0x7a, 0x87, 0x8e, 0x72, - 0x05, 0x84, 0x77, 0x9a, 0x62, 0x82, 0x5c, 0x18, - 0xda, 0x26, 0x41, 0x5e, 0x49, 0xa7, 0x17, 0x6a, - 0x89, 0x4e, 0x75, 0x10, 0xfd, 0x14, 0x51, 0xf5 -}; - -static const hash_testvector_t sha512_hash_testvectors[] = { - { sizeof(sha512_short2_msg), sha512_short2_msg, sha512_short2_msg_digest }, - { sizeof(sha512_short4_msg), sha512_short4_msg, sha512_short4_msg_digest }, - { sizeof(sha512_long2_msg), sha512_long2_msg, sha512_long2_msg_digest }, - { 0, NULL, NULL } -}; - -/* SHA-256, SHA-384, and SHA-512 hmac test vectors - * from RFC 4231 "Identifiers and Test Vectors for HMAC-SHA-224, - * HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512" - * December 2005, M. Nystrom, RSA Security - */ - -static const u_char sha2_hmac1_key[] = { - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b -}; - -static const u_char sha2_hmac1_msg[] = { - 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 -}; - -static const u_char sha2_hmac1_256[] = { - 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, - 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, - 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, - 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7 -}; - -static const u_char sha2_hmac1_384[] = { - 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62, - 0x6b, 0x08, 0x25, 0xf4, 0xab ,0x46, 0x90, 0x7f, - 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6, - 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c, - 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f, - 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6 -}; - -static const u_char sha2_hmac1_512[] = { - 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, - 0x4f, 0xf0, 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0, - 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78, - 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, - 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02, - 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, - 0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70, - 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54 -}; - -static const u_char sha2_hmac2_key[] = { - 0x4a, 0x65, 0x66, 0x65 -}; - -static const u_char sha2_hmac2_msg[] = { - 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, - 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, - 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, - 0x69, 0x6e, 0x67, 0x3f -}; - -static const u_char sha2_hmac2_256[] = { - 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, - 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, - 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, - 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 -}; - -static const u_char sha2_hmac2_384[] = { - 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, - 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b, - 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47, - 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e, - 0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7, - 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49 -}; - -static const u_char sha2_hmac2_512[] = { - 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, - 0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3, - 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, - 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54, - 0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99, 0x4a, - 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd, - 0xca, 0xea, 0xb1, 0xa3, 0x4d, 0x4a, 0x6b, 0x4b, - 0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37 -}; - -static const u_char sha2_hmac3_key[] = { - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa -}; - -static const u_char sha2_hmac3_msg[] = { - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd -}; - -static const u_char sha2_hmac3_256[] = { - 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, - 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, - 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, - 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe -}; - -static const u_char sha2_hmac3_384[] = { - 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, - 0x0a, 0xa2, 0xac, 0xe0, 0x14, 0xc8, 0xa8, 0x6f, - 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb, - 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, - 0x2a, 0x5a, 0xb3, 0x9d, 0xc1, 0x38, 0x14, 0xb9, - 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27 -}; - -static const u_char sha2_hmac3_512[] = { - 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, - 0xef, 0xb0, 0xf0, 0x75, 0x6c, 0x89, 0x0b, 0xe9, - 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, - 0x55, 0xf8, 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, - 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22, 0xc8, - 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, - 0xb9, 0x46, 0xa3, 0x37, 0xbe, 0xe8, 0x94, 0x26, - 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb -}; - -static const u_char sha2_hmac4_key[] = { - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19 -}; - -static const u_char sha2_hmac4_msg[] = { - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd -}; - -static const u_char sha2_hmac4_256[] = { - 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, - 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, - 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, - 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b -}; - -static const u_char sha2_hmac4_384[] = { - 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85, - 0x19, 0x33, 0xab, 0x62, 0x90, 0xaf, 0x6c, 0xa7, - 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c, - 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e, - 0x68, 0x01, 0xdd, 0x23, 0xc4, 0xa7, 0xd6, 0x79, - 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb -}; - -static const u_char sha2_hmac4_512[] = { - 0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69, - 0x90, 0xe5, 0xa8, 0xc5, 0xf6, 0x1d, 0x4a, 0xf7, - 0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d, - 0xe7, 0x6f, 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb, - 0xa9, 0x1c, 0xa5, 0xc1, 0x1a, 0xa2, 0x5e, 0xb4, - 0xd6, 0x79, 0x27, 0x5c, 0xc5, 0x78, 0x80, 0x63, - 0xa5, 0xf1, 0x97, 0x41, 0x12, 0x0c, 0x4f, 0x2d, - 0xe2, 0xad, 0xeb, 0xeb, 0x10, 0xa2, 0x98, 0xdd -}; - -static const u_char sha2_hmac6_key[] = { - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa -}; - -static const u_char sha2_hmac6_msg[] = { - 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, - 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, - 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, - 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, - 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, - 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 -}; - -static const u_char sha2_hmac6_256[] = { - 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, - 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, - 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, - 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54 -}; - -static const u_char sha2_hmac6_384[] = { - 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, - 0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4, - 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f, - 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, - 0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82, - 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52 -}; - -static const u_char sha2_hmac6_512[] = { - 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, - 0xb7, 0x14, 0x93, 0xc1, 0xdd, 0x7b, 0xe8, 0xb4, - 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, - 0x12, 0x1b, 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, - 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25, 0x98, - 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, - 0x95, 0xe6, 0x4f, 0x73, 0xf6, 0x3f, 0x0a, 0xec, - 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98 -}; - -static const u_char sha2_hmac7_msg[] = { - 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, - 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, - 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, - 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, - 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, - 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, - 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, - 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, - 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, - 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, - 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, - 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, - 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, - 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, - 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, - 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e -}; - -static const u_char sha2_hmac7_256[] = { - 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, - 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, - 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, - 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2 -}; - -static const u_char sha2_hmac7_384[] = { - 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, - 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c, - 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a, - 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, - 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d, - 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e -}; - -static const u_char sha2_hmac7_512[] = { - 0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, - 0xa4, 0xdf, 0xa9, 0xf9, 0x6e, 0x5e, 0x3f, 0xfd, - 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, - 0x5d, 0xf5, 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, - 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82, 0xb1, - 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, - 0x13, 0x46, 0x76, 0xfb, 0x6d, 0xe0, 0x44, 0x60, - 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58 -}; - -static const hmac_testvector_t sha256_hmac_testvectors[] = { - { sizeof(sha2_hmac1_key), sha2_hmac1_key, sizeof(sha2_hmac1_msg), sha2_hmac1_msg, sha2_hmac1_256 }, - { sizeof(sha2_hmac2_key), sha2_hmac2_key, sizeof(sha2_hmac2_msg), sha2_hmac2_msg, sha2_hmac2_256 }, - { sizeof(sha2_hmac3_key), sha2_hmac3_key, sizeof(sha2_hmac3_msg), sha2_hmac3_msg, sha2_hmac3_256 }, - { sizeof(sha2_hmac4_key), sha2_hmac4_key, sizeof(sha2_hmac4_msg), sha2_hmac4_msg, sha2_hmac4_256 }, - { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac6_msg), sha2_hmac6_msg, sha2_hmac6_256 }, - { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac7_msg), sha2_hmac7_msg, sha2_hmac7_256 }, - { 0, NULL, 0, NULL, NULL } -}; - -static const hmac_testvector_t sha384_hmac_testvectors[] = { - { sizeof(sha2_hmac1_key), sha2_hmac1_key, sizeof(sha2_hmac1_msg), sha2_hmac1_msg, sha2_hmac1_384 }, - { sizeof(sha2_hmac2_key), sha2_hmac2_key, sizeof(sha2_hmac2_msg), sha2_hmac2_msg, sha2_hmac2_384 }, - { sizeof(sha2_hmac3_key), sha2_hmac3_key, sizeof(sha2_hmac3_msg), sha2_hmac3_msg, sha2_hmac3_384 }, - { sizeof(sha2_hmac4_key), sha2_hmac4_key, sizeof(sha2_hmac4_msg), sha2_hmac4_msg, sha2_hmac4_384 }, - { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac6_msg), sha2_hmac6_msg, sha2_hmac6_384 }, - { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac7_msg), sha2_hmac7_msg, sha2_hmac7_384 }, - { 0, NULL, 0, NULL, NULL } -}; - -static const hmac_testvector_t sha512_hmac_testvectors[] = { - { sizeof(sha2_hmac1_key), sha2_hmac1_key, sizeof(sha2_hmac1_msg), sha2_hmac1_msg, sha2_hmac1_512 }, - { sizeof(sha2_hmac2_key), sha2_hmac2_key, sizeof(sha2_hmac2_msg), sha2_hmac2_msg, sha2_hmac2_512 }, - { sizeof(sha2_hmac3_key), sha2_hmac3_key, sizeof(sha2_hmac3_msg), sha2_hmac3_msg, sha2_hmac3_512 }, - { sizeof(sha2_hmac4_key), sha2_hmac4_key, sizeof(sha2_hmac4_msg), sha2_hmac4_msg, sha2_hmac4_512 }, - { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac6_msg), sha2_hmac6_msg, sha2_hmac6_512 }, - { sizeof(sha2_hmac6_key), sha2_hmac6_key, sizeof(sha2_hmac7_msg), sha2_hmac7_msg, sha2_hmac7_512 }, - { 0, NULL, 0, NULL, NULL } -}; - -struct hash_desc hash_desc_sha2_256 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_256, - algo_next: NULL, - hash_ctx_size: sizeof(sha256_context), - hash_block_size: SHA2_256_BLOCK_SIZE, - hash_digest_size: SHA2_256_DIGEST_SIZE, - hash_testvectors: sha256_hash_testvectors, - hmac_testvectors: sha256_hmac_testvectors, - hash_init: (void (*)(void *))sha256_init, - hash_update: (void (*)(void *, const u_char *, size_t ))sha256_write, - hash_final:(void (*)(u_char *, void *))sha256_hash_final -}; - -struct hash_desc hash_desc_sha2_384 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_384, - algo_next: NULL, - hash_ctx_size: sizeof(sha512_context), - hash_block_size: SHA2_384_BLOCK_SIZE, - hash_digest_size: SHA2_384_DIGEST_SIZE, - hash_testvectors: sha384_hash_testvectors, - hmac_testvectors: sha384_hmac_testvectors, - hash_init: (void (*)(void *))sha384_init, - hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write, - hash_final:(void (*)(u_char *, void *))sha384_hash_final -}; - -struct hash_desc hash_desc_sha2_512 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_512, - algo_next: NULL, - hash_ctx_size: sizeof(sha512_context), - hash_block_size: SHA2_512_BLOCK_SIZE, - hash_digest_size: SHA2_512_DIGEST_SIZE, - hash_testvectors: sha512_hash_testvectors, - hmac_testvectors: sha512_hmac_testvectors, - hash_init: (void (*)(void *))sha512_init, - hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write, - hash_final:(void (*)(u_char *, void *))sha512_hash_final -}; - -int ike_alg_sha2_init(void); - -int -ike_alg_sha2_init(void) -{ - int ret -; - ret = ike_alg_register_hash(&hash_desc_sha2_256); - if (ret) - goto out; - ret = ike_alg_register_hash(&hash_desc_sha2_384); - if (ret) - goto out; - ret = ike_alg_register_hash(&hash_desc_sha2_512); - -out: - return ret; -} - -/* -IKE_ALG_INIT_NAME: ike_alg_sha2_init -*/ diff --git a/src/pluto/alg/ike_alg_twofish.c b/src/pluto/alg/ike_alg_twofish.c deleted file mode 100644 index 1788bc394..000000000 --- a/src/pluto/alg/ike_alg_twofish.c +++ /dev/null @@ -1,85 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stddef.h> -#include <sys/types.h> -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "libtwofish/twofish_cbc.h" -#include "alg_info.h" -#include "ike_alg.h" - -#define TWOFISH_CBC_BLOCK_SIZE (128/BITS_PER_BYTE) -#define TWOFISH_KEY_MIN_LEN 128 -#define TWOFISH_KEY_DEF_LEN 128 -#define TWOFISH_KEY_MAX_LEN 256 - -static void -do_twofish(u_int8_t *buf, size_t buf_size, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc) -{ - twofish_context twofish_ctx; - char iv_bak[TWOFISH_CBC_BLOCK_SIZE]; - char *new_iv = NULL; /* logic will avoid copy to NULL */ - - twofish_set_key(&twofish_ctx, key, key_size); - /* - * my TWOFISH cbc does not touch passed IV (optimization for - * ESP handling), so I must "emulate" des-like IV - * crunching - */ - if (!enc) - memcpy(new_iv=iv_bak, - (char*) buf + buf_size-TWOFISH_CBC_BLOCK_SIZE, - TWOFISH_CBC_BLOCK_SIZE); - - twofish_cbc_encrypt(&twofish_ctx, buf, buf, buf_size, iv, enc); - - if (enc) - new_iv = (char*) buf + buf_size-TWOFISH_CBC_BLOCK_SIZE; - - memcpy(iv, new_iv, TWOFISH_CBC_BLOCK_SIZE); -} - -struct encrypt_desc encrypt_desc_twofish = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_TWOFISH_CBC, - algo_next: NULL, - enc_ctxsize: sizeof(twofish_context), - enc_blocksize: TWOFISH_CBC_BLOCK_SIZE, - keydeflen: TWOFISH_KEY_MIN_LEN, - keyminlen: TWOFISH_KEY_DEF_LEN, - keymaxlen: TWOFISH_KEY_MAX_LEN, - do_crypt: do_twofish, -}; - -struct encrypt_desc encrypt_desc_twofish_ssh = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_TWOFISH_CBC_SSH, - algo_next: NULL, - enc_ctxsize: sizeof(twofish_context), - enc_blocksize: TWOFISH_CBC_BLOCK_SIZE, - keydeflen: TWOFISH_KEY_MIN_LEN, - keyminlen: TWOFISH_KEY_DEF_LEN, - keymaxlen: TWOFISH_KEY_MAX_LEN, - do_crypt: do_twofish, -}; - -int ike_alg_twofish_init(void); - -int -ike_alg_twofish_init(void) -{ - int ret = ike_alg_register_enc(&encrypt_desc_twofish); - - if (ike_alg_register_enc(&encrypt_desc_twofish_ssh) < 0) - plog("ike_alg_twofish_init(): Experimental OAKLEY_TWOFISH_CBC_SSH activation failed"); - - return ret; -} -/* -IKE_ALG_INIT_NAME: ike_alg_twofish_init -*/ diff --git a/src/pluto/alg/ike_alginit.c b/src/pluto/alg/ike_alginit.c deleted file mode 100644 index 8784bf31b..000000000 --- a/src/pluto/alg/ike_alginit.c +++ /dev/null @@ -1,7 +0,0 @@ -extern int ike_alg_init(void); int ike_alg_init(void) { -{ extern int ike_alg_aes_init (void); ike_alg_aes_init();} -{ extern int ike_alg_blowfish_init (void); ike_alg_blowfish_init();} -{ extern int ike_alg_serpent_init (void); ike_alg_serpent_init();} -{ extern int ike_alg_sha2_init (void); ike_alg_sha2_init();} -{ extern int ike_alg_twofish_init (void); ike_alg_twofish_init();} -return 0;} diff --git a/src/pluto/alg_info.c b/src/pluto/alg_info.c index cd02d2358..a85a18905 100644 --- a/src/pluto/alg_info.c +++ b/src/pluto/alg_info.c @@ -1,6 +1,7 @@ /* * Algorithm info parsing and creation functions - * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> + * 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 @@ -11,8 +12,6 @@ * 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. - * - * RCSID $Id: alg_info.c 3846 2008-04-18 17:01:45Z andreas $ */ #include <stddef.h> @@ -27,390 +26,187 @@ #include <ctype.h> #include <freeswan.h> -#include <ipsec_policy.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" -#ifndef NO_PLUTO #include "defs.h" #include "log.h" #include "whack.h" -#include "sha1.h" -#include "md5.h" #include "crypto.h" #include "kernel_alg.h" #include "ike_alg.h" -#else -/* - * macros/functions for compilation without pluto (eg: spi for manual conns) - */ -#include <assert.h> -#define passert(x) assert(x) -extern int debug; /* eg: spi.c */ -#define DBG(cond, action) { if (debug) { action ; } } -#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args); -#define RC_LOG_SERIOUS -#define loglog(x, args...) fprintf(stderr, ##args); -#define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name) -void * alloc_bytes(size_t size, const char *name) { - void *p=malloc(size); - if (p == NULL) - fprintf(stderr, "unable to malloc %lu bytes for %s", - (unsigned long) size, name); - memset(p, '\0', size); - return p; -} -#define pfreeany(ptr) free(ptr) -#endif /* NO_PLUTO */ /* * 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; - case AUTH_ALGORITHM_HMAC_SHA2_256: - case AUTH_ALGORITHM_HMAC_SHA2_384: - case AUTH_ALGORITHM_HMAC_SHA2_512: - case AUTH_ALGORITHM_HMAC_RIPEMD: - sadb_aalg = auth; - break; - default: - /* loose ... */ - sadb_aalg = auth; - } - return sadb_aalg; -} - -int /* __attribute__ ((unused)) */ -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; - /* since they are the same ... :) */ - case AUTH_ALGORITHM_HMAC_SHA2_256: - case AUTH_ALGORITHM_HMAC_SHA2_384: - case AUTH_ALGORITHM_HMAC_SHA2_512: - case AUTH_ALGORITHM_HMAC_RIPEMD: - auth = sadb_aalg; - break; - default: - /* loose ... */ - auth = sadb_aalg; - } - return auth; -} - -/* - * Search enum_name array with in prefixed uppercase - */ -static int -enum_search_prefix (enum_names *ed, const char *prefix, const char *str, int strlen) -{ - char buf[64]; - char *ptr; - int ret; - int len = sizeof(buf) - 1; /* reserve space for final \0 */ - - for (ptr = buf; *prefix; *ptr++ = *prefix++, len--); - while (strlen-- && len-- && *str) *ptr++ = toupper(*str++); - *ptr = 0; - - DBG(DBG_CRYPT, - DBG_log("enum_search_prefix () calling enum_search(%p, \"%s\")" - , ed, buf) - ) - ret = enum_search(ed, buf); - return ret; -} - -/* - * Search enum_name array with in prefixed and postfixed uppercase - */ -static int -enum_search_ppfix (enum_names *ed, const char *prefix, const char *postfix, const char *str, int strlen) -{ - char buf[64]; - char *ptr; - int ret; - int len = sizeof(buf) - 1; /* reserve space for final \0 */ - - for (ptr = buf; *prefix; *ptr++ = *prefix++, len--); - while (strlen-- && len-- && *str) *ptr++ = toupper(*str++); - while (len-- && *postfix) *ptr++ = *postfix++; - *ptr = 0; - - DBG(DBG_CRYPT, - DBG_log("enum_search_ppfixi () calling enum_search(%p, \"%s\")" - , ed, buf) - ) - ret = enum_search(ed, buf); - return ret; -} - -/* - * Search esp_transformid_names for a match, eg: - * "3des" <=> "ESP_3DES" - */ -#define ESP_MAGIC_ID 0x00ffff01 - -static int -ealg_getbyname_esp(const char *const str, int len) +int alg_info_esp_aa2sadb(int auth) { - if (!str || !*str) - return -1; - - /* leave special case for eg: "id248" string */ - if (strcmp("id", str) == 0) - return ESP_MAGIC_ID; - - return enum_search_prefix(&esp_transformid_names, "ESP_", str, len); + int sadb_aalg = 0; + + switch(auth) { + case AUTH_ALGORITHM_HMAC_MD5: + case AUTH_ALGORITHM_HMAC_SHA1: + sadb_aalg = auth + 1; + break; + case AUTH_ALGORITHM_HMAC_SHA2_256: + case AUTH_ALGORITHM_HMAC_SHA2_384: + case AUTH_ALGORITHM_HMAC_SHA2_512: + case AUTH_ALGORITHM_HMAC_RIPEMD: + sadb_aalg = auth; + break; + default: + /* loose ... */ + sadb_aalg = auth; + } + return sadb_aalg; } -/* - * Search auth_alg_names for a match, eg: - * "md5" <=> "AUTH_ALGORITHM_HMAC_MD5" - */ -static int -aalg_getbyname_esp(const char *const str, int len) +int alg_info_esp_sadb2aa(int sadb_aalg) { - int ret; - unsigned num; - - if (!str || !*str) - return -1; - - /* interpret 'SHA' as 'SHA1' */ - if (strncasecmp("SHA", str, len) == 0) - return AUTH_ALGORITHM_HMAC_SHA1; - - /* interpret 'AESXCBC' as 'AES_XCBC_MAC' */ - if (strncasecmp("AESXCBC", str, len) == 0) - return AUTH_ALGORITHM_AES_XCBC_MAC; - - ret = enum_search_prefix(&auth_alg_names,"AUTH_ALGORITHM_HMAC_", str ,len); - if (ret >= 0) - return ret; - - ret = enum_search_prefix(&auth_alg_names,"AUTH_ALGORITHM_", str, len); - if (ret >= 0) - return ret; - - sscanf(str, "id%d%n", &ret, &num); - return (ret >= 0 && num != strlen(str))? -1 : ret; + int auth = 0; + + switch(sadb_aalg) { + case SADB_AALG_MD5HMAC: + case SADB_AALG_SHA1HMAC: + auth = sadb_aalg - 1; + break; + /* since they are the same ... :) */ + case AUTH_ALGORITHM_HMAC_SHA2_256: + case AUTH_ALGORITHM_HMAC_SHA2_384: + case AUTH_ALGORITHM_HMAC_SHA2_512: + case AUTH_ALGORITHM_HMAC_RIPEMD: + auth = sadb_aalg; + break; + default: + /* loose ... */ + auth = sadb_aalg; + } + return auth; } -static int -modp_getbyname_esp(const char *const str, int len) +void alg_info_free(struct alg_info *alg_info) { - int ret; - - if (!str || !*str) - return -1; - - ret = enum_search_prefix(&oakley_group_names,"OAKLEY_GROUP_", str, len); - if (ret >= 0) - return ret; - - ret = enum_search_ppfix(&oakley_group_names, "OAKLEY_GROUP_", " (extension)", str, len); - return ret; -} - -void -alg_info_free(struct alg_info *alg_info) -{ - pfreeany(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) +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; + struct esp_info *esp_info = alg_info->esp; + unsigned cnt = alg_info->alg_info_cnt, i; - /* check for overflows */ - passert(cnt < elemsof(alg_info->esp)); + /* 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; - } + /* 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; + 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++; + /* 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("__alg_info_esp_add() ealg=%d aalg=%d cnt=%d" - , ealg_id, aalg_id, alg_info->alg_info_cnt) - ) + DBG(DBG_CRYPT, + DBG_log("esp alg added: %s_%d/%s, cnt=%d", + enum_show(&esp_transformid_names, ealg_id), ek_bits, + enum_show(&auth_alg_names, aalg_id), + alg_info->alg_info_cnt) + ) } /* * 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) +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) - { -#ifndef NO_PLUTO - if (aalg_id > 0) -#else - /* Allow no auth for manual conns (from spi.c) */ - if (aalg_id >= 0) -#endif - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - aalg_id, ak_bits); - else + /* Policy: default to 3DES */ + if (ealg_id == 0) { - /* Policy: default to MD5 and SHA1 */ - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - AUTH_ALGORITHM_HMAC_MD5, ak_bits); - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - AUTH_ALGORITHM_HMAC_SHA1, ak_bits); + ealg_id = ESP_3DES; + } + if (ealg_id > 0) + { + 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 MD5 and SHA1 */ + __alg_info_esp_add((struct alg_info_esp *)alg_info, + ealg_id, ek_bits, + AUTH_ALGORITHM_HMAC_MD5, ak_bits); + __alg_info_esp_add((struct alg_info_esp *)alg_info, + ealg_id, ek_bits, + AUTH_ALGORITHM_HMAC_SHA1, ak_bits); + } } - } -} - -#ifndef NO_PLUTO -/************************************** - * - * IKE alg - * - *************************************/ -/* - * Search oakley_enc_names for a match, eg: - * "3des_cbc" <=> "OAKLEY_3DES_CBC" - */ -static int -ealg_getbyname_ike(const char *const str, int len) -{ - int ret; - - if (!str || !*str) - return -1; - - ret = enum_search_prefix(&oakley_enc_names,"OAKLEY_", str, len); - if (ret >= 0) - return ret; - - ret = enum_search_ppfix(&oakley_enc_names, "OAKLEY_", "_CBC", str, len); - return ret; -} - -/* - * Search oakley_hash_names for a match, eg: - * "md5" <=> "OAKLEY_MD5" - */ -static int -aalg_getbyname_ike(const char *const str, int len) -{ - int ret; - unsigned num; - - if (!str || !*str) - return -1; - - /* interpret 'SHA1' as 'SHA' */ - if (strncasecmp("SHA1", str, len) == 0) - return enum_search(&oakley_hash_names, "OAKLEY_SHA"); - - ret = enum_search_prefix(&oakley_hash_names,"OAKLEY_", str, len); - if (ret >= 0) - return ret; - - sscanf(str, "id%d%n", &ret, &num); - return (ret >=0 && num != strlen(str))? -1 : ret; -} - -/* - * Search oakley_group_names for a match, eg: - * "modp1024" <=> "OAKLEY_GROUP_MODP1024" - */ -static int -modp_getbyname_ike(const char *const str, int len) -{ - int ret; - - if (!str || !*str) - return -1; - - ret = enum_search_prefix(&oakley_group_names,"OAKLEY_GROUP_", str, len); - if (ret >= 0) - return ret; - - ret = enum_search_ppfix(&oakley_group_names, "OAKLEY_GROUP_", " (extension)", str, len); - return ret; } -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) +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; + struct ike_info *ike_info = alg_info->ike; + unsigned cnt = alg_info->alg_info_cnt; + unsigned i; - /* check for overflows */ - passert(cnt < elemsof(alg_info->ike)); + /* check for overflows */ + passert(cnt < countof(alg_info->ike)); - /* dont add duplicates */ - for (i = 0;i < cnt; i++) + /* 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; - } + 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++; + 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("__alg_info_ike_add() ealg=%d aalg=%d modp_id=%d, cnt=%d" - , ealg_id, aalg_id, 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) + ) } /* @@ -419,792 +215,449 @@ __alg_info_ike_add (struct alg_info_ike *alg_info, int ealg_id, unsigned ek_bits */ static int default_ike_groups[] = { - OAKLEY_GROUP_MODP1536, - OAKLEY_GROUP_MODP1024 + MODP_1536_BIT, + MODP_1024_BIT }; -/* - * Add IKE alg info _with_ logic (policy): +/* + * 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) +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 = elemsof(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; + int i = 0; + int n_groups = countof(default_ike_groups); - if (ealg_id > 0) + /* if specified modp_id avoid loop over default_ike_groups */ + if (modp_id) { - 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); - } + 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); + } + } } - } -} -#endif /* NO_PLUTO */ - -/* - * Creates a new alg_info by parsing passed string - */ -enum parser_state_esp { - ST_INI, - ST_EA, /* encrypt algo */ - ST_EA_END, - ST_EK, /* enc. key length */ - ST_EK_END, - ST_AA, /* auth algo */ - ST_AA_END, - ST_AK, /* auth. key length */ - ST_AK_END, - ST_MODP, /* modp spec */ - ST_FLAG_STRICT, - ST_END, - ST_EOF, - ST_ERR -}; - -static const char *parser_state_esp_names[] = { - "ST_INI", - "ST_EA", - "ST_EA_END", - "ST_EK", - "ST_EK_END", - "ST_AA", - "ST_AA_END", - "ST_AK", - "ST_AK_END", - "ST_MOPD", - "ST_FLAG_STRICT", - "ST_END", - "ST_EOF", - "ST_ERR" -}; - -static const char* -parser_state_name_esp(enum parser_state_esp state) -{ - return parser_state_esp_names[state]; -} - -/* XXX:jjo to implement different parser for ESP and IKE */ -struct parser_context { - unsigned state, old_state; - unsigned protoid; - char ealg_buf[16]; - char aalg_buf[16]; - char modp_buf[16]; - int (*ealg_getbyname)(const char *const str, int len); - int (*aalg_getbyname)(const char *const str, int len); - int (*modp_getbyname)(const char *const str, int len); - char *ealg_str; - char *aalg_str; - char *modp_str; - int eklen; - int aklen; - int ch; - const char *err; -}; - -static inline void -parser_set_state(struct parser_context *p_ctx, enum parser_state_esp state) -{ - if (state != p_ctx->state) - { - p_ctx->old_state = p_ctx->state; - p_ctx->state = state; - } } -static int -parser_machine(struct parser_context *p_ctx) +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) { - int ch = p_ctx->ch; - - /* special 'absolute' cases */ - p_ctx->err = "No error."; + const proposal_token_t *token = proposal_get_token(alg.ptr, alg.len); - /* chars that end algo strings */ - switch (ch){ - case 0: /* end-of-string */ - case '!': /* flag as strict algo list */ - case ',': /* algo string separator */ - switch (p_ctx->state) { - case ST_EA: - case ST_EK: - case ST_AA: - case ST_AK: - case ST_MODP: - case ST_FLAG_STRICT: - { - enum parser_state_esp next_state = 0; - - switch (ch) { - case 0: - next_state = ST_EOF; - break; - case ',': - next_state = ST_END; - break; - case '!': - next_state = ST_FLAG_STRICT; - break; - } - /* ch? parser_set_state(p_ctx, ST_END) : parser_set_state(p_ctx, ST_EOF) ; */ - parser_set_state(p_ctx, next_state); - goto out; - } - default: - p_ctx->err = "String ended with invalid char"; - goto err; - } - } -re_eval: - switch (p_ctx->state) { - case ST_INI: - if (isspace(ch)) - break; - if (isalnum(ch)) - { - *(p_ctx->ealg_str++) = ch; - parser_set_state(p_ctx, ST_EA); - break; - } - p_ctx->err = "No alphanum. char initially found"; - goto err; - case ST_EA: - if (isalpha(ch) || ch == '_') - { - *(p_ctx->ealg_str++) = ch; - break; - } - if (isdigit(ch)) - { - /* bravely switch to enc keylen */ - *(p_ctx->ealg_str) = 0; - parser_set_state(p_ctx, ST_EK); - goto re_eval; - } - if (ch == '-') - { - *(p_ctx->ealg_str) = 0; - parser_set_state(p_ctx, ST_EA_END); - break; - } - p_ctx->err = "No valid char found after enc alg string"; - goto err; - case ST_EA_END: - if (isdigit(ch)) - { - /* bravely switch to enc keylen */ - parser_set_state(p_ctx, ST_EK); - goto re_eval; - } - if (isalpha(ch)) - { - parser_set_state(p_ctx, ST_AA); - goto re_eval; - } - p_ctx->err = "No alphanum char found after enc alg separator"; - goto err; - case ST_EK: - if (ch == '-') - { - parser_set_state(p_ctx, ST_EK_END); - break; - } - if (isdigit(ch)) - { - p_ctx->eklen = p_ctx->eklen*10 + ch - '0'; - break; - } - p_ctx->err = "Non digit or valid separator found while reading enc keylen"; - goto err; - case ST_EK_END: - if (isalpha(ch)) - { - parser_set_state(p_ctx, ST_AA); - goto re_eval; - } - p_ctx->err = "Non alpha char found after enc keylen end separator"; - goto err; - case ST_AA: - if (ch == '-') - { - *(p_ctx->aalg_str++) = 0; - parser_set_state(p_ctx, ST_AA_END); - break; - } - if (isalnum(ch) || ch == '_') - { - *(p_ctx->aalg_str++) = ch; - break; - } - p_ctx->err = "Non alphanum or valid separator found in auth string"; - goto err; - case ST_AA_END: - if (isdigit(ch)) - { - parser_set_state(p_ctx, ST_AK); - goto re_eval; - } - /* Only allow modpXXXX string if we have a modp_getbyname method */ - if ((p_ctx->modp_getbyname) && isalpha(ch)) - { - parser_set_state(p_ctx, ST_MODP); - goto re_eval; - } - p_ctx->err = "Non initial digit found for auth keylen"; - goto err; - case ST_AK: - if (ch=='-') - { - parser_set_state(p_ctx, ST_AK_END); - break; - } - if (isdigit(ch)) + if (token == NULL) { - p_ctx->aklen = p_ctx->aklen*10 + ch - '0'; - break; + return FAILED; } - p_ctx->err = "Non digit found for auth keylen"; - goto err; - case ST_AK_END: - /* Only allow modpXXXX string if we have a modp_getbyname method */ - if ((p_ctx->modp_getbyname) && isalpha(ch)) + switch (token->type) { - parser_set_state(p_ctx, ST_MODP); - goto re_eval; - } - p_ctx->err = "Non alpha char found after auth keylen"; - goto err; - case ST_MODP: - if (isalnum(ch)) - { - *(p_ctx->modp_str++) = ch; - break; - } - p_ctx->err = "Non alphanum char found after in modp string"; - goto err; - case ST_FLAG_STRICT: - if (ch == 0) - parser_set_state(p_ctx, ST_END); - p_ctx->err = "Flags character(s) must be at end of whole string"; - goto err; - - /* XXX */ - case ST_END: - case ST_EOF: - case ST_ERR: - break; - /* XXX */ - } -out: - return p_ctx->state; -err: - parser_set_state(p_ctx, ST_ERR); - return ST_ERR; + 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; } -/* - * Must be called for each "new" char, with new - * character in ctx.ch - */ -static void -parser_init(struct parser_context *p_ctx, unsigned protoid) -{ - memset(p_ctx, 0, sizeof (*p_ctx)); - p_ctx->protoid = protoid; /* XXX: jjo */ - p_ctx->protoid = PROTO_IPSEC_ESP; - p_ctx->ealg_str = p_ctx->ealg_buf; - p_ctx->aalg_str = p_ctx->aalg_buf; - p_ctx->modp_str = p_ctx->modp_buf; - p_ctx->state = ST_INI; - - switch (protoid) { -#ifndef NO_PLUTO - case PROTO_ISAKMP: - p_ctx->ealg_getbyname = ealg_getbyname_ike; - p_ctx->aalg_getbyname = aalg_getbyname_ike; - p_ctx->modp_getbyname = modp_getbyname_ike; - break; -#endif - case PROTO_IPSEC_ESP: - p_ctx->ealg_getbyname = ealg_getbyname_esp; - p_ctx->aalg_getbyname = aalg_getbyname_esp; - break; - } -} -static int -parser_alg_info_add(struct parser_context *p_ctx, struct alg_info *alg_info) +static status_t alg_info_parse_str(struct alg_info *alg_info, char *alg_str) { - int ealg_id = 0; - int aalg_id = 0; - int modp_id = 0; -#ifndef NO_PLUTO - const struct oakley_group_desc *gd; -#endif + char *strict, *single; + status_t status = SUCCESS; - if (*p_ctx->ealg_buf) - { - ealg_id = p_ctx->ealg_getbyname(p_ctx->ealg_buf, strlen(p_ctx->ealg_buf)); - if (ealg_id == ESP_MAGIC_ID) - { - ealg_id = p_ctx->eklen; - p_ctx->eklen = 0; - } - if (ealg_id < 0) + strict = alg_str + strlen(alg_str) - 1; + if (*strict == '!') { - p_ctx->err = "enc_alg not found"; - return -1; + alg_info->alg_info_flags |= ALG_INFO_F_STRICT; + *strict = '\0'; } - DBG(DBG_CRYPT, - DBG_log("parser_alg_info_add() ealg_getbyname(\"%s\")=%d" - , p_ctx->ealg_buf - , ealg_id) - ) - } - if (*p_ctx->aalg_buf) - { - aalg_id = p_ctx->aalg_getbyname(p_ctx->aalg_buf, strlen(p_ctx->aalg_buf)); - if (aalg_id < 0) + while ((single = strsep(&alg_str, ","))) { - p_ctx->err = "hash_alg not found"; - return -1; - } - DBG(DBG_CRYPT, - DBG_log("parser_alg_info_add() aalg_getbyname(\"%s\")=%d" - , p_ctx->aalg_buf - , aalg_id) - ) - } - if (p_ctx->modp_getbyname && *p_ctx->modp_buf) - { - modp_id = p_ctx->modp_getbyname(p_ctx->modp_buf, strlen(p_ctx->modp_buf)); - if (modp_id < 0) - { - p_ctx->err = "modp group not found"; - return -1; - } - DBG(DBG_CRYPT, - DBG_log("parser_alg_info_add() modp_getbyname(\"%s\")=%d" - , p_ctx->modp_buf - , modp_id) - ) - } - switch (alg_info->alg_info_protoid) { - case PROTO_IPSEC_ESP: - alg_info_esp_add(alg_info, - ealg_id, p_ctx->eklen, - aalg_id, p_ctx->aklen); - break; -#ifndef NO_PLUTO - case PROTO_ISAKMP: - if (modp_id && !(gd = lookup_group(modp_id))) - { - p_ctx->err = "found modp group id, but not supported"; - return -1; - } - alg_info_ike_add(alg_info, - ealg_id, p_ctx->eklen, - aalg_id, p_ctx->aklen, - modp_id); - break; -#endif - default: - return -1; - } - return 0; -} + 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; -static int -alg_info_parse_str (struct alg_info *alg_info, const char *alg_str, const char **err_p) -{ - struct parser_context ctx; - int ret; - const char *ptr; - static char err_buf[256]; - - *err_buf = 0; - parser_init(&ctx, alg_info->alg_info_protoid); - if (err_p) - *err_p = NULL; + eat_whitespace(&string); - /* use default if nul esp string */ - if (!*alg_str) - { - switch (alg_info->alg_info_protoid) { -#ifndef NO_PLUTO - case PROTO_ISAKMP: - alg_info_ike_add(alg_info, 0, 0, 0, 0, 0); - return 0; -#endif - case PROTO_IPSEC_ESP: - alg_info_esp_add(alg_info, 0, 0, 0, 0); - return 0; - default: - /* IMPOSSIBLE */ - passert(alg_info->alg_info_protoid); - } - } + 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) - for (ret = 0, ptr = alg_str; ret < ST_EOF;) - { - ctx.ch = *ptr++; - ret = parser_machine(&ctx); - - switch (ret) { - case ST_FLAG_STRICT: - alg_info->alg_info_flags |= ALG_INFO_F_STRICT; - break; - case ST_END: - case ST_EOF: - DBG(DBG_CRYPT, - DBG_log("alg_info_parse_str() ealg_buf=%s aalg_buf=%s" - "eklen=%d aklen=%d", - ctx.ealg_buf, ctx.aalg_buf, - ctx.eklen, ctx.aklen) - ) - if (parser_alg_info_add(&ctx, alg_info) < 0) - { - snprintf(err_buf, sizeof(err_buf), - "%s, enc_alg=\"%s\", auth_alg=\"%s\", modp=\"%s\"", - ctx.err, - ctx.ealg_buf, - ctx.aalg_buf, - ctx.modp_buf); - goto err; - } - /* zero out for next run (ST_END) */ - parser_init(&ctx, alg_info->alg_info_protoid); - break; - case ST_ERR: - snprintf(err_buf, sizeof(err_buf), - "%s, just after \"%.*s\" (old_state=%s)", - ctx.err, - (int)(ptr-alg_str-1), alg_str , - parser_state_name_esp(ctx.old_state)); - goto err; - default: - if (!ctx.ch) - break; + { + 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 0; -err: - if (err_p) - *err_p=err_buf; - return -1; + return status; } -struct alg_info_esp * -alg_info_esp_create_from_str (const char *alg_str, const char **err_p) +struct alg_info_esp *alg_info_esp_create_from_str(char *alg_str) { - struct alg_info_esp *alg_info_esp; - char esp_buf[256]; - static char err_buf[256]; - char *pfs_name; - int ret = 0; - /* - * alg_info storage should be sized dynamically - * but this may require 2passes to know - * transform count in advance. - */ - alg_info_esp = alloc_thing (struct alg_info_esp, "alg_info_esp"); - if (!alg_info_esp) - goto out; - - pfs_name=index (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') + 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=index (alg_str, ';'); + if (pfs_name) { - ret = modp_getbyname_esp(pfs_name, strlen(pfs_name)); - if (ret < 0) - { - /* Bomb if pfsgroup not found */ - DBG(DBG_CRYPT, - DBG_log("alg_info_esp_create_from_str(): pfsgroup \"%s\" not found" - , pfs_name) - ) - if (*err_p) - { - snprintf(err_buf, sizeof(err_buf), - "pfsgroup \"%s\" not found", - pfs_name); + memcpy(esp_buf, alg_str, pfs_name-alg_str); + esp_buf[pfs_name-alg_str] = 0; + alg_str = esp_buf; + pfs_name++; - *err_p = err_buf; + /* 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; } - goto out; - } - alg_info_esp->esp_pfsgroup = ret; } - } - else - alg_info_esp->esp_pfsgroup = 0; - - alg_info_esp->alg_info_protoid = PROTO_IPSEC_ESP; - ret = alg_info_parse_str((struct alg_info *)alg_info_esp, alg_str, err_p) ; + 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 (ret < 0) - { - pfreeany(alg_info_esp); - alg_info_esp = NULL; - } - return alg_info_esp; + if (status != SUCCESS) + { + free(alg_info_esp); + alg_info_esp = NULL; + } + return alg_info_esp; } -#ifndef NO_PLUTO -struct alg_info_ike * -alg_info_ike_create_from_str (const char *alg_str, const char **err_p) +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 = alloc_thing (struct alg_info_ike, "alg_info_ike"); - alg_info_ike->alg_info_protoid = PROTO_ISAKMP; - - if (alg_info_parse_str((struct alg_info *)alg_info_ike, - alg_str, err_p) < 0) - { - pfreeany(alg_info_ike); - return NULL; - } - return alg_info_ike; + 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) + { + free(alg_info_ike); + return NULL; + } + return alg_info_ike; } -#endif /* - * alg_info struct can be shared by - * several connections instances, - * handle free() with ref_cnts + * 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++; - DBG(DBG_CRYPT, - DBG_log("alg_info_addref() alg_info->ref_cnt=%d" - , alg_info->ref_cnt) - ) - } + 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; + struct alg_info *alg_info = *alg_info_p; - if (alg_info != NULL) - { - passert(alg_info->ref_cnt != 0); - alg_info->ref_cnt--; - DBG(DBG_CRYPT, - DBG_log("alg_info_delref() alg_info->ref_cnt=%d" - , alg_info->ref_cnt) - ) - if (alg_info->ref_cnt == 0) + if (alg_info != NULL) { - DBG(DBG_CRYPT, - DBG_log("alg_info_delref() freeing alg_info") - ) - alg_info_free(alg_info); + 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; } - *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; -#ifndef NO_PLUTO - struct ike_info *ike_info; -#endif - 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; + 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_transformid_names, esp_info->esp_ealg_id)); + ptr += np; + buflen -= np; + if (esp_info->esp_ealg_keylen) + { + np = snprintf(ptr, buflen, "_%u", 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; + } - ALG_INFO_ESP_FOREACH(alg_info_esp, esp_info, cnt) - { - np = snprintf(ptr, buflen, "%d_%03d-%d, " - , esp_info->esp_ealg_id - , (int)esp_info->esp_ealg_keylen - , 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=%d; " - , alg_info_esp->esp_pfsgroup); + 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, "_%u", 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; - if (buflen < 0) - goto out; - } - break; - } -#ifndef NO_PLUTO - case PROTO_ISAKMP: - ALG_INFO_IKE_FOREACH((struct alg_info_ike *)alg_info, ike_info, cnt) - { - np = snprintf(ptr, buflen, "%d_%03d-%d-%d, " - , ike_info->ike_ealg - , (int)ike_info->ike_eklen - , ike_info->ike_halg - , ike_info->ike_modp); - ptr += np; - buflen -= np; - if (buflen < 0) goto out; - } - break; -#endif - 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":""); + , 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; + if (buflen < 0) + { + loglog(RC_LOG_SERIOUS + , "buffer space exhausted in alg_info_snprint_ike(), buflen=%d" + , buflen); + } + + return ptr - buf; } -#ifndef NO_PLUTO -int -alg_info_snprint_esp(char *buf, int buflen, struct alg_info_esp *alg_info) +int alg_info_snprint_esp(char *buf, int buflen, struct alg_info_esp *alg_info) { - char *ptr = buf; + char *ptr = buf; - int cnt = alg_info->alg_info_cnt; - struct esp_info *esp_info = alg_info->esp; + 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)) + while (cnt--) { - 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; + 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++; } - esp_info++; - } - return ptr - buf; + return ptr - buf; } -int -alg_info_snprint_ike(char *buf, int buflen, struct alg_info_ike *alg_info) +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; + char *ptr = buf; - while (cnt--) - { - struct encrypt_desc *enc_desc = ike_alg_get_encrypter(ike_info->ike_ealg); - struct hash_desc *hash_desc = ike_alg_get_hasher(ike_info->ike_halg); + int cnt = alg_info->alg_info_cnt; + struct ike_info *ike_info = alg_info->ike; - if (enc_desc != NULL && hash_desc != NULL - && lookup_group(ike_info->ike_modp)) + 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); - 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; + if (enc_desc && hash_desc && dh_desc) + { - 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; + 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++; } - ike_info++; - } - return ptr - buf; + return ptr - buf; } -#endif /* NO_PLUTO */ + diff --git a/src/pluto/alg_info.h b/src/pluto/alg_info.h index cacc2a354..fcf7efca0 100644 --- a/src/pluto/alg_info.h +++ b/src/pluto/alg_info.h @@ -10,76 +10,71 @@ * 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. - * - * RCSID $Id: alg_info.h 3252 2007-10-06 21:24:50Z andreas $ */ #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 */ + 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; + 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 + int alg_info_cnt; \ + int ref_cnt; \ + unsigned alg_info_flags; \ + unsigned alg_info_protoid struct alg_info { - ALG_INFO_COMMON; + ALG_INFO_COMMON; }; struct alg_info_esp { - ALG_INFO_COMMON; - struct esp_info esp[64]; - int esp_pfsgroup; + ALG_INFO_COMMON; + struct esp_info esp[64]; + int esp_pfsgroup; }; struct alg_info_ike { - ALG_INFO_COMMON; - struct ike_info ike[64]; + 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 */ +#define esp_ealg_keylen enckeylen /* bits */ +#define esp_aalg_keylen authkeylen /* bits */ -/* alg_info_flags bits */ -#define ALG_INFO_F_STRICT 0x01 +/* 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(const char *alg_str - , const char **err_p); -extern struct alg_info_ike* alg_info_ike_create_from_str(const char *alg_str - , const char **err_p); +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(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); + , struct alg_info_esp *alg_info); extern int alg_info_snprint_ike(char *buf, int buflen - , struct alg_info_ike *alg_info); + , 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++) + 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++) + for (i=(ai)->alg_info_cnt,ai_ike=(ai)->ike; i--; ai_ike++) #endif /* ALG_INFO_H */ diff --git a/src/pluto/asn1.c b/src/pluto/asn1.c deleted file mode 100644 index 529f597fb..000000000 --- a/src/pluto/asn1.c +++ /dev/null @@ -1,787 +0,0 @@ -/* Simple ASN.1 parser - * 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. - * - * RCSID $Id: asn1.c 5041 2009-03-27 08:58:48Z andreas $ - */ - -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "mp_defs.h" -#include "asn1.h" -#include <asn1/oid.h> -#include "log.h" - -/* some common prefabricated ASN.1 constants */ - -static u_char ASN1_INTEGER_0_str[] = { 0x02, 0x00 }; -static u_char ASN1_INTEGER_1_str[] = { 0x02, 0x01, 0x01 }; -static u_char ASN1_INTEGER_2_str[] = { 0x02, 0x01, 0x02 }; - -const chunk_t ASN1_INTEGER_0 = strchunk(ASN1_INTEGER_0_str); -const chunk_t ASN1_INTEGER_1 = strchunk(ASN1_INTEGER_1_str); -const chunk_t ASN1_INTEGER_2 = strchunk(ASN1_INTEGER_2_str); - -/* some popular algorithmIdentifiers */ - -static u_char ASN1_md5_id_str[] = { - 0x30, 0x0C, - 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, - 0x05, 0x00 -}; - -static u_char ASN1_sha1_id_str[] = { - 0x30, 0x09, - 0x06, 0x05, 0x2B, 0x0E,0x03, 0x02, 0x1A, - 0x05, 0x00 -}; - -static u_char ASN1_md5WithRSA_id_str[] = { - 0x30, 0x0D, - 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, - 0x05, 0x00 -}; - -static u_char ASN1_sha1WithRSA_id_str[] = { - 0x30, 0x0D, - 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, - 0x05, 0x00 -}; - -static u_char ASN1_rsaEncryption_id_str[] = { - 0x30, 0x0D, - 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, - 0x05, 0x00 -}; - -const chunk_t ASN1_md5_id = strchunk(ASN1_md5_id_str); -const chunk_t ASN1_sha1_id = strchunk(ASN1_sha1_id_str); -const chunk_t ASN1_rsaEncryption_id = strchunk(ASN1_rsaEncryption_id_str); -const chunk_t ASN1_md5WithRSA_id = strchunk(ASN1_md5WithRSA_id_str); -const chunk_t ASN1_sha1WithRSA_id = strchunk(ASN1_sha1WithRSA_id_str); - -/* ASN.1 definition of an algorithmIdentifier */ - -static const asn1Object_t algorithmIdentifierObjects[] = { - { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */ - { 1, "parameters", ASN1_EOC, ASN1_OPT | - ASN1_RAW }, /* 2 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */ -}; - -#define ALGORITHM_ID_ALG 1 -#define ALGORITHM_ID_PARAMETERS 2 -#define ALGORITHM_ID_ROOF 4 - -/* - * return the ASN.1 encoded algorithm identifier - */ -chunk_t -asn1_algorithmIdentifier(int oid) -{ - switch (oid) - { - case OID_RSA_ENCRYPTION: - return ASN1_rsaEncryption_id; - case OID_MD5_WITH_RSA: - return ASN1_md5WithRSA_id; - case OID_SHA1_WITH_RSA: - return ASN1_sha1WithRSA_id; - case OID_MD5: - return ASN1_md5_id; - case OID_SHA1: - return ASN1_sha1_id; - default: - return empty_chunk; - } -} - -/* If the oid is listed in the oid_names table then the corresponding - * position in the oid_names table is returned otherwise -1 is returned - */ -int -known_oid(chunk_t object) -{ - int oid = 0; - - while (object.len) - { - if (oid_names[oid].octet == *object.ptr) - { - if (--object.len == 0 || oid_names[oid].down == 0) - { - return oid; /* found terminal symbol */ - } - else - { - object.ptr++; oid++; /* advance to next hex octet */ - } - } - else - { - if (oid_names[oid].next) - oid = oid_names[oid].next; - else - return OID_UNKNOWN; - } - } - return -1; -} - -/* - * Decodes the length in bytes of an ASN.1 object - */ -u_int -asn1_length(chunk_t *blob) -{ - u_char n; - size_t len; - - /* advance from tag field on to length field */ - blob->ptr++; - blob->len--; - - /* read first octet of length field */ - n = *blob->ptr++; - blob->len--; - - if ((n & 0x80) == 0) /* single length octet */ - return n; - - /* composite length, determine number of length octets */ - n &= 0x7f; - - if (n > blob->len) - { - DBG(DBG_PARSING, - DBG_log("number of length octets is larger than ASN.1 object") - ) - return ASN1_INVALID_LENGTH; - } - - if (n > sizeof(len)) - { - DBG(DBG_PARSING, - DBG_log("number of length octets is larger than limit of %d octets" - , (int)sizeof(len)) - ) - return ASN1_INVALID_LENGTH; - } - - len = 0; - - while (n-- > 0) - { - len = 256*len + *blob->ptr++; - blob->len--; - } - return len; -} - -/* - * codes ASN.1 lengths up to a size of 16'777'215 bytes - */ -void -code_asn1_length(size_t length, chunk_t *code) -{ - if (length < 128) - { - code->ptr[0] = length; - code->len = 1; - } - else if (length < 256) - { - code->ptr[0] = 0x81; - code->ptr[1] = (u_char) length; - code->len = 2; - } - else if (length < 65536) - { - code->ptr[0] = 0x82; - code->ptr[1] = length >> 8; - code->ptr[2] = length & 0x00ff; - code->len = 3; - } - else - { - code->ptr[0] = 0x83; - code->ptr[1] = length >> 16; - code->ptr[2] = (length >> 8) & 0x00ff; - code->ptr[3] = length & 0x0000ff; - code->len = 4; - } -} - -/* - * build an empty asn.1 object with tag and length fields already filled in - */ -u_char* -build_asn1_object(chunk_t *object, asn1_t type, size_t datalen) -{ - u_char length_buf[4]; - chunk_t length = { length_buf, 0 }; - u_char *pos; - - /* code the asn.1 length field */ - code_asn1_length(datalen, &length); - - /* allocate memory for the asn.1 TLV object */ - object->len = 1 + length.len + datalen; - object->ptr = alloc_bytes(object->len, "asn1 object"); - - /* set position pointer at the start of the object */ - pos = object->ptr; - - /* copy the asn.1 tag field and advance the pointer */ - *pos++ = type; - - /* copy the asn.1 length field and advance the pointer */ - chunkcpy(pos, length); - - return pos; -} - -/* - * build a simple ASN.1 object - */ -chunk_t -asn1_simple_object(asn1_t tag, chunk_t content) -{ - chunk_t object; - - u_char *pos = build_asn1_object(&object, tag, content.len); - chunkcpy(pos, content); - - return object; -} - -/* Build an ASN.1 object from a variable number of individual chunks. - * Depending on the mode, chunks either are moved ('m') or copied ('c'). - */ -chunk_t -asn1_wrap(asn1_t type, const char *mode, ...) -{ - chunk_t construct; - va_list chunks; - u_char *pos; - int i; - int count = strlen(mode); - - /* sum up lengths of individual chunks */ - va_start(chunks, mode); - construct.len = 0; - for (i = 0; i < count; i++) - { - chunk_t ch = va_arg(chunks, chunk_t); - construct.len += ch.len; - } - va_end(chunks); - - /* allocate needed memory for construct */ - pos = build_asn1_object(&construct, type, construct.len); - - /* copy or move the chunks */ - va_start(chunks, mode); - for (i = 0; i < count; i++) - { - chunk_t ch = va_arg(chunks, chunk_t); - - switch (*mode++) - { - case 'm': - mv_chunk(&pos, ch); - break; - case 'c': - default: - chunkcpy(pos, ch); - } - } - va_end(chunks); - - return construct; -} - -/* - * convert a MP integer into a DER coded ASN.1 object - */ -chunk_t -asn1_integer_from_mpz(const mpz_t value) -{ - size_t bits = mpz_sizeinbase(value, 2); /* size in bits */ - size_t size = 1 + bits / BITS_PER_BYTE; /* size in bytes */ - chunk_t n = mpz_to_n(value, size); - - return asn1_wrap(ASN1_INTEGER, "m", n); -} - -/* - * determines if a character string is of type ASN.1 printableString - */ -bool -is_printablestring(chunk_t str) -{ - const char printablestring_charset[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?"; - u_int i; - - for (i = 0; i < str.len; i++) - { - if (strchr(printablestring_charset, str.ptr[i]) == NULL) - return FALSE; - } - return TRUE; -} - -#define TIME_MAX 0x7fffffff - -/* - * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time - */ -time_t -asn1totime(const chunk_t *utctime, asn1_t type) -{ - struct tm t; - time_t tc, tz_offset; - u_char *eot = NULL; - - if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL) - { - tz_offset = 0; /* Zulu time with a zero time zone offset */ - } - else if ((eot = memchr(utctime->ptr, '+', utctime->len)) != NULL) - { - int tz_hour, tz_min; - - sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min); - tz_offset = 3600*tz_hour + 60*tz_min; /* positive time zone offset */ - } - else if ((eot = memchr(utctime->ptr, '-', utctime->len)) != NULL) - { - int tz_hour, tz_min; - - sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min); - tz_offset = -3600*tz_hour - 60*tz_min; /* negative time zone offset */ - } - else - { - return 0; /* error in time format */ - } - - /* parse ASN.1 time string */ - { - const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d": - "%4d%2d%2d%2d%2d"; - - sscanf(utctime->ptr, format, &t.tm_year, &t.tm_mon, &t.tm_mday, - &t.tm_hour, &t.tm_min); - } - - /* is there a seconds field? */ - if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14)) - { - sscanf(eot-2, "%2d", &t.tm_sec); - } - else - { - t.tm_sec = 0; - } - - /* representation of year */ - if (t.tm_year >= 1900) - { - t.tm_year -= 1900; - } - else if (t.tm_year >= 100) - { - return 0; - } - else if (t.tm_year < 50) - { - t.tm_year += 100; - } - - /* representation of month 0..11*/ - t.tm_mon--; - - /* set daylight saving time to off */ - t.tm_isdst = 0; - - /* convert to time_t */ - tc = mktime(&t); - - /* if no conversion overflow occurred, compensate timezone */ - return (tc == -1) ? TIME_MAX : (tc - timezone - tz_offset); -} - -/* - * convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format - */ -chunk_t -timetoasn1(const time_t *time, asn1_t type) -{ - int offset; - const char *format; - char buf[TIMETOA_BUF]; - chunk_t formatted_time; - struct tm *t = gmtime(time); - - if (type == ASN1_GENERALIZEDTIME) - { - format = "%04d%02d%02d%02d%02d%02dZ"; - offset = 1900; - } - else /* ASN1_UTCTIME */ - { - format = "%02d%02d%02d%02d%02d%02dZ"; - offset = (t->tm_year < 100)? 0 : -100; - } - sprintf(buf, format, t->tm_year + offset, t->tm_mon + 1, t->tm_mday - , t->tm_hour, t->tm_min, t->tm_sec); - formatted_time.ptr = buf; - formatted_time.len = strlen(buf); - return asn1_simple_object(type, formatted_time); -} - - -/* - * Initializes the internal context of the ASN.1 parser - */ -void -asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0, - bool implicit, u_int cond) -{ - ctx->blobs[0] = blob; - ctx->level0 = level0; - ctx->implicit = implicit; - ctx->cond = cond; - memset(ctx->loopAddr, '\0', sizeof(ctx->loopAddr)); -} - -/* - * print the value of an ASN.1 simple object - */ -static void -debug_asn1_simple_object(chunk_t object, asn1_t type, u_int cond) -{ - int oid; - - switch (type) - { - case ASN1_OID: - oid = known_oid(object); - if (oid != OID_UNKNOWN) - { - DBG(DBG_PARSING, - DBG_log(" '%s'",oid_names[oid].name); - ) - return; - } - break; - case ASN1_UTF8STRING: - case ASN1_IA5STRING: - case ASN1_PRINTABLESTRING: - case ASN1_T61STRING: - case ASN1_VISIBLESTRING: - DBG(DBG_PARSING, - DBG_log(" '%.*s'", (int)object.len, object.ptr); - ) - return; - case ASN1_UTCTIME: - case ASN1_GENERALIZEDTIME: - DBG(DBG_PARSING, - time_t time = asn1totime(&object, type); - DBG_log(" '%s'", timetoa(&time, TRUE)); - ) - return; - default: - break; - } - DBG(cond, - DBG_dump_chunk("", object); - ) -} - -/* - * Parses and extracts the next ASN.1 object - */ -bool -extract_object(asn1Object_t const *objects, - u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx) -{ - asn1Object_t obj = objects[*objectID]; - chunk_t *blob; - chunk_t *blob1; - u_char *start_ptr; - - *object = empty_chunk; - - if (obj.flags & ASN1_END) /* end of loop or option found */ - { - if (ctx->loopAddr[obj.level] && ctx->blobs[obj.level+1].len > 0) - { - *objectID = ctx->loopAddr[obj.level]; /* another iteration */ - obj = objects[*objectID]; - } - else - { - ctx->loopAddr[obj.level] = 0; /* exit loop or option*/ - return TRUE; - } - } - - *level = ctx->level0 + obj.level; - blob = ctx->blobs + obj.level; - blob1 = blob + 1; - start_ptr = blob->ptr; - - /* handle ASN.1 defaults values */ - - if ((obj.flags & ASN1_DEF) - && (blob->len == 0 || *start_ptr != obj.type) ) - { - /* field is missing */ - DBG(DBG_PARSING, - DBG_log("L%d - %s:", *level, obj.name); - ) - if (obj.type & ASN1_CONSTRUCTED) - { - (*objectID)++ ; /* skip context-specific tag */ - } - return TRUE; - } - - /* handle ASN.1 options */ - - if ((obj.flags & ASN1_OPT) - && (blob->len == 0 || *start_ptr != obj.type)) - { - /* advance to end of missing option field */ - do - (*objectID)++; - while (!((objects[*objectID].flags & ASN1_END) - && (objects[*objectID].level == obj.level))); - return TRUE; - } - - /* an ASN.1 object must possess at least a tag and length field */ - - if (blob->len < 2) - { - DBG(DBG_PARSING, - DBG_log("L%d - %s: ASN.1 object smaller than 2 octets", - *level, obj.name); - ) - return FALSE; - } - - blob1->len = asn1_length(blob); - - if (blob1->len == ASN1_INVALID_LENGTH || blob->len < blob1->len) - { - DBG(DBG_PARSING, - DBG_log("L%d - %s: length of ASN.1 object invalid or too large", - *level, obj.name); - ) - return FALSE; - } - - blob1->ptr = blob->ptr; - blob->ptr += blob1->len; - blob->len -= blob1->len; - - /* return raw ASN.1 object without prior type checking */ - - if (obj.flags & ASN1_RAW) - { - DBG(DBG_PARSING, - DBG_log("L%d - %s:", *level, obj.name); - ) - object->ptr = start_ptr; - object->len = (size_t)(blob->ptr - start_ptr); - return TRUE; - } - - if (*start_ptr != obj.type && !(ctx->implicit && *objectID == 0)) - { - DBG(DBG_PARSING, - DBG_log("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x", - *level, obj.name, obj.type, *start_ptr); - DBG_dump("", start_ptr, (u_int)(blob->ptr - start_ptr)); - ) - return FALSE; - } - - DBG(DBG_PARSING, - DBG_log("L%d - %s:", ctx->level0+obj.level, obj.name); - ) - - /* In case of "SEQUENCE OF" or "SET OF" start a loop */ - - if (obj.flags & ASN1_LOOP) - { - if (blob1->len > 0) - { - /* at least one item, start the loop */ - ctx->loopAddr[obj.level] = *objectID + 1; - } - else - { - /* no items, advance directly to end of loop */ - do - (*objectID)++; - while (!((objects[*objectID].flags & ASN1_END) - && (objects[*objectID].level == obj.level))); - return TRUE; - } - } - - if (obj.flags & ASN1_OBJ) - { - object->ptr = start_ptr; - object->len = (size_t)(blob->ptr - start_ptr); - DBG(ctx->cond, - DBG_dump_chunk("", *object); - ) - } - else if (obj.flags & ASN1_BODY) - { - *object = *blob1; - debug_asn1_simple_object(*object, obj.type, ctx->cond); - } - return TRUE; -} - -/* - * parse an ASN.1 simple type - */ -bool -parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level -, const char* name) -{ - size_t len; - - /* an ASN.1 object must possess at least a tag and length field */ - if (object->len < 2) - { - DBG(DBG_PARSING, - DBG_log("L%d - %s: ASN.1 object smaller than 2 octets", - level, name); - ) - return FALSE; - } - - if (*object->ptr != type) - { - DBG(DBG_PARSING, - DBG_log("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x", - level, name, type, *object->ptr); - ) - return FALSE; - } - - len = asn1_length(object); - - if (len == ASN1_INVALID_LENGTH || object->len < len) - { - DBG(DBG_PARSING, - DBG_log("L%d - %s: length of ASN.1 object invalid or too large", - level, name); - ) - return FALSE; - } - - DBG(DBG_PARSING, - DBG_log("L%d - %s:", level, name); - ) - debug_asn1_simple_object(*object, type, DBG_RAW); - return TRUE; -} - -/* - * extracts an algorithmIdentifier - */ -int -parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int alg = OID_UNKNOWN; - int objectID = 0; - - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); - - while (objectID < ALGORITHM_ID_ROOF) - { - if (!extract_object(algorithmIdentifierObjects, &objectID, &object, &level, &ctx)) - return alg; - - switch (objectID) - { - case ALGORITHM_ID_ALG: - alg = known_oid(object); - break; - case ALGORITHM_ID_PARAMETERS: - if (parameters != NULL) - *parameters = object; - break; - default: - break; - } - objectID++; - } - return alg; - } - -/* - * tests if a blob contains a valid ASN.1 set or sequence - */ -bool -is_asn1(chunk_t blob) -{ - u_int len; - u_char tag = *blob.ptr; - - if (tag != ASN1_SEQUENCE && tag != ASN1_SET) - { - DBG(DBG_PARSING, - DBG_log(" file content is not binary ASN.1"); - ) - return FALSE; - } - - len = asn1_length(&blob); - - /* exact match */ - if (len == blob.len) - { - return TRUE; - } - - /* some websites append a surplus newline character to the blob */ - if (len + 1 == blob.len && *(blob.ptr + len) == '\n') - { - return TRUE; - } - - DBG(DBG_PARSING, - DBG_log(" file size does not match ASN.1 coded length"); - ) - return FALSE; -} diff --git a/src/pluto/asn1.h b/src/pluto/asn1.h deleted file mode 100644 index 730245e4a..000000000 --- a/src/pluto/asn1.h +++ /dev/null @@ -1,141 +0,0 @@ -/* Simple ASN.1 parser - * 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. - * - * RCSID $Id: asn1.h 3252 2007-10-06 21:24:50Z andreas $ - */ - -#ifndef _ASN1_H -#define _ASN1_H - -#include <stdarg.h> -#include <gmp.h> - -#include "defs.h" - -/* Defines some primitive ASN1 types */ - -typedef enum { - ASN1_EOC = 0x00, - ASN1_BOOLEAN = 0x01, - ASN1_INTEGER = 0x02, - ASN1_BIT_STRING = 0x03, - ASN1_OCTET_STRING = 0x04, - ASN1_NULL = 0x05, - ASN1_OID = 0x06, - ASN1_ENUMERATED = 0x0A, - ASN1_UTF8STRING = 0x0C, - ASN1_NUMERICSTRING = 0x12, - ASN1_PRINTABLESTRING = 0x13, - ASN1_T61STRING = 0x14, - ASN1_VIDEOTEXSTRING = 0x15, - ASN1_IA5STRING = 0x16, - ASN1_UTCTIME = 0x17, - ASN1_GENERALIZEDTIME = 0x18, - ASN1_GRAPHICSTRING = 0x19, - ASN1_VISIBLESTRING = 0x1A, - ASN1_GENERALSTRING = 0x1B, - ASN1_UNIVERSALSTRING = 0x1C, - ASN1_BMPSTRING = 0x1E, - - ASN1_CONSTRUCTED = 0x20, - - ASN1_SEQUENCE = 0x30, - - ASN1_SET = 0x31, - - ASN1_CONTEXT_S_0 = 0x80, - ASN1_CONTEXT_S_1 = 0x81, - ASN1_CONTEXT_S_2 = 0x82, - ASN1_CONTEXT_S_3 = 0x83, - ASN1_CONTEXT_S_4 = 0x84, - ASN1_CONTEXT_S_5 = 0x85, - ASN1_CONTEXT_S_6 = 0x86, - ASN1_CONTEXT_S_7 = 0x87, - ASN1_CONTEXT_S_8 = 0x88, - - ASN1_CONTEXT_C_0 = 0xA0, - ASN1_CONTEXT_C_1 = 0xA1, - ASN1_CONTEXT_C_2 = 0xA2, - ASN1_CONTEXT_C_3 = 0xA3, - ASN1_CONTEXT_C_4 = 0xA4, - ASN1_CONTEXT_C_5 = 0xA5 -} asn1_t; - -/* Definition of ASN1 flags */ - -#define ASN1_NONE 0x00 -#define ASN1_DEF 0x01 -#define ASN1_OPT 0x02 -#define ASN1_LOOP 0x04 -#define ASN1_END 0x08 -#define ASN1_OBJ 0x10 -#define ASN1_BODY 0x20 -#define ASN1_RAW 0x40 - -#define ASN1_INVALID_LENGTH 0xffffffff - -/* definition of an ASN.1 object */ - -typedef struct { - u_int level; - const u_char *name; - asn1_t type; - u_char flags; -} asn1Object_t; - -#define ASN1_MAX_LEVEL 10 - -typedef struct { - bool implicit; - u_int cond; - u_int level0; - u_int loopAddr[ASN1_MAX_LEVEL+1]; - chunk_t blobs[ASN1_MAX_LEVEL+2]; -} asn1_ctx_t; - -/* some common prefabricated ASN.1 constants */ - -extern const chunk_t ASN1_INTEGER_0; -extern const chunk_t ASN1_INTEGER_1; -extern const chunk_t ASN1_INTEGER_2; - -/* some popular algorithmIdentifiers */ -extern const chunk_t ASN1_md5_id; -extern const chunk_t ASN1_sha1_id; -extern const chunk_t ASN1_rsaEncryption_id; -extern const chunk_t ASN1_md5WithRSA_id; -extern const chunk_t ASN1_sha1WithRSA_id; - -extern chunk_t asn1_algorithmIdentifier(int oid); -extern int known_oid(chunk_t object); -extern u_int asn1_length(chunk_t *blob); -extern void code_asn1_length(size_t length, chunk_t *code); -extern u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen); -extern chunk_t asn1_integer_from_mpz(const mpz_t value); -extern chunk_t asn1_simple_object(asn1_t tag, chunk_t content); -extern chunk_t asn1_wrap(asn1_t type, const char *mode, ...); -extern bool is_printablestring(chunk_t str); -extern time_t asn1totime(const chunk_t *utctime, asn1_t type); -extern chunk_t timetoasn1(const time_t *time, asn1_t type); -extern void asn1_init(asn1_ctx_t *ctx, chunk_t blob - , u_int level0, bool implicit, u_int cond); -extern bool extract_object(asn1Object_t const *objects - , u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx); -extern bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level - , const char* name); -extern int parse_algorithmIdentifier(chunk_t blob, int level0 - , chunk_t *parameters); -extern bool is_asn1(chunk_t blob); - -#endif /* _ASN1_H */ - diff --git a/src/pluto/ca.c b/src/pluto/ca.c index 816db53a8..4fdb8cfe7 100644 --- a/src/pluto/ca.c +++ b/src/pluto/ca.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: ca.c 4709 2008-11-27 10:20:25Z martin $ */ #include <stdlib.h> @@ -23,7 +21,6 @@ #include <sys/types.h> #include <freeswan.h> -#include <ipsec_policy.h> #include "constants.h" #include "defs.h" @@ -40,17 +37,17 @@ static x509cert_t *x509authcerts = NULL; const ca_info_t empty_ca_info = { - NULL , /* next */ - NULL , /* name */ - UNDEFINED_TIME, - { NULL, 0 } , /* authName */ - { NULL, 0 } , /* authKeyID */ - { NULL, 0 } , /* authKey SerialNumber */ - NULL , /* ldaphost */ - NULL , /* ldapbase */ - NULL , /* ocspori */ - NULL , /* crluri */ - FALSE /* strictcrlpolicy */ + NULL , /* next */ + NULL , /* name */ + UNDEFINED_TIME, + { NULL, 0 } , /* authName */ + { NULL, 0 } , /* authKeyID */ + { NULL, 0 } , /* authKey SerialNumber */ + NULL , /* ldaphost */ + NULL , /* ldapbase */ + NULL , /* ocspori */ + NULL , /* crluri */ + FALSE /* strictcrlpolicy */ }; /* chained list of X.509 certification authority information records */ @@ -63,52 +60,52 @@ static ca_info_t *ca_infos = NULL; bool trusted_ca(chunk_t a, chunk_t b, int *pathlen) { - bool match = FALSE; - - /* no CA b specified -> any CA a is accepted */ - if (b.ptr == NULL) - { - *pathlen = (a.ptr == NULL)? 0 : MAX_CA_PATH_LEN; - return TRUE; - } - - /* no CA a specified -> trust cannot be established */ - if (a.ptr == NULL) - { - *pathlen = MAX_CA_PATH_LEN; - return FALSE; - } + bool match = FALSE; + + /* no CA b specified -> any CA a is accepted */ + if (b.ptr == NULL) + { + *pathlen = (a.ptr == NULL)? 0 : MAX_CA_PATH_LEN; + return TRUE; + } + + /* no CA a specified -> trust cannot be established */ + if (a.ptr == NULL) + { + *pathlen = MAX_CA_PATH_LEN; + return FALSE; + } - *pathlen = 0; + *pathlen = 0; - /* CA a equals CA b -> we have a match */ - if (same_dn(a, b)) - return TRUE; + /* CA a equals CA b -> we have a match */ + if (same_dn(a, b)) + return TRUE; - /* CA a might be a subordinate CA of b */ - lock_authcert_list("trusted_ca"); + /* CA a might be a subordinate CA of b */ + lock_authcert_list("trusted_ca"); - while ((*pathlen)++ < MAX_CA_PATH_LEN) - { - x509cert_t *cacert = get_authcert(a, empty_chunk, empty_chunk, AUTH_CA); + while ((*pathlen)++ < MAX_CA_PATH_LEN) + { + x509cert_t *cacert = get_authcert(a, chunk_empty, chunk_empty, AUTH_CA); - /* cacert not found or self-signed root cacert-> exit */ - if (cacert == NULL || same_dn(cacert->issuer, a)) - break; + /* cacert not found or self-signed root cacert-> exit */ + if (cacert == NULL || same_dn(cacert->issuer, a)) + break; - /* does the issuer of CA a match CA b? */ - match = same_dn(cacert->issuer, b); + /* does the issuer of CA a match CA b? */ + match = same_dn(cacert->issuer, b); - /* we have a match and exit the loop */ - if (match) - break; + /* we have a match and exit the loop */ + if (match) + break; - /* go one level up in the CA chain */ - a = cacert->issuer; - } - - unlock_authcert_list("trusted_ca"); - return match; + /* go one level up in the CA chain */ + a = cacert->issuer; + } + + unlock_authcert_list("trusted_ca"); + return match; } /* @@ -117,36 +114,36 @@ trusted_ca(chunk_t a, chunk_t b, int *pathlen) bool match_requested_ca(generalName_t *requested_ca, chunk_t our_ca, int *our_pathlen) { - /* if no ca is requested than any ca will match */ - if (requested_ca == NULL) - { - *our_pathlen = 0; - return TRUE; - } - - *our_pathlen = MAX_CA_PATH_LEN + 1; + /* if no ca is requested than any ca will match */ + if (requested_ca == NULL) + { + *our_pathlen = 0; + return TRUE; + } - while (requested_ca != NULL) - { - int pathlen; + *our_pathlen = MAX_CA_PATH_LEN + 1; - if (trusted_ca(our_ca, requested_ca->name, &pathlen) - && pathlen < *our_pathlen) + while (requested_ca != NULL) { - *our_pathlen = pathlen; + int pathlen; + + if (trusted_ca(our_ca, requested_ca->name, &pathlen) + && pathlen < *our_pathlen) + { + *our_pathlen = pathlen; + } + requested_ca = requested_ca->next; } - requested_ca = requested_ca->next; - } - if (*our_pathlen > MAX_CA_PATH_LEN) - { - *our_pathlen = MAX_CA_PATH_LEN; - return FALSE; - } - else - { - return TRUE; - } + if (*our_pathlen > MAX_CA_PATH_LEN) + { + *our_pathlen = MAX_CA_PATH_LEN; + return FALSE; + } + else + { + return TRUE; + } } /* @@ -155,9 +152,9 @@ match_requested_ca(generalName_t *requested_ca, chunk_t our_ca, int *our_pathlen static void free_first_authcert(void) { - x509cert_t *first = x509authcerts; - x509authcerts = first->next; - free_x509cert(first); + x509cert_t *first = x509authcerts; + x509authcerts = first->next; + free_x509cert(first); } /* @@ -166,12 +163,12 @@ free_first_authcert(void) void free_authcerts(void) { - lock_authcert_list("free_authcerts"); + lock_authcert_list("free_authcerts"); - while (x509authcerts != NULL) - free_first_authcert(); + while (x509authcerts != NULL) + free_first_authcert(); - unlock_authcert_list("free_authcerts"); + unlock_authcert_list("free_authcerts"); } /* @@ -180,29 +177,29 @@ free_authcerts(void) x509cert_t* get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid, u_char auth_flags) { - x509cert_t *cert = x509authcerts; - x509cert_t *prev_cert = NULL; - - while (cert != NULL) - { - if (cert->authority_flags & auth_flags - && ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID) - : (same_dn(subject, cert->subject) - && same_serial(serial, cert->serialNumber)))) + x509cert_t *cert = x509authcerts; + x509cert_t *prev_cert = NULL; + + while (cert != NULL) { - if (cert != x509authcerts) - { - /* bring the certificate up front */ - prev_cert->next = cert->next; - cert->next = x509authcerts; - x509authcerts = cert; - } - return cert; + if (cert->authority_flags & auth_flags + && ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID) + : (same_dn(subject, cert->subject) + && same_serial(serial, cert->serialNumber)))) + { + if (cert != x509authcerts) + { + /* bring the certificate up front */ + prev_cert->next = cert->next; + cert->next = x509authcerts; + x509authcerts = cert; + } + return cert; + } + prev_cert = cert; + cert = cert->next; } - prev_cert = cert; - cert = cert->next; - } - return NULL; + return NULL; } /* @@ -211,49 +208,49 @@ get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid, u_char auth_flags) x509cert_t* add_authcert(x509cert_t *cert, u_char auth_flags) { - x509cert_t *old_cert; + x509cert_t *old_cert; - /* set authority flags */ - cert->authority_flags |= auth_flags; + /* set authority flags */ + cert->authority_flags |= auth_flags; - lock_authcert_list("add_authcert"); + lock_authcert_list("add_authcert"); - old_cert = get_authcert(cert->subject, cert->serialNumber - , cert->subjectKeyID, auth_flags); + old_cert = get_authcert(cert->subject, cert->serialNumber + , cert->subjectKeyID, auth_flags); - if (old_cert != NULL) - { - if (same_x509cert(cert, old_cert)) - { - /* cert is already present, just add additional authority flags */ - old_cert->authority_flags |= cert->authority_flags; - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log(" authcert is already present and identical") - ) - unlock_authcert_list("add_authcert"); - - free_x509cert(cert); - return old_cert; - } - else + if (old_cert != NULL) { - /* cert is already present but will be replaced by new cert */ - free_first_authcert(); - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log(" existing authcert deleted") - ) + if (same_x509cert(cert, old_cert)) + { + /* cert is already present, just add additional authority flags */ + old_cert->authority_flags |= cert->authority_flags; + DBG(DBG_CONTROL | DBG_PARSING , + DBG_log(" authcert is already present and identical") + ) + unlock_authcert_list("add_authcert"); + + free_x509cert(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; - share_x509cert(cert); /* set count to one */ - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" authcert inserted") - ) - unlock_authcert_list("add_authcert"); - return cert; + + /* add new authcert to chained list */ + cert->next = x509authcerts; + x509authcerts = cert; + share_x509cert(cert); /* set count to one */ + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log(" authcert inserted") + ) + unlock_authcert_list("add_authcert"); + return cert; } /* @@ -262,41 +259,41 @@ add_authcert(x509cert_t *cert, u_char auth_flags) void load_authcerts(const char *type, const char *path, u_char auth_flags) { - 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(path)) - { - plog("Could not change to directory '%s'", path); - } - else - { - plog("Changing to directory '%s'", path); - n = scandir(path, &filelist, file_select, alphasort); - - if (n < 0) - plog(" scandir() error"); - else - { - while (n--) - { - cert_t cert; + struct dirent **filelist; + u_char buf[BUF_LEN]; + u_char *save_dir; + int n; - if (load_cert(filelist[n]->d_name, type, &cert)) - add_authcert(cert.u.x509, auth_flags); + /* change directory to specified path */ + save_dir = getcwd(buf, BUF_LEN); - free(filelist[n]); - } - free(filelist); + if (chdir(path)) + { + plog("Could not change to directory '%s'", path); } - } - /* restore directory path */ - ignore_result(chdir(save_dir)); + else + { + plog("Changing to directory '%s'", path); + n = scandir(path, &filelist, file_select, alphasort); + + if (n < 0) + plog(" scandir() error"); + else + { + while (n--) + { + cert_t cert; + + if (load_cert(filelist[n]->d_name, type, &cert)) + add_authcert(cert.u.x509, auth_flags); + + free(filelist[n]); + } + free(filelist); + } + } + /* restore directory path */ + ignore_result(chdir(save_dir)); } /* @@ -305,9 +302,9 @@ load_authcerts(const char *type, const char *path, u_char auth_flags) void list_authcerts(const char *caption, u_char auth_flags, bool utc) { - lock_authcert_list("list_authcerts"); - list_x509cert_chain(caption, x509authcerts, auth_flags, utc); - unlock_authcert_list("list_authcerts"); + lock_authcert_list("list_authcerts"); + list_x509cert_chain(caption, x509authcerts, auth_flags, utc); + unlock_authcert_list("list_authcerts"); } /* @@ -315,19 +312,19 @@ list_authcerts(const char *caption, u_char auth_flags, bool utc) */ static const x509cert_t* get_alt_cacert(chunk_t subject, chunk_t serial, chunk_t keyid - , const x509cert_t *cert) + , const x509cert_t *cert) { - while (cert != NULL) - { - if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID) - : (same_dn(subject, cert->subject) - && same_serial(serial, cert->serialNumber))) + while (cert != NULL) { - return cert; + if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID) + : (same_dn(subject, cert->subject) + && same_serial(serial, cert->serialNumber))) + { + return cert; + } + cert = cert->next; } - cert = cert->next; - } - return NULL; + return NULL; } /* establish trust into a candidate authcert by going up the trust chain. @@ -336,85 +333,85 @@ get_alt_cacert(chunk_t subject, chunk_t serial, chunk_t keyid bool trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) { - int pathlen; - - lock_authcert_list("trust_authcert_candidate"); - - for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) - { - const x509cert_t *authcert = NULL; - u_char buf[BUF_LEN]; - - DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, cert->subject); - DBG_log("subject: '%s'",buf); - dntoa(buf, BUF_LEN, cert->issuer); - DBG_log("issuer: '%s'",buf); - if (cert->authKeyID.ptr != NULL) - { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); - } - ) + int pathlen; - /* search in alternative chain first */ - authcert = get_alt_cacert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, alt_chain); + lock_authcert_list("trust_authcert_candidate"); - if (authcert != NULL) + for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) { - DBG(DBG_CONTROL, - DBG_log("issuer cacert found in alternative chain") - ) - } - else - { - /* search in trusted chain */ - authcert = get_authcert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, AUTH_CA); + const x509cert_t *authcert = NULL; + u_char buf[BUF_LEN]; - if (authcert != NULL) - { DBG(DBG_CONTROL, - DBG_log("issuer cacert found") + dntoa(buf, BUF_LEN, cert->subject); + DBG_log("subject: '%s'",buf); + dntoa(buf, BUF_LEN, cert->issuer); + DBG_log("issuer: '%s'",buf); + if (cert->authKeyID.ptr != NULL) + { + datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' + , buf, BUF_LEN); + DBG_log("authkey: %s", buf); + } ) - } - else - { - plog("issuer cacert not found"); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; - } - } - if (!check_signature(cert->tbsCertificate, cert->signature - , cert->algorithm, cert->algorithm, authcert)) - { - plog("certificate signature is invalid"); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate signature is valid") - ) + /* search in alternative chain first */ + authcert = get_alt_cacert(cert->issuer, cert->authKeySerialNumber + , cert->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(cert->issuer, cert->authKeySerialNumber + , cert->authKeyID, AUTH_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 (!x509_check_signature(cert->tbsCertificate, cert->signature, + cert->algorithm, authcert)) + { + 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 && same_dn(cert->issuer, cert->subject)) - { - DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca") - ) - unlock_authcert_list("trust_authcert_candidate"); - return TRUE; + /* check if cert is a self-signed root ca */ + if (pathlen > 0 && same_dn(cert->issuer, cert->subject)) + { + 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; } - - /* go up one step in the trust chain */ - cert = authcert; - } - plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; + plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN); + unlock_authcert_list("trust_authcert_candidate"); + return FALSE; } /* @@ -423,19 +420,19 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain) ca_info_t* get_ca_info(chunk_t authname, chunk_t serial, chunk_t keyid) { - ca_info_t *ca= ca_infos; + ca_info_t *ca= ca_infos; - while (ca!= NULL) - { - if ((keyid.ptr != NULL) ? same_keyid(keyid, ca->authKeyID) - : (same_dn(authname, ca->authName) - && same_serial(serial, ca->authKeySerialNumber))) + while (ca!= NULL) { - return ca; + if ((keyid.ptr != NULL) ? same_keyid(keyid, ca->authKeyID) + : (same_dn(authname, ca->authName) + && same_serial(serial, ca->authKeySerialNumber))) + { + return ca; + } + ca = ca->next; } - ca = ca->next; - } - return NULL; + return NULL; } @@ -445,21 +442,18 @@ get_ca_info(chunk_t authname, chunk_t serial, chunk_t keyid) static void free_ca_info(ca_info_t* ca_info) { - if (ca_info == NULL) - return; - - pfreeany(ca_info->name); - pfreeany(ca_info->ldaphost); - pfreeany(ca_info->ldapbase); - pfreeany(ca_info->ocspuri); - - freeanychunk(ca_info->authName); - freeanychunk(ca_info->authKeyID); - freeanychunk(ca_info->authKeySerialNumber); - - free_generalNames(ca_info->crluri, TRUE); - - pfree(ca_info); + if (ca_info == NULL) + return; + + free(ca_info->name); + free(ca_info->ldaphost); + free(ca_info->ldapbase); + free(ca_info->ocspuri); + free(ca_info->authName.ptr); + free(ca_info->authKeyID.ptr); + free(ca_info->authKeySerialNumber.ptr); + free_generalNames(ca_info->crluri, TRUE); + free(ca_info); } /* @@ -468,13 +462,13 @@ free_ca_info(ca_info_t* ca_info) void free_ca_infos(void) { - while (ca_infos != NULL) - { - ca_info_t *ca = ca_infos; + while (ca_infos != NULL) + { + ca_info_t *ca = ca_infos; - ca_infos = ca_infos->next; - free_ca_info(ca); - } + ca_infos = ca_infos->next; + free_ca_info(ca); + } } /* @@ -483,28 +477,28 @@ free_ca_infos(void) bool find_ca_info_by_name(const char *name, bool delete) { - ca_info_t **ca_p = &ca_infos; - ca_info_t *ca = *ca_p; + 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)) + while (ca != NULL) { - 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; + /* 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; } - ca_p = &ca->next; - ca = *ca_p; - } - return FALSE; + return FALSE; } @@ -514,136 +508,133 @@ find_ca_info_by_name(const char *name, bool delete) void add_ca_info(const whack_message_t *msg) { - smartcard_t *sc = NULL; - cert_t cert; - bool valid_cert = FALSE; - 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 */ - valid_cert = scx_load_cert(msg->cacert, &sc, &cert, &cached_cert); - } - else - { - /* load CA cert from file */ - valid_cert = load_ca_cert(msg->cacert, &cert); - } - - if (valid_cert) - { - char buf[BUF_LEN]; - x509cert_t *cacert = cert.u.x509; - ca_info_t *ca = NULL; - - /* does the authname already exist? */ - ca = get_ca_info(cacert->subject, cacert->serialNumber - , cacert->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); - free_x509cert(cacert); - return; - } + smartcard_t *sc = NULL; + cert_t cert; + bool valid_cert = FALSE; + bool cached_cert = FALSE; - plog("added ca description \"%s\"", msg->name); - - /* create and initialize new ca_info record */ - ca = alloc_thing(ca_info_t, "ca info"); - *ca = empty_ca_info; - - /* name */ - ca->name = clone_str(msg->name, "ca name"); - - /* authName */ - clonetochunk(ca->authName, cacert->subject.ptr - , cacert->subject.len, "authName"); - dntoa(buf, BUF_LEN, ca->authName); - DBG(DBG_CONTROL, - DBG_log("authname: '%s'", buf) - ) - - /* authSerialNumber */ - clonetochunk(ca->authKeySerialNumber, cacert->serialNumber.ptr - , cacert->serialNumber.len, "authKeySerialNumber"); - - /* authKeyID */ - if (cacert->subjectKeyID.ptr != NULL) + if (find_ca_info_by_name(msg->name, FALSE)) { - clonetochunk(ca->authKeyID, cacert->subjectKeyID.ptr - , cacert->subjectKeyID.len, "authKeyID"); - datatot(cacert->subjectKeyID.ptr, cacert->subjectKeyID.len, ':' - , buf, BUF_LEN); - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log("authkey: %s", buf) - ) + loglog(RC_DUPNAME, "attempt to redefine ca record \"%s\"", msg->name); + return; } - /* ldaphost */ - ca->ldaphost = clone_str(msg->ldaphost, "ldaphost"); - - /* ldapbase */ - ca->ldapbase = clone_str(msg->ldapbase, "ldapbase"); - - /* ocspuri */ - if (msg->ocspuri != NULL) + if (scx_on_smartcard(msg->cacert)) { - if (strncasecmp(msg->ocspuri, "http", 4) == 0) - ca->ocspuri = clone_str(msg->ocspuri, "ocspuri"); - else - plog(" ignoring ocspuri with unkown protocol"); + /* load CA cert from smartcard */ + valid_cert = scx_load_cert(msg->cacert, &sc, &cert, &cached_cert); } - - /* crluri2*/ - if (msg->crluri2 != NULL) + else { - generalName_t gn = - { NULL, GN_URI, {msg->crluri2, strlen(msg->crluri2)} }; - - add_distribution_points(&gn, &ca->crluri); + /* load CA cert from file */ + valid_cert = load_ca_cert(msg->cacert, &cert); } - /* crluri */ - if (msg->crluri != NULL) + if (valid_cert) { - generalName_t gn = - { NULL, GN_URI, {msg->crluri, strlen(msg->crluri)} }; - - add_distribution_points(&gn, &ca->crluri); - } - - /* 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; - ca->installed = time(NULL); - - unlock_ca_info_list("add_ca_info"); + char buf[BUF_LEN]; + x509cert_t *cacert = cert.u.x509; + ca_info_t *ca = NULL; + + /* does the authname already exist? */ + ca = get_ca_info(cacert->subject, cacert->serialNumber + , cacert->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); + free_x509cert(cacert); + return; + } + + plog("added ca description \"%s\"", msg->name); + + /* create and initialize new ca_info record */ + ca = malloc_thing(ca_info_t); + *ca = empty_ca_info; + + /* name */ + ca->name = clone_str(msg->name); + + /* authName */ + ca->authName = chunk_clone(cacert->subject); + dntoa(buf, BUF_LEN, ca->authName); + DBG(DBG_CONTROL, + DBG_log("authname: '%s'", buf) + ) - /* add cacert to list of authcerts */ - if (!cached_cert && sc != NULL) - { - if (sc->last_cert.type == CERT_X509_SIGNATURE) - sc->last_cert.u.x509->count--; - sc->last_cert.u.x509 = add_authcert(cacert, AUTH_CA); - share_cert(sc->last_cert); + /* authSerialNumber */ + ca->authKeySerialNumber = chunk_clone(cacert->serialNumber); + + /* authKeyID */ + if (cacert->subjectKeyID.ptr != NULL) + { + ca->authKeyID = chunk_clone(cacert->subjectKeyID); + datatot(cacert->subjectKeyID.ptr, cacert->subjectKeyID.len, ':' + , buf, BUF_LEN); + DBG(DBG_CONTROL | DBG_PARSING , + DBG_log("authkey: %s", buf) + ) + } + + /* 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 unkown protocol"); + } + + /* crluri2*/ + if (msg->crluri2 != NULL) + { + generalName_t gn = + { NULL, GN_URI, {msg->crluri2, strlen(msg->crluri2)} }; + + add_distribution_points(&gn, &ca->crluri); + } + + /* crluri */ + if (msg->crluri != NULL) + { + generalName_t gn = + { NULL, GN_URI, {msg->crluri, strlen(msg->crluri)} }; + + add_distribution_points(&gn, &ca->crluri); + } + + /* 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; + ca->installed = time(NULL); + + unlock_ca_info_list("add_ca_info"); + + /* add cacert to list of authcerts */ + if (!cached_cert && sc != NULL) + { + if (sc->last_cert.type == CERT_X509_SIGNATURE) + sc->last_cert.u.x509->count--; + sc->last_cert.u.x509 = add_authcert(cacert, AUTH_CA); + share_cert(sc->last_cert); + } + if (sc != NULL) + time(&sc->last_load); } - if (sc != NULL) - time(&sc->last_load); - } } /* @@ -652,51 +643,51 @@ add_ca_info(const whack_message_t *msg) 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:"); - whack_log(RC_COMMENT, " "); - } - - while (ca != NULL) - { - u_char buf[BUF_LEN]; - - /* strictpolicy per CA not supported yet - * - whack_log(RC_COMMENT, "%s, \"%s\", strictcrlpolicy: %s" - , timetoa(&ca->installed, utc), ca->name - , ca->strictcrlpolicy? "yes":"no"); - */ - whack_log(RC_COMMENT, "%s, \"%s\"", timetoa(&ca->installed, utc), ca->name); - dntoa(buf, BUF_LEN, ca->authName); - whack_log(RC_COMMENT, " authname: '%s'", buf); - if (ca->ldaphost != NULL) - whack_log(RC_COMMENT, " ldaphost: '%s'", ca->ldaphost); - if (ca->ldapbase != NULL) - whack_log(RC_COMMENT, " ldapbase: '%s'", ca->ldapbase); - if (ca->ocspuri != NULL) - whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri); - - list_distribution_points(ca->crluri); - - if (ca->authKeyID.ptr != NULL) + ca_info_t *ca = ca_infos; + + if (ca != NULL) { - datatot(ca->authKeyID.ptr, ca->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of X.509 CA Information Records:"); + whack_log(RC_COMMENT, " "); } - if (ca->authKeySerialNumber.ptr != NULL) + + while (ca != NULL) { - datatot(ca->authKeySerialNumber.ptr, ca->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + u_char buf[BUF_LEN]; + + /* 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, "%T, \"%s\"", &ca->installed, utc, ca->name); + dntoa(buf, BUF_LEN, ca->authName); + whack_log(RC_COMMENT, " authname: '%s'", buf); + if (ca->ldaphost != NULL) + whack_log(RC_COMMENT, " ldaphost: '%s'", ca->ldaphost); + if (ca->ldapbase != NULL) + whack_log(RC_COMMENT, " ldapbase: '%s'", ca->ldapbase); + if (ca->ocspuri != NULL) + whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri); + + list_distribution_points(ca->crluri); + + if (ca->authKeyID.ptr != NULL) + { + datatot(ca->authKeyID.ptr, ca->authKeyID.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " authkey: %s", buf); + } + if (ca->authKeySerialNumber.ptr != NULL) + { + datatot(ca->authKeySerialNumber.ptr, ca->authKeySerialNumber.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " aserial: %s", buf); + } + ca = ca->next; } - ca = ca->next; - } } diff --git a/src/pluto/ca.h b/src/pluto/ca.h index 13f874284..44d079b4c 100644 --- a/src/pluto/ca.h +++ b/src/pluto/ca.h @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: ca.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _CA_H @@ -20,45 +18,45 @@ #include "x509.h" #include "whack.h" -#define MAX_CA_PATH_LEN 7 +#define MAX_CA_PATH_LEN 7 /* authority flags */ -#define AUTH_NONE 0x00 /* no authorities */ -#define AUTH_CA 0x01 /* certification authority */ -#define AUTH_AA 0x02 /* authorization authority */ -#define AUTH_OCSP 0x04 /* ocsp signing authority */ +#define AUTH_NONE 0x00 /* no authorities */ +#define AUTH_CA 0x01 /* certification authority */ +#define AUTH_AA 0x02 /* authorization authority */ +#define AUTH_OCSP 0x04 /* ocsp signing authority */ /* CA info structures */ typedef struct ca_info ca_info_t; struct ca_info { - ca_info_t *next; - char *name; - time_t installed; - chunk_t authName; - chunk_t authKeyID; - chunk_t authKeySerialNumber; - char *ldaphost; - char *ldapbase; - char *ocspuri; - generalName_t *crluri; - bool strictcrlpolicy; + ca_info_t *next; + char *name; + time_t installed; + chunk_t authName; + chunk_t authKeyID; + chunk_t authKeySerialNumber; + char *ldaphost; + char *ldapbase; + char *ocspuri; + generalName_t *crluri; + bool strictcrlpolicy; }; extern bool trusted_ca(chunk_t a, chunk_t b, int *pathlen); extern bool match_requested_ca(generalName_t *requested_ca - , chunk_t our_ca, int *our_pathlen); + , chunk_t our_ca, int *our_pathlen); extern x509cert_t* get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid - , u_char auth_flags); + , u_char auth_flags); extern void load_authcerts(const char *type, const char *path - , u_char auth_flags); + , u_char auth_flags); extern x509cert_t* add_authcert(x509cert_t *cert, u_char auth_flags); extern void free_authcerts(void); extern void list_authcerts(const char *caption, u_char auth_flags, bool utc); extern bool trust_authcert_candidate(const x509cert_t *cert - , const x509cert_t *alt_chain); + , const x509cert_t *alt_chain); extern ca_info_t* get_ca_info(chunk_t name, chunk_t serial, 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); diff --git a/src/pluto/certs.c b/src/pluto/certs.c index 43976a913..ca3019b9b 100644 --- a/src/pluto/certs.c +++ b/src/pluto/certs.c @@ -1,5 +1,7 @@ /* Certificate support for IKE authentication - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * 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 @@ -10,8 +12,6 @@ * 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. - * - * RCSID $Id: certs.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdlib.h> @@ -19,241 +19,251 @@ #include <string.h> #include <freeswan.h> -#include <ipsec_policy.h> + +#include "library.h" +#include "asn1/asn1.h" #include "constants.h" #include "defs.h" #include "log.h" -#include "asn1.h" #include "id.h" -#include "x509.h" -#include "pgp.h" #include "pem.h" #include "certs.h" -#include "pkcs1.h" -/* +/** * used for initializatin of certs */ -const cert_t empty_cert = {CERT_NONE, {NULL}}; +const cert_t cert_empty = {CERT_NONE, {NULL}}; -/* +/** * extracts the certificate to be sent to the peer */ -chunk_t -get_mycert(cert_t cert) +chunk_t cert_get_encoding(cert_t cert) { - switch (cert.type) - { - case CERT_PGP: - return cert.u.pgp->certificate; - case CERT_X509_SIGNATURE: - return cert.u.x509->certificate; - default: - return empty_chunk; - } + switch (cert.type) + { + case CERT_PGP: + return cert.u.pgp->certificate; + case CERT_X509_SIGNATURE: + return cert.u.x509->certificate; + default: + return chunk_empty; + } +} + +public_key_t* cert_get_public_key(const cert_t cert) +{ + switch (cert.type) + { + case CERT_PGP: + return cert.u.pgp->public_key; + break; + case CERT_X509_SIGNATURE: + return cert.u.x509->public_key; + break; + default: + return NULL; + } } /* load a coded key or certificate file with autodetection * of binary DER or base64 PEM ASN.1 formats and armored PGP format */ -bool -load_coded_file(const char *filename, prompt_pass_t *pass, const char *type -, chunk_t *blob, bool *pgp) +bool load_coded_file(char *filename, prompt_pass_t *pass, const char *type, + chunk_t *blob, bool *pgp) { - err_t ugh = NULL; + err_t ugh = NULL; + + FILE *fd = fopen(filename, "r"); - FILE *fd = fopen(filename, "r"); + if (fd) + { + int bytes; + fseek(fd, 0, SEEK_END ); + blob->len = ftell(fd); + rewind(fd); + blob->ptr = malloc(blob->len); + bytes = fread(blob->ptr, 1, blob->len, fd); + fclose(fd); + plog(" loaded %s file '%s' (%d bytes)", type, filename, bytes); - if (fd) - { - int bytes; - fseek(fd, 0, SEEK_END ); - blob->len = ftell(fd); - rewind(fd); - blob->ptr = alloc_bytes(blob->len, type); - bytes = fread(blob->ptr, 1, blob->len, fd); - fclose(fd); - plog(" loaded %s file '%s' (%d bytes)", type, filename, bytes); + *pgp = FALSE; - *pgp = FALSE; + /* try DER format */ + if (is_asn1(*blob)) + { + DBG(DBG_PARSING, + DBG_log(" file coded in DER format"); + ) + return TRUE; + } - /* try DER format */ - if (is_asn1(*blob)) - { - DBG(DBG_PARSING, - DBG_log(" file coded in DER format"); - ) - return TRUE; - } + /* try PEM format */ + ugh = pemtobin(blob, pass, filename, pgp); - /* try PEM format */ - ugh = pemtobin(blob, pass, filename, pgp); + if (ugh == NULL) + { + if (*pgp) + { + DBG(DBG_PARSING, + DBG_log(" file coded in armored PGP format"); + ) + return TRUE; + } + if (is_asn1(*blob)) + { + DBG(DBG_PARSING, + DBG_log(" file coded in PEM format"); + ) + return TRUE; + } + ugh = "file coded in unknown format, discarded"; + } - if (ugh == NULL) + /* a conversion error has occured */ + plog(" %s", ugh); + free(blob->ptr); + *blob = chunk_empty; + } + else { - if (*pgp) - { - DBG(DBG_PARSING, - DBG_log(" file coded in armored PGP format"); - ) - return TRUE; - } - if (is_asn1(*blob)) - { - DBG(DBG_PARSING, - DBG_log(" file coded in PEM format"); - ) - return TRUE; - } - ugh = "file coded in unknown format, discarded"; + plog(" could not open %s file '%s'", type, filename); } - - /* a conversion error has occured */ - plog(" %s", ugh); - pfree(blob->ptr); - *blob = empty_chunk; - } - else - { - plog(" could not open %s file '%s'", type, filename); - } - return FALSE; + return FALSE; } -/* - * Loads a PKCS#1 or PGP private RSA key file +/** + * Loads a PKCS#1 or PGP privatekey file */ -err_t -load_rsa_private_key(const char* filename, prompt_pass_t *pass -, RSA_private_key_t *key) +private_key_t* load_private_key(char* filename, prompt_pass_t *pass, + key_type_t type) { - err_t ugh = NULL; - bool pgp = FALSE; - chunk_t blob = empty_chunk; + private_key_t *key = NULL; + chunk_t blob = chunk_empty; + bool pgp = FALSE; - const char *path = concatenate_paths(PRIVATE_KEY_PATH, filename); + char *path = concatenate_paths(PRIVATE_KEY_PATH, filename); - if (load_coded_file(path, pass, "private key", &blob, &pgp)) - { - if (pgp) + if (load_coded_file(path, pass, "private key", &blob, &pgp)) { - if (!parse_pgp(blob, NULL, key)) - ugh = "syntax error in PGP private key file"; + if (pgp) + { + parse_pgp(blob, NULL, &key); + } + else + { + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, + BUILD_BLOB_ASN1_DER, blob, BUILD_END); + } + if (key == NULL) + { + plog(" syntax error in %s private key file", pgp ? "PGP":"PKCS#"); + } + free(blob.ptr); } else { - if (!pkcs1_parse_private_key(blob, key)) - ugh = "syntax error in PKCS#1 private key file"; + plog(" error loading private key file"); } - pfree(blob.ptr); - } - else - ugh = "error loading RSA private key file"; - - return ugh; + return key; } -/* + +/** * Loads a X.509 or OpenPGP certificate */ -bool -load_cert(const char *filename, const char *label, cert_t *cert) +bool load_cert(char *filename, const char *label, cert_t *cert) { - bool pgp = FALSE; - chunk_t blob = empty_chunk; + bool pgp = FALSE; + chunk_t blob = chunk_empty; - /* initialize cert struct */ - cert->type = CERT_NONE; - cert->u.x509 = NULL; + /* initialize cert struct */ + cert->type = CERT_NONE; + cert->u.x509 = NULL; - if (load_coded_file(filename, NULL, label, &blob, &pgp)) - { - if (pgp) - { - pgpcert_t *pgpcert = alloc_thing(pgpcert_t, "pgpcert"); - *pgpcert = empty_pgpcert; - if (parse_pgp(blob, pgpcert, NULL)) - { - cert->type = CERT_PGP; - cert->u.pgp = pgpcert; - return TRUE; - } - else - { - plog(" error in OpenPGP certificate"); - free_pgpcert(pgpcert); - return FALSE; - } - } - else + if (load_coded_file(filename, NULL, label, &blob, &pgp)) { - x509cert_t *x509cert = alloc_thing(x509cert_t, "x509cert"); - *x509cert = empty_x509cert; - if (parse_x509cert(blob, 0, x509cert)) - { - cert->type = CERT_X509_SIGNATURE; - cert->u.x509 = x509cert; - return TRUE; - } - else - { - plog(" error in X.509 certificate"); - free_x509cert(x509cert); - return FALSE; - } + if (pgp) + { + pgpcert_t *pgpcert = malloc_thing(pgpcert_t); + *pgpcert = pgpcert_empty; + if (parse_pgp(blob, pgpcert, NULL)) + { + cert->type = CERT_PGP; + cert->u.pgp = pgpcert; + return TRUE; + } + else + { + plog(" error in OpenPGP certificate"); + free_pgpcert(pgpcert); + return FALSE; + } + } + else + { + x509cert_t *x509cert = malloc_thing(x509cert_t); + *x509cert = empty_x509cert; + if (parse_x509cert(blob, 0, x509cert)) + { + cert->type = CERT_X509_SIGNATURE; + cert->u.x509 = x509cert; + return TRUE; + } + else + { + plog(" error in X.509 certificate"); + free_x509cert(x509cert); + return FALSE; + } + } } - } - return FALSE; + return FALSE; } -/* +/** * Loads a host certificate */ -bool -load_host_cert(const char *filename, cert_t *cert) +bool load_host_cert(char *filename, cert_t *cert) { - const char *path = concatenate_paths(HOST_CERT_PATH, filename); + char *path = concatenate_paths(HOST_CERT_PATH, filename); - return load_cert(path, "host cert", cert); + return load_cert(path, "host cert", cert); } -/* +/** * Loads a CA certificate */ -bool -load_ca_cert(const char *filename, cert_t *cert) +bool load_ca_cert(char *filename, cert_t *cert) { - const char *path = concatenate_paths(CA_CERT_PATH, filename); + char *path = concatenate_paths(CA_CERT_PATH, filename); - return load_cert(path, "CA cert", cert); + return load_cert(path, "CA cert", cert); } -/* +/** * establish equality of two certificates */ -bool -same_cert(const cert_t *a, const cert_t *b) +bool same_cert(const cert_t *a, const cert_t *b) { - return a->type == b->type && a->u.x509 == b->u.x509; + return a->type == b->type && a->u.x509 == b->u.x509; } -/* for each link pointing to the certif icate - " increase the count by one +/** + * for each link pointing to the certificate increase the count by one */ -void -share_cert(cert_t cert) +void share_cert(cert_t cert) { - switch (cert.type) - { - case CERT_PGP: - share_pgpcert(cert.u.pgp); - break; - case CERT_X509_SIGNATURE: - share_x509cert(cert.u.x509); - break; - default: - break; - } + switch (cert.type) + { + case CERT_PGP: + share_pgpcert(cert.u.pgp); + break; + case CERT_X509_SIGNATURE: + share_x509cert(cert.u.x509); + break; + default: + break; + } } /* release of a certificate decreases the count by one @@ -263,16 +273,16 @@ void release_cert(cert_t cert) { switch (cert.type) - { - case CERT_PGP: - release_pgpcert(cert.u.pgp); - break; - case CERT_X509_SIGNATURE: - release_x509cert(cert.u.x509); - break; - default: - break; - } + { + case CERT_PGP: + release_pgpcert(cert.u.pgp); + break; + case CERT_X509_SIGNATURE: + release_x509cert(cert.u.x509); + break; + default: + break; + } } /* @@ -281,7 +291,7 @@ release_cert(cert_t cert) void list_certs(bool utc) { - list_x509_end_certs(utc); - list_pgp_end_certs(utc); + list_x509_end_certs(utc); + list_pgp_end_certs(utc); } diff --git a/src/pluto/certs.h b/src/pluto/certs.h index b71c53e15..0810c52fa 100644 --- a/src/pluto/certs.h +++ b/src/pluto/certs.h @@ -1,5 +1,7 @@ /* Certificate support for IKE authentication - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * 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 @@ -10,66 +12,65 @@ * 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. - * - * RCSID $Id: certs.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _CERTS_H #define _CERTS_H -#include "pkcs1.h" +#include <credentials/keys/private_key.h> + #include "x509.h" -#include "pgp.h" +#include "pgpcert.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" +#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 */ +#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 */ /* certificate access structure * currently X.509 and OpenPGP certificates are supported */ typedef struct { - u_char type; - union { - x509cert_t *x509; - pgpcert_t *pgp; - } u; + u_char type; + union { + x509cert_t *x509; + pgpcert_t *pgp; + } u; } cert_t; /* used for initialization */ -extern const cert_t empty_cert; +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 err_t load_rsa_private_key(const char* filename, prompt_pass_t *pass - , RSA_private_key_t *key); -extern chunk_t get_mycert(cert_t cert); -extern bool load_coded_file(const char *filename, prompt_pass_t *pass - , const char *type, chunk_t *blob, bool *pgp); -extern bool load_cert(const char *filename, const char *label - , cert_t *cert); -extern bool load_host_cert(const char *filename, cert_t *cert); -extern bool load_ca_cert(const char *filename, cert_t *cert); +extern public_key_t* cert_get_public_key(const cert_t cert); +extern chunk_t cert_get_encoding(cert_t cert); +extern private_key_t* load_private_key(char* filename, prompt_pass_t *pass, + key_type_t type); +extern bool load_coded_file(char *filename, prompt_pass_t *pass, + const char *type, chunk_t *blob, bool *pgp); +extern bool load_cert(char *filename, const char *label, cert_t *cert); +extern bool load_host_cert(char *filename, cert_t *cert); +extern bool load_ca_cert(char *filename, cert_t *cert); extern bool same_cert(const cert_t *a, const cert_t *b); extern void share_cert(cert_t cert); extern void release_cert(cert_t cert); diff --git a/src/pluto/connections.c b/src/pluto/connections.c index cd118cb34..4deb722f7 100644 --- a/src/pluto/connections.c +++ b/src/pluto/connections.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: connections.c 4924 2009-03-10 21:13:18Z andreas $ */ #include <string.h> @@ -25,20 +23,21 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ +#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ #include <sys/queue.h> #include <freeswan.h> -#include <ipsec_policy.h> #include "kameipsec.h" +#include <credentials/keys/private_key.h> + #include "constants.h" #include "defs.h" #include "id.h" #include "x509.h" #include "ca.h" #include "crl.h" -#include "pgp.h" +#include "pgpcert.h" #include "certs.h" #include "ac.h" #include "smartcard.h" @@ -48,13 +47,13 @@ #include "demux.h" #include "state.h" #include "timer.h" -#include "ipsec_doi.h" /* needs demux.h and state.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 "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" @@ -62,7 +61,7 @@ #include "nat_traversal.h" #include "virtual.h" -static void flush_pending_by_connection(struct connection *c); /* forward */ +static void flush_pending_by_connection(struct connection *c); /* forward */ static struct connection *connections = NULL; @@ -77,14 +76,14 @@ static struct connection *connections = NULL; */ struct host_pair { - struct { - ip_address addr; - u_int16_t port; /* host order */ - } me, him; - bool initial_connection_sent; - struct connection *connections; /* connections with this pair */ - struct pending *pending; /* awaiting Keying Channel */ - struct host_pair *next; + struct { + ip_address addr; + u_int16_t port; /* host order */ + } me, him; + bool initial_connection_sent; + struct connection *connections; /* connections with this pair */ + struct pending *pending; /* awaiting Keying Channel */ + struct host_pair *next; }; static struct host_pair *host_pairs = NULL; @@ -96,45 +95,45 @@ bool same_peer_ids(const struct connection *c, const struct connection *d , const struct id *his_id) { - return same_id(&c->spd.this.id, &d->spd.this.id) - && same_id(his_id == NULL? &c->spd.that.id : his_id, &d->spd.that.id); + return same_id(&c->spd.this.id, &d->spd.this.id) + && same_id(his_id == NULL? &c->spd.that.id : his_id, &d->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) + struct host_pair *p, *prev; + + /* default hisaddr to an appropriate any */ + if (hisaddr == NULL) + hisaddr = aftoinfo(addrtypeof(myaddr))->any; + + if (nat_traversal_enabled) { - if (prev != NULL) - { - prev->next = p->next; /* remove p from list */ - p->next = host_pairs; /* and stick it on front */ - host_pairs = p; - } - break; + /** + * port is not relevant in host_pair. with nat_traversal we + * always use pluto_port (500) + */ + myport = pluto_port; + hisport = pluto_port; } - } - return p; + + 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 != NULL) + { + 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 */ @@ -142,63 +141,63 @@ static struct connection * 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) - { - struct connection *c; + struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport); - for (c = hp->connections; c != NULL; c = c->hp_next) + if (nat_traversal_enabled && hp && hisaddr) { - if (c->spd.this.host_port == myport && c->spd.that.host_port == hisport) - return c; + struct connection *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 NULL; - } - return hp == NULL? NULL : hp->connections; + return hp == NULL? NULL : hp->connections; } static void connect_to_host_pair(struct connection *c) { - if (oriented(*c)) - { - struct host_pair *hp; + 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; + 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); + hp = find_host_pair(&c->spd.this.host_addr, c->spd.this.host_port + , &his_addr, c->spd.that.host_port); - if (hp == NULL) + 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 { - /* no suitable host_pair -- build one */ - hp = alloc_thing(struct host_pair, "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; + /* 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; } - 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. @@ -209,317 +208,317 @@ connect_to_host_pair(struct connection *c) struct connection * con_by_name(const char *nm, bool strict) { - struct connection *p, *prev; + struct connection *p, *prev; - for (prev = NULL, p = connections; ; prev = p, p = p->ac_next) - { - if (p == NULL) + for (prev = NULL, p = connections; ; prev = p, p = p->ac_next) { - 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 != NULL) - { - prev->ac_next = p->ac_next; /* remove p from list */ - p->ac_next = connections; /* and stick it on front */ - connections = p; - } - break; + 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 != NULL) + { + prev->ac_next = p->ac_next; /* remove p from list */ + p->ac_next = connections; /* and stick it on front */ + connections = p; + } + break; + } } - } - return p; + return p; } void release_connection(struct connection *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); - } + 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; \ - } + 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(struct connection *c, bool relations) { - struct connection *old_cur_connection - = cur_connection == c? NULL : cur_connection; + struct connection *old_cur_connection + = cur_connection == c? NULL : cur_connection; #ifdef DEBUG - lset_t old_cur_debugging = cur_debugging; + 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(struct connection, 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(struct connection, hp_next, c, unoriented_connections); - } - else - { - struct host_pair *hp = c->host_pair; - - list_rm(struct connection, 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. + set_cur_connection(c); + + /* Must be careful to avoid circularity: + * we mark c as going away so it won't get deleted recursively. */ - if (hp->connections == NULL - && !hp->initial_connection_sent) + 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(struct connection, ac_next, c, connections); + cur_connection = old_cur_connection; + + /* find and delete c from the host pair list */ + if (c->host_pair == NULL) { - passert(hp->pending == NULL); /* ??? must deal with this! */ - list_rm(struct host_pair, next, hp, host_pairs); - pfree(hp); + if (c->ikev1) + list_rm(struct connection, hp_next, c, unoriented_connections); } - } + else + { + struct host_pair *hp = c->host_pair; - if (c->kind != CK_GOING_AWAY) - pfreeany(c->spd.that.virt); + list_rm(struct connection, 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); + } #ifdef DEBUG - cur_debugging = old_cur_debugging; + cur_debugging = old_cur_debugging; #endif - pfreeany(c->name); - free_id_content(&c->spd.this.id); - pfreeany(c->spd.this.updown); - freeanychunk(c->spd.this.ca); - free_ietfAttrList(c->spd.this.groups); - free_id_content(&c->spd.that.id); - pfreeany(c->spd.that.updown); - freeanychunk(c->spd.that.ca); - free_ietfAttrList(c->spd.that.groups); - free_generalNames(c->requested_ca, TRUE); - gw_delref(&c->gw_info); - - lock_certs_and_keys("delete_connection"); - release_cert(c->spd.this.cert); - scx_release(c->spd.this.sc); - release_cert(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); - - pfree(c); + free(c->name); + free_id_content(&c->spd.this.id); + free(c->spd.this.updown); + free(c->spd.this.ca.ptr); + free_ietfAttrList(c->spd.this.groups); + free_id_content(&c->spd.that.id); + free(c->spd.that.updown); + free(c->spd.that.ca.ptr); + free_ietfAttrList(c->spd.that.groups); + free_generalNames(c->requested_ca, TRUE); + gw_delref(&c->gw_info); + + lock_certs_and_keys("delete_connection"); + release_cert(c->spd.this.cert); + scx_release(c->spd.this.sc); + release_cert(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) { - struct connection *c = con_by_name(name, strict); + struct connection *c = con_by_name(name, strict); - for (; c != NULL; c = con_by_name(name, FALSE)) - delete_connection(c, FALSE); + for (; c != NULL; c = con_by_name(name, FALSE)) + delete_connection(c, FALSE); } void delete_every_connection(void) { - while (connections != NULL) - delete_connection(connections, TRUE); + while (connections != NULL) + delete_connection(connections, TRUE); } void release_dead_interfaces(void) { - struct host_pair *hp; - - for (hp = host_pairs; hp != NULL; hp = hp->next) - { - struct connection **pp - , *p; + struct host_pair *hp; - for (pp = &hp->connections; (p = *pp) != NULL; ) + for (hp = host_pairs; hp != NULL; hp = hp->next) { - 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; + struct connection **pp + , *p; - *pp = p->hp_next; /* advance *pp */ - p->host_pair = NULL; - p->hp_next = unoriented_connections; - unoriented_connections = p; - } - else + for (pp = &hp->connections; (p = *pp) != NULL; ) { - /* The connection should have vanished, - * but the previous connection remains. - */ - passert(p != *pp); + 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 */ + } } - } - 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 */ - { - struct connection *c = unoriented_connections; + /* try to orient all the unoriented connections */ + { + struct connection *c = unoriented_connections; - unoriented_connections = NULL; + unoriented_connections = NULL; - while (c != NULL) - { - struct connection *nxt = c->hp_next; + while (c != NULL) + { + struct connection *nxt = c->hp_next; - (void)orient(c); - connect_to_host_pair(c); - c = nxt; + (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) + /* Check that no oriented connection has become double-oriented. + * In other words, the far side must not match one of our new interfaces. + */ { - if (i->change == IFN_ADD) - { - struct host_pair *hp; + struct iface *i; - for (hp = host_pairs; hp != NULL; hp = hp->next) + for (i = interfaces; i != NULL; i = i->next) { - if (sameaddr(&hp->him.addr, &i->addr) - && (!no_klips || 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). - */ - struct connection *c = hp->connections; - - hp->connections = NULL; - while (c != NULL) + if (i->change == IFN_ADD) { - struct connection *nxt = c->hp_next; - - c->interface = NULL; - (void)orient(c); - connect_to_host_pair(c); - c = nxt; + struct host_pair *hp; + + for (hp = host_pairs; hp != NULL; hp = hp->next) + { + if (sameaddr(&hp->him.addr, &i->addr) + && (!no_klips || 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). + */ + struct connection *c = hp->connections; + + hp->connections = NULL; + while (c != NULL) + { + struct connection *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; - const struct af_info *afi = aftoinfo(addrtypeof(&e->host_addr)); - - if (afi == NULL) - return "unknown address family in default_end"; - - /* default ID to IP (but only if not NO_IP -- WildCard) */ - if (e->id.kind == ID_NONE && !isanyaddr(&e->host_addr)) - { - e->id.kind = afi->id_addr; - e->id.ip_addr = 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; + err_t ugh = NULL; + const struct af_info *afi = aftoinfo(addrtypeof(&e->host_addr)); + + if (afi == NULL) + return "unknown address family in default_end"; + + /* default ID to IP (but only if not NO_IP -- WildCard) */ + if (e->id.kind == ID_ANY && !isanyaddr(&e->host_addr)) + { + e->id.kind = afi->id_addr; + e->id.ip_addr = 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. @@ -535,710 +534,702 @@ format_end(char *buf , bool is_left , lset_t policy) { - char client[SUBNETTOT_BUF]; - 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)) + char client[SUBNETTOT_BUF]; + 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)) { - case POLICY_GROUP: - host = "%group"; - break; - case POLICY_OPPO: - host = "%opportunistic"; - break; - case POLICY_GROUP | POLICY_OPPO: - host = "%opportunisticgroup"; - break; - default: - host = "%any"; - break; + 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)) - strcpy(client, "?"); + + 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)) + strcpy(client, "?"); + else + subnettot(&this->client, 0, client, sizeof(client)); + } + else if (this->modecfg && isanyaddr(&this->host_srcip)) + { + /* we are mode config client */ + client_sep = "==="; + strcpy(client, "%modecfg"); + } + + /* 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, if different from host */ + host_id[0] = '\0'; + if (this->id.kind == ID_MYID) + { + strcpy(host_id, "[%myid]"); + } + else if (!(this->id.kind == ID_ANY + || (id_is_ipaddr(&this->id) && sameaddr(&this->id.ip_addr, &this->host_addr)))) + { + int len = idtoa(&this->id, host_id+1, sizeof(host_id)-2); + + host_id[0] = '['; + strcpy(&host_id[len < 0? (ptrdiff_t)sizeof(host_id)-2 : 1 + len], "]"); + } + + /* [---hop] */ + hop[0] = '\0'; + hop_sep = ""; + if (that != NULL && !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 - subnettot(&this->client, 0, client, sizeof(client)); - } - else if (this->modecfg && isanyaddr(&this->host_srcip)) - { - /* we are mode config client */ - client_sep = "==="; - strcpy(client, "%modecfg"); - } - - /* 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, if different from host */ - host_id[0] = '\0'; - if (this->id.kind == ID_MYID) - { - strcpy(host_id, "[%myid]"); - } - else if (!(this->id.kind == ID_NONE - || (id_is_ipaddr(&this->id) && sameaddr(&this->id.ip_addr, &this->host_addr)))) - { - int len = idtoa(&this->id, host_id+1, sizeof(host_id)-2); - - host_id[0] = '['; - strcpy(&host_id[len < 0? (ptrdiff_t)sizeof(host_id)-2 : 1 + len], "]"); - } - - /* [---hop] */ - hop[0] = '\0'; - hop_sep = ""; - if (that != NULL && !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); + 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) +#define CONNECTION_BUF (2 * (END_BUF - 1) + 4) static size_t format_connection(char *buf, size_t buf_len - , const struct connection *c - , struct spd_route *sr) + , const struct connection *c + , struct spd_route *sr) { - size_t w = format_end(buf, buf_len, &sr->this, &sr->that, TRUE, LEMPTY); + 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); + 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(struct connection *c) { - c->name = clone_str(c->name, "connection name"); - - unshare_id_content(&c->spd.this.id); - c->spd.this.updown = clone_str(c->spd.this.updown, "updown"); - scx_share(c->spd.this.sc); - share_cert(c->spd.this.cert); - if (c->spd.this.ca.ptr != NULL) - clonetochunk(c->spd.this.ca, c->spd.this.ca.ptr, c->spd.this.ca.len, "ca string"); - - unshare_id_content(&c->spd.that.id); - c->spd.that.updown = clone_str(c->spd.that.updown, "updown"); - scx_share(c->spd.that.sc); - share_cert(c->spd.that.cert); - if (c->spd.that.ca.ptr != NULL) - clonetochunk(c->spd.that.ca, c->spd.that.ca.ptr, c->spd.that.ca.len, "ca string"); - - /* 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); + c->name = clone_str(c->name); + + unshare_id_content(&c->spd.this.id); + c->spd.this.updown = clone_str(c->spd.this.updown); + scx_share(c->spd.this.sc); + share_cert(c->spd.this.cert); + c->spd.this.ca = chunk_clone(c->spd.this.ca); + + unshare_id_content(&c->spd.that.id); + c->spd.that.updown = clone_str(c->spd.that.updown); + scx_share(c->spd.that.sc); + share_cert(c->spd.that.cert); + c->spd.that.ca = chunk_clone(c->spd.that.ca); + + /* 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(const char *filename, struct end *dst) +static void load_end_certificate(char *filename, struct end *dst) { - time_t valid_until; - cert_t cert; - bool valid_cert = FALSE; - bool cached_cert = FALSE; + time_t valid_until; + cert_t cert; + bool valid_cert = FALSE; + bool cached_cert = FALSE; - /* initialize end certificate */ - dst->cert.type = CERT_NONE; - dst->cert.u.x509 = NULL; + /* initialize end certificate */ + dst->cert.type = CERT_NONE; + dst->cert.u.x509 = NULL; - /* initialize smartcard info record */ - dst->sc = NULL; + /* initialize smartcard info record */ + dst->sc = NULL; - if (filename != NULL) - { - if (scx_on_smartcard(filename)) + if (filename != NULL) { - /* load cert from smartcard */ - valid_cert = scx_load_cert(filename, &dst->sc, &cert, &cached_cert); - } - else - { - /* load cert from file */ - valid_cert = load_host_cert(filename, &cert); + if (scx_on_smartcard(filename)) + { + /* load cert from smartcard */ + valid_cert = scx_load_cert(filename, &dst->sc, &cert, &cached_cert); + } + else + { + /* load cert from file */ + valid_cert = load_host_cert(filename, &cert); + } } - } - if (valid_cert) - { - err_t ugh = NULL; - - switch (cert.type) + if (valid_cert) { - case CERT_PGP: - select_pgpcert_id(cert.u.pgp, &dst->id); - - if (cached_cert) - dst->cert = cert; - else - { - valid_until = cert.u.pgp->until; - add_pgp_public_key(cert.u.pgp, cert.u.pgp->until, DAL_LOCAL); - dst->cert.type = cert.type; - dst->cert.u.pgp = add_pgpcert(cert.u.pgp); - } - break; - case CERT_X509_SIGNATURE: - select_x509cert_id(cert.u.x509, &dst->id); - - if (cached_cert) - dst->cert = cert; - else - { - /* check validity of cert */ - valid_until = cert.u.x509->notAfter; - ugh = check_validity(cert.u.x509, &valid_until); - if (ugh != NULL) + err_t ugh = NULL; + + switch (cert.type) { - plog(" %s", ugh); - free_x509cert(cert.u.x509); - break; - } + case CERT_PGP: + select_pgpcert_id(cert.u.pgp, &dst->id); - DBG(DBG_CONTROL, - DBG_log("certificate is valid") - ) - add_x509_public_key(cert.u.x509, valid_until, DAL_LOCAL); - dst->cert.type = cert.type; - dst->cert.u.x509 = add_x509cert(cert.u.x509); - } - /* if no CA is defined, use issuer as default */ - if (dst->ca.ptr == NULL) - dst->ca = dst->cert.u.x509->issuer; - break; - default: - break; - } + if (cached_cert) + dst->cert = cert; + else + { + valid_until = cert.u.pgp->until; + add_pgp_public_key(cert.u.pgp, cert.u.pgp->until, DAL_LOCAL); + dst->cert.type = cert.type; + dst->cert.u.pgp = add_pgpcert(cert.u.pgp); + } + break; + case CERT_X509_SIGNATURE: + select_x509cert_id(cert.u.x509, &dst->id); - /* cache the certificate that was last retrieved from the smartcard */ - if (dst->sc != NULL) - { - if (!same_cert(&dst->sc->last_cert, &dst->cert)) - { - lock_certs_and_keys("load_end_certificates"); - release_cert(dst->sc->last_cert); - dst->sc->last_cert = dst->cert; - share_cert(dst->cert); - unlock_certs_and_keys("load_end_certificates"); - } - time(&dst->sc->last_load); + if (cached_cert) + dst->cert = cert; + else + { + /* check validity of cert */ + valid_until = cert.u.x509->notAfter; + ugh = check_validity(cert.u.x509, &valid_until); + if (ugh != NULL) + { + plog(" %s", ugh); + free_x509cert(cert.u.x509); + break; + } + + DBG(DBG_CONTROL, + DBG_log("certificate is valid") + ) + add_x509_public_key(cert.u.x509, valid_until, DAL_LOCAL); + dst->cert.type = cert.type; + dst->cert.u.x509 = add_x509cert(cert.u.x509); + } + /* if no CA is defined, use issuer as default */ + if (dst->ca.ptr == NULL) + dst->ca = dst->cert.u.x509->issuer; + break; + default: + break; + } + + /* cache the certificate that was last retrieved from the smartcard */ + if (dst->sc != NULL) + { + if (!same_cert(&dst->sc->last_cert, &dst->cert)) + { + lock_certs_and_keys("load_end_certificates"); + release_cert(dst->sc->last_cert); + dst->sc->last_cert = dst->cert; + share_cert(dst->cert); + unlock_certs_and_keys("load_end_certificates"); + } + time(&dst->sc->last_load); + } } - } } static bool extract_end(struct end *dst, const whack_end_t *src, const char *which) { - bool same_ca = FALSE; - - /* decode id, if any */ - if (src->id == NULL) - { - dst->id.kind = ID_NONE; - } - else - { - err_t ugh = atoid(src->id, &dst->id, TRUE); + bool same_ca = FALSE; - if (ugh != NULL) + /* decode id, if any */ + if (src->id == NULL) { - loglog(RC_BADID, "bad %s --id: %s (ignored)", which, ugh); - dst->id = empty_id; /* ignore bad one */ + dst->id.kind = ID_ANY; } - } + else + { + err_t ugh = atoid(src->id, &dst->id, TRUE); - dst->ca = empty_chunk; + if (ugh != NULL) + { + loglog(RC_BADID, "bad %s --id: %s (ignored)", which, ugh); + dst->id = empty_id; /* ignore bad one */ + } + } + + dst->ca = chunk_empty; - /* decode CA distinguished name, if any */ - if (src->ca != NULL) - { - if streq(src->ca, "%same") - same_ca = TRUE; - else if (!streq(src->ca, "%any")) + /* decode CA distinguished name, if any */ + if (src->ca != NULL) { - err_t ugh; - - dst->ca.ptr = temporary_cyclic_buffer(); - ugh = atodn(src->ca, &dst->ca); - if (ugh != NULL) - { - plog("bad CA string '%s': %s (ignored)", src->ca, ugh); - dst->ca = empty_chunk; - } + if streq(src->ca, "%same") + same_ca = TRUE; + else if (!streq(src->ca, "%any")) + { + err_t ugh; + + dst->ca.ptr = temporary_cyclic_buffer(); + ugh = atodn(src->ca, &dst->ca); + if (ugh != NULL) + { + plog("bad CA string '%s': %s (ignored)", src->ca, ugh); + dst->ca = chunk_empty; + } + } } - } - - /* load local end certificate and extract ID, if any */ - load_end_certificate(src->cert, dst); - - /* does id has wildcards? */ - dst->has_id_wildcards = id_count_wildcards(&dst->id) > 0; - - /* decode group attributes, if any */ - decode_groups(src->groups, &dst->groups); - - /* the rest is simple copying of corresponding fields */ - dst->host_addr = src->host_addr; - dst->host_nexthop = src->host_nexthop; - dst->host_srcip = 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 = src->updown; - dst->host_port = src->host_port; - - /* if host sourceip is defined but no client is present - * behind the host then set client to sourceip/32 - */ - if (addrbytesptr(&dst->host_srcip, NULL) - && !isanyaddr(&dst->host_srcip) - && !dst->has_natip - && !dst->has_client) - { - err_t ugh = addrtosubnet(&dst->host_srcip, &dst->client); - if (ugh != NULL) - plog("could not assign host sourceip to client subnet"); - else - dst->has_client = TRUE; - } - return same_ca; + /* load local end certificate and extract ID, if any */ + load_end_certificate(src->cert, dst); + + /* does id has wildcards? */ + dst->has_id_wildcards = id_count_wildcards(&dst->id) > 0; + + /* decode group attributes, if any */ + decode_groups(src->groups, &dst->groups); + + /* the rest is simple copying of corresponding fields */ + dst->host_addr = src->host_addr; + dst->host_nexthop = src->host_nexthop; + dst->host_srcip = 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 = src->updown; + dst->host_port = src->host_port; + + /* if host sourceip is defined but no client is present + * behind the host then set client to sourceip/32 + */ + if (addrbytesptr(&dst->host_srcip, NULL) + && !isanyaddr(&dst->host_srcip) + && !dst->has_natip + && !dst->has_client) + { + err_t ugh = addrtosubnet(&dst->host_srcip, &dst->client); + + if (ugh != NULL) + 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 (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)) + if (isanyaddr(&that->host_addr)) { - loglog(RC_ORIENT, "connection must specify host IP address for our side"); - return FALSE; + /* 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; - } + 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 */ + return TRUE; /* happy */ } struct connection * find_connection_by_reqid(uint32_t reqid) { - struct connection *c; + struct connection *c; - reqid &= ~3; - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->spd.reqid == reqid) - return c; - } + reqid &= ~3; + for (c = connections; c != NULL; c = c->ac_next) + { + if (c->spd.reqid == reqid) + return c; + } - return NULL; + 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 ... */ + 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; - struct connection *c = alloc_thing(struct connection, "struct connection"); - - c->name = 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 KLIPS is not configured to do IPCOMP" - , c->name); - - if (wm->esp) + if (con_by_name(wm->name, FALSE) != NULL) { - const char *ugh; - - 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 : "", &ugh); - - DBG(DBG_CRYPT|DBG_CONTROL, - static char buf[256]="<NULL>"; - - if (c->alg_info_esp) - alg_info_snprint(buf, sizeof(buf) - ,(struct alg_info *)c->alg_info_esp); - DBG_log("esp string values: %s", buf); - ) - if (c->alg_info_esp) - { - if (c->alg_info_esp->alg_info_cnt==0) - loglog(RC_LOG_SERIOUS - , "got 0 transforms for esp=\"%s\"", wm->esp); - } - else - { - loglog(RC_LOG_SERIOUS - , "esp string error: %s", ugh? ugh : "Unknown"); - } + loglog(RC_DUPNAME, "attempt to redefine connection \"%s\"", wm->name); } - - if (wm->ike) + else if (wm->right.protocol != wm->left.protocol) { - const char *ugh; - - 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 : "", &ugh); - - DBG(DBG_CRYPT|DBG_CONTROL, - static char buf[256]="<NULL>"; - - if (c->alg_info_ike) - alg_info_snprint(buf, sizeof(buf) - , (struct alg_info *)c->alg_info_ike); - DBG_log("ike string values: %s", buf); - ) - if (c->alg_info_ike) - { - if (c->alg_info_ike->alg_info_cnt==0) - loglog(RC_LOG_SERIOUS - , "got 0 transforms for ike=\"%s\"", wm->ike); - } - else - { - loglog(RC_LOG_SERIOUS - , "ike string error: %s", ugh? ugh : "Unknown"); - } + /* 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"); } - - 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; + else if (check_connection_end(&wm->right, &wm->left, wm) + && check_connection_end(&wm->left, &wm->right, wm)) + { + bool same_rightca, same_leftca; + struct connection *c = malloc_thing(struct connection); - /* RFC 3706 DPD */ - c->dpd_delay = wm->dpd_delay; - c->dpd_timeout = wm->dpd_timeout; - c->dpd_action = wm->dpd_action; + zero(c); + c->name = wm->name; + c->ikev1 = wm->ikev1; + c->policy = wm->policy; - c->addr_family = wm->addr_family; - c->tunnel_addr_family = wm->tunnel_addr_family; + if ((c->policy & POLICY_COMPRESS) && !can_do_IPcomp) + loglog(RC_COMMENT + , "ignoring --compress in \"%s\" because KLIPS is not configured to do IPCOMP" + , c->name); - c->requested_ca = NULL; + 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 transforms for esp=\"%s\"", wm->esp); + } + else + { + loglog(RC_LOG_SERIOUS, "esp string error"); + } + } + + 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 transforms for ike=\"%s\"", wm->ike); + } + else + { + loglog(RC_LOG_SERIOUS, "ike string error:"); + } + } + + 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; - same_leftca = extract_end(&c->spd.this, &wm->left, "left"); - same_rightca = extract_end(&c->spd.that, &wm->right, "right"); + /* RFC 3706 DPD */ + c->dpd_delay = wm->dpd_delay; + c->dpd_timeout = wm->dpd_timeout; + c->dpd_action = wm->dpd_action; - if (same_rightca) - c->spd.that.ca = c->spd.this.ca; - else if (same_leftca) - c->spd.this.ca = c->spd.that.ca; + c->addr_family = wm->addr_family; + c->tunnel_addr_family = wm->tunnel_addr_family; - default_end(&c->spd.this, &c->spd.that.host_addr); - default_end(&c->spd.that, &c->spd.this.host_addr); + c->requested_ca = NULL; - /* 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; + same_leftca = extract_end(&c->spd.this, &wm->left, "left"); + same_rightca = extract_end(&c->spd.that, &wm->right, "right"); - c->spd.this = c->spd.that; - c->spd.that = t; - } + if (same_rightca) + c->spd.that.ca = c->spd.this.ca; + else if (same_leftca) + c->spd.this.ca = c->spd.that.ca; - c->spd.next = NULL; - c->spd.reqid = gen_reqid(); + default_end(&c->spd.this, &c->spd.that.host_addr); + default_end(&c->spd.that, &c->spd.this.host_addr); - /* 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 */ + /* 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 = gen_reqid(); + + /* 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; + c->extra_debugging = wm->debugging; #endif - c->gw_info = NULL; + 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; - } + 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; + } - unshare_connection_strings(c); - (void)orient(c); + unshare_connection_strings(c); + (void)orient(c); - if (c->ikev1) - connect_to_host_pair(c); + 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[CONNECTION_BUF]; - - (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)); - ); - } + /* log all about this connection */ + plog("added connection description \"%s\"", c->name); + DBG(DBG_CONTROL, + char topo[CONNECTION_BUF]; + + (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 pfreeing. + * Caller is responsible for freeing. */ char * add_group_instance(struct connection *group, const ip_subnet *target) { - char namebuf[100] - , targetbuf[SUBNETTOT_BUF]; - struct connection *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, "group instance"); - t->name = namebuf; - unshare_connection_strings(t); - name = clone_str(t->name, "group instance 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; + char namebuf[100] + , targetbuf[SUBNETTOT_BUF]; + struct connection *t; + char *name = NULL; - /* reset log file info */ - t->log_file_name = NULL; - t->log_file = NULL; - t->log_file_err = FALSE; + passert(group->kind == CK_GROUP); + passert(oriented(*group)); - t->spd.reqid = gen_reqid(); + /* manufacture a unique name for this template */ + subnettot(target, 0, targetbuf, sizeof(targetbuf)); + snprintf(namebuf, sizeof(namebuf), "%s#%s", group->name, targetbuf); - if (t->spd.that.virt) + if (con_by_name(namebuf, FALSE) != NULL) { - DBG_log("virtual_ip not supported in group instance"); - t->spd.that.virt = 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; + /* add to connections list */ + t->ac_next = connections; + connections = t; - /* same host_pair as parent: stick after parent on list */ - group->hp_next = 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"); + /* route if group is routed */ + if (group->policy & POLICY_GROUTED) + { + if (!trap_connection(t)) + whack_log(RC_ROUTE, "could not route"); + } } - } - return name; + return name; } /* an old target has disappeared for a group: delete instance */ @@ -1246,17 +1237,17 @@ void remove_group_instance(const struct connection *group USED_BY_DEBUG , const char *name) { - passert(group->kind == CK_GROUP); - passert(oriented(*group)); + passert(group->kind == CK_GROUP); + passert(oriented(*group)); - delete_connections_by_name(name, FALSE); + 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_NONE), the + * 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. * @@ -1267,90 +1258,90 @@ instantiate(struct connection *c, const ip_address *him , u_int16_t his_port , const struct id *his_id) { - struct connection *d; - int wildcards; - - passert(c->kind == CK_TEMPLATE); - passert(c->spd.next == NULL); - - c->instance_serial++; - d = clone_thing(*c, "temporary connection"); - d->spd.that.allow_any = FALSE; - - if (his_id != NULL) - { - passert(match_id(his_id, &d->spd.that.id, &wildcards)); - d->spd.that.id = *his_id; - d->spd.that.has_id_wildcards = FALSE; - } - unshare_connection_strings(d); - unshare_ietfAttrList(&d->spd.this.groups); - unshare_ietfAttrList(&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); - - return d; - if (sameaddr(&d->spd.that.host_addr, &d->spd.this.host_nexthop)) - { - d->spd.this.host_nexthop = *him; - } + struct connection *d; + int wildcards; + + 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 != NULL) + { + passert(match_id(his_id, &d->spd.that.id, &wildcards)); + d->spd.that.id = *his_id; + d->spd.that.has_id_wildcards = FALSE; + } + unshare_connection_strings(d); + unshare_ietfAttrList(&d->spd.this.groups); + unshare_ietfAttrList(&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); + + return d; + if (sameaddr(&d->spd.that.host_addr, &d->spd.this.host_nexthop)) + { + d->spd.this.host_nexthop = *him; + } } struct connection * rw_instantiate(struct connection *c, const ip_address *him, u_int16_t his_port , const ip_subnet *his_net, const struct id *his_id) { - struct connection *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; + struct connection *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; } struct connection * @@ -1361,77 +1352,77 @@ oppo_instantiate(struct connection *c , const ip_address *our_client USED_BY_DEBUG , const ip_address *peer_client) { - struct connection *d = instantiate(c, him, 0, his_id); + struct connection *d = instantiate(c, him, 0, his_id); - passert(d->spd.next == NULL); + 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 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. + /* fill in peer's client side. + * If the client is the peer, excise the client from the connection. */ - passert(addrinsubnet(our_client, &d->spd.this.client)); - happy(addrtosubnet(our_client, &d->spd.this.client)); + 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.this.client.addr); - } - else - { - /* there was no client in the abstract connection - * so we demand that the required client be the host + 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. */ - 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[CONNECTION_BUF]; - - (void) format_connection(topo, sizeof(topo), d, &d->spd); - DBG_log("instantiated \"%s\": %s", d->name, topo); - ); - return d; + if (routed(c->spd.routing)) + d->instance_initiation_ok = TRUE; + + DBG(DBG_CONTROL, + char topo[CONNECTION_BUF]; + + (void) format_connection(topo, sizeof(topo), d, &d->spd); + DBG_log("instantiated \"%s\": %s", d->name, topo); + ); + return d; } /* 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); + 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. @@ -1442,65 +1433,65 @@ fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]) 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 */ + if (subnetisaddr(client, gw)) + { + buf[0] = '\0'; /* compact denotation for "self" */ + } else - subnettot(client, 0, ap, SUBNETTOT_BUF); - } - return strlen(buf); + { + 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 struct connection *c, char buf[CONN_INST_BUF]) { - char *p = buf; + char *p = buf; - *p = '\0'; + *p = '\0'; - if (c->kind == CK_INSTANCE) - { - if (c->instance_serial != 0) + if (c->kind == CK_INSTANCE) { - snprintf(p, CONN_INST_BUF, "[%lu]", c->instance_serial); - p += strlen(p); - } + 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); + if (c->policy & POLICY_OPPO) + { + size_t w = fmt_client(&c->spd.this.client, &c->spd.this.host_addr, " ", p); - p += w; + p += w; - strcpy(p, w == 0? " ..." : "=== ..."); - p += strlen(p); + strcpy(p, w == 0? " ..." : "=== ..."); + p += strlen(p); - addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF); - 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); + (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); - } + 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. @@ -1520,124 +1511,124 @@ fmt_conn_instance(const struct connection *c, char buf[CONN_INST_BUF]) */ struct connection * find_connection_for_clients(struct spd_route **srp, - const ip_address *our_client, - const ip_address *peer_client, - int transport_proto) + const ip_address *our_client, + const ip_address *peer_client, + int transport_proto) { - struct connection *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)); + struct connection *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]; + 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); - } + 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) + for (c = connections; c != NULL; c = c->ac_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]; + 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); + 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); - } + 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 == 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!= NULL && NEVER_NEGOTIATE(best->policy)) - best = NULL; + if (best!= NULL && NEVER_NEGOTIATE(best->policy)) + best = NULL; - if (srp != NULL && best != NULL) - *srp = best_sr; + if (srp != NULL && best != NULL) + *srp = best_sr; #ifdef DEBUG - if (DBGP(DBG_CONTROL)) - { - if (best) + if (DBGP(DBG_CONTROL)) { - 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"); + 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; + return best; } /* Find and instantiate a connection for an outgoing Opportunistic connection. @@ -1664,203 +1655,203 @@ find_connection_for_clients(struct spd_route **srp, */ struct connection * build_outgoing_opportunistic_connection(struct gw_info *gw - ,const ip_address *our_client - ,const ip_address *peer_client) + ,const ip_address *our_client + ,const ip_address *peer_client) { - struct iface *p; - struct connection *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)); - - passert(!isanyaddr(our_client) && !isanyaddr(peer_client)); - - /* We don't know his ID yet, so gw id must be an ipaddr */ - passert(gw->key != NULL); - passert(id_is_ipaddr(&gw->gw_id)); - - /* 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). - */ - struct connection *c = find_host_pair_connections(&p->addr - , pluto_port, (ip_address *)NULL, pluto_port); + struct iface *p; + struct connection *best = NULL; + struct spd_route *sr, *bestsr; + char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; - for (; c != NULL; c = c->hp_next) + addrtot(our_client, 0, ocb, sizeof(ocb)); + addrtot(peer_client, 0, pcb, sizeof(pcb)); + + passert(!isanyaddr(our_client) && !isanyaddr(peer_client)); + + /* We don't know his ID yet, so gw id must be an ipaddr */ + passert(gw->key != NULL); + passert(id_is_ipaddr(&gw->gw_id)); + + /* for each of our addresses... */ + for (p = interfaces; p != NULL; p = p->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)) + /* 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). + */ + struct connection *c = find_host_pair_connections(&p->addr + , pluto_port, (ip_address *)NULL, pluto_port); + + for (; c != NULL; c = c->hp_next) { - 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))) + DBG(DBG_OPPO, + DBG_log("checking %s", c->name)); + if (c->kind == CK_GROUP) { - best = c; + 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 - return oppo_instantiate(best, &gw->gw_id.ip_addr, NULL, gw - , our_client, peer_client); + if (best == NULL + || NEVER_NEGOTIATE(best->policy) + || (best->policy & POLICY_OPPO) == LEMPTY + || best->kind != CK_TEMPLATE) + return NULL; + else + return oppo_instantiate(best, &gw->gw_id.ip_addr, NULL, gw + , our_client, peer_client); } bool orient(struct connection *c) { - struct spd_route *sr; - - if (!oriented(*c)) - { - struct iface *p; + struct spd_route *sr; - for (sr = &c->spd; sr; sr = sr->next) + if (!oriented(*c)) { - /* 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 (;;) + struct iface *p; + + for (sr = &c->spd; sr; sr = sr->next) { - /* check if this interface matches this end */ - if (sameaddr(&sr->this.host_addr, &p->addr) - && (!no_klips || sr->this.host_port == pluto_port)) - { - if (oriented(*c)) + /* 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 (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; + if (p->ike_float) + continue; + + for (;;) + { + /* check if this interface matches this end */ + if (sameaddr(&sr->this.host_addr, &p->addr) + && (!no_klips || 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) + && (!no_klips || 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; + } + } } - c->interface = p; - } - - /* done with this interface if it doesn't match that end */ - if (!(sameaddr(&sr->that.host_addr, &p->addr) - && (!no_klips || 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); + return oriented(*c); } void initiate_connection(const char *name, int whackfd) { - struct connection *c = con_by_name(name, TRUE); + struct connection *c = con_by_name(name, TRUE); - if (c != NULL && 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 + if (c != NULL && c->ikev1) { - /* do we have to prompt for a PIN code? */ - if (c->spd.this.sc != NULL && !c->spd.this.sc->valid && whackfd != NULL_FD) - { - scx_get_pin(c->spd.this.sc, whackfd); - } - if (c->spd.this.sc != NULL && !c->spd.this.sc->valid) - { - loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN"); - } - else - { - - if (c->spd.that.allow_any) + 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) { - c = instantiate(c, &c->spd.that.host_addr, c->spd.that.host_port - , &c->spd.that.id); + 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 != NULL && !c->spd.this.sc->valid && whackfd != NULL_FD) + { + scx_get_pin(c->spd.this.sc, whackfd); + } + if (c->spd.this.sc != NULL && !c->spd.this.sc->valid) + { + loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN"); + } + else + { - /* 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 */ - } + 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(); } - reset_cur_connection(); - } - close_any(whackfd); + close_any(whackfd); } /* (Possibly) Opportunistic Initiation: @@ -1874,10 +1865,10 @@ initiate_connection(const char *name, int whackfd) * 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 + * 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! @@ -1887,174 +1878,174 @@ initiate_connection(const char *name, int whackfd) */ 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, + 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, + fos_our_key, #endif /* USE_KEYRR */ - fos_his_client, - fos_done + 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", + "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", + "fos_our_key", #endif /* USE_KEYRR */ - "fos_his_client", - "fos_done" + "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; + 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; + struct adns_continuation ac; /* common prefix */ + struct find_oppo_bundle b; }; static void cannot_oppo(struct connection *c - , struct find_oppo_bundle *b - , err_t ugh) + , struct find_oppo_bundle *b + , err_t ugh) { - char pcb[ADDRTOT_BUF]; - char ocb[ADDRTOT_BUF]; + char pcb[ADDRTOT_BUF]; + char ocb[ADDRTOT_BUF]; - addrtot(&b->peer_client, 0, pcb, sizeof(pcb)); - addrtot(&b->our_client, 0, ocb, sizeof(ocb)); + 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)); + 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); + whack_log(RC_OPPOFAILURE + , "Can't Opportunistically initiate for %s to %s: %s" + , ocb, pcb, ugh); - if (c != NULL && c->policy_next != NULL) - { - /* there is some policy that comes afterwards */ - struct spd_route *shunt_spd; - struct connection *nc = c->policy_next; - struct state *st; + if (c != NULL && c->policy_next != NULL) + { + /* there is some policy that comes afterwards */ + struct spd_route *shunt_spd; + struct connection *nc = c->policy_next; + struct state *st; - passert(c->kind == CK_TEMPLATE); - passert(c->policy_next->kind == CK_PERMANENT); + 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)); + 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. - */ + /* + * 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 eroute policy"); + shunt_spd = clone_thing(nc->spd); - shunt_spd->next = nc->spd.next; - nc->spd.next = shunt_spd; + shunt_spd->next = nc->spd.next; + nc->spd.next = shunt_spd; - happy(addrtosubnet(&b->peer_client, &shunt_spd->that.client)); + 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; + 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; + /* + * 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. - */ + /* now, lookup the state, and poke it up. + */ - st = state_with_serialno(nc->newest_ipsec_sa); + st = state_with_serialno(nc->newest_ipsec_sa); - /* XXX what to do if the IPSEC SA has died? */ - passert(st != NULL); + /* 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 - */ + /* 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)); + 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); - } + 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); + 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; } - return; - } #ifdef KLIPS - if (b->held) - { - /* Replace HOLD with b->failure_shunt. - * If no b->failure_shunt specified, use SPI_PASS -- THIS MAY CHANGE. - */ - if (b->failure_shunt == 0) + if (b->held) { - DBG(DBG_OPPO, DBG_log("no explicit failure shunt for %s to %s; installing %%pass" - , ocb, pcb)); - } + /* Replace HOLD with b->failure_shunt. + * If no b->failure_shunt specified, use SPI_PASS -- THIS MAY CHANGE. + */ + if (b->failure_shunt == 0) + { + DBG(DBG_OPPO, DBG_log("no explicit failure shunt for %s to %s; installing %%pass" + , ocb, pcb)); + } - (void) replace_bare_shunt(&b->our_client, &b->peer_client - , b->policy_prio - , b->failure_shunt - , b->failure_shunt != 0 - , b->transport_proto - , ugh); - } + (void) replace_bare_shunt(&b->our_client, &b->peer_client + , b->policy_prio + , b->failure_shunt + , b->failure_shunt != 0 + , b->transport_proto + , ugh); + } #endif } static void initiate_opportunistic_body(struct find_oppo_bundle *b - , struct adns_continuation *ac, err_t ac_ugh); /* forward */ + , struct adns_continuation *ac, err_t ac_ugh); /* forward */ void initiate_opportunistic(const ip_address *our_client @@ -2063,93 +2054,93 @@ initiate_opportunistic(const ip_address *our_client , 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); + 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); } static void continue_oppo(struct adns_continuation *acr, err_t ugh) { - struct find_oppo_continuation *cr = (void *)acr; /* inherit, damn you! */ - struct connection *c; - bool was_held = cr->b.held; - int whackfd = cr->b.whackfd; + struct find_oppo_continuation *cr = (void *)acr; /* inherit, damn you! */ + struct connection *c; + bool was_held = cr->b.held; + int whackfd = cr->b.whackfd; - /* note: cr->id has no resources; cr->sgw_id is id_none: - * neither need freeing. - */ - whack_log_fd = whackfd; + /* note: cr->id has no resources; cr->sgw_id is ID_ANY: + * neither need freeing. + */ + whack_log_fd = whackfd; #ifdef KLIPS - /* Discover and record whether %hold has gone away. - * This could have happened while we were awaiting DNS. - * We must check BEFORE any call to cannot_oppo. - */ - if (was_held) - cr->b.held = has_bare_hold(&cr->b.our_client, &cr->b.peer_client - , cr->b.transport_proto); + /* Discover and record whether %hold has gone away. + * This could have happened while we were awaiting DNS. + * We must check BEFORE any call to cannot_oppo. + */ + if (was_held) + cr->b.held = has_bare_hold(&cr->b.our_client, &cr->b.peer_client + , cr->b.transport_proto); #endif #ifdef DEBUG - /* if we're going to ignore the error, at least note it in debugging log */ - if (cr->b.failure_ok && ugh != NULL) - { - DBG(DBG_CONTROL | DBG_DNS, - { + /* if we're going to ignore the error, at least note it in debugging log */ + if (cr->b.failure_ok && ugh != NULL) + { + 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 != NULL) + { + 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)); - 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 != NULL) - { - 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]; + 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 */ + } - 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); + whack_log_fd = NULL_FD; + close_any(whackfd); } #ifdef USE_KEYRR @@ -2158,110 +2149,112 @@ check_key_recs(enum myid_state try_state , const struct connection *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; - const struct RSA_private_key *our_RSA_pri; - 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 ((our_RSA_pri = get_RSA_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. + /* 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. */ - pubkey_list_t *kr; + enum myid_state old_myid_state = myid_state; + private_key_t *private; + err_t ugh = NULL; - ugh = "no KEY RR found for us"; - for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next) + myid_state = try_state; + + if (old_myid_state != myid_state && old_myid_state == MYID_SPECIFIED) { - ugh = "all our KEY RRs have the wrong public key"; - if (kr->key->alg == PUBKEY_ALG_RSA - && same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa)) - { - ugh = NULL; /* good! */ - break; - } + 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"; } - } - if (ugh != NULL) - myid_state = old_myid_state; - return ugh; + 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 != NULL) + myid_state = old_myid_state; + return ugh; } #endif /* USE_KEYRR */ -static err_t -check_txt_recs(enum myid_state try_state -, const struct connection *c -, struct adns_continuation *ac) +static err_t check_txt_recs(enum myid_state try_state, + const struct connection *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; - const struct RSA_private_key *our_RSA_pri; - 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 ((our_RSA_pri = get_RSA_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. + /* 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. */ - struct gw_info *gwp; + enum myid_state old_myid_state = myid_state; + private_key_t *private; + err_t ugh = NULL; + + myid_state = try_state; - ugh = "no TXT RR found for us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) + if (old_myid_state != myid_state + && old_myid_state == MYID_SPECIFIED) { - ugh = "all our TXT RRs have the wrong public key"; - if (gwp->key->alg == PUBKEY_ALG_RSA - && same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa)) - { - ugh = NULL; /* good! */ - break; - } + 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"; } - } - if (ugh != NULL) - myid_state = old_myid_state; - return ugh; + 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. + */ + 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 != NULL) + { + myid_state = old_myid_state; + } + return ugh; } @@ -2271,776 +2264,775 @@ initiate_opportunistic_body(struct find_oppo_bundle *b , struct adns_continuation *ac , err_t ac_ugh) { - struct connection *c; - struct spd_route *sr; + struct connection *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 KLIPS 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. + /* What connection shall we use? + * First try for one that explicitly handles the clients. */ - - /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */ - - if(c->kind == CK_INSTANCE) + 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)) { - 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; */ + cannot_oppo(NULL, b, "impossible IP address"); } - - /* otherwise, there is some kind of static conn that can handle - * this connection, so we initiate it */ - -#ifdef KLIPS - if (b->held) + else if ((c = find_connection_for_clients(&sr + , &b->our_client + , &b->peer_client + , b->transport_proto)) == NULL) { - /* what should we do on failure? */ - (void) assign_hold(c, sr, b->transport_proto, &b->our_client, &b->peer_client); + /* 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"); } -#endif - ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY); - b->whackfd = NULL_FD; /* protect from close */ - } - 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))); - - - idtoa(&sr->this.id, mycredentialstr, sizeof(mycredentialstr)); - - passert(c->policy & POLICY_OPPO); /* can't initiate Road Warrior connections */ - - /* handle any DNS answer; select next step */ - - switch (b->step) + else if (c->kind != CK_TEMPLATE) { - 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 != NULL) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, DBG_log("can not use our IP (%s:TXT) as identity: %s" - , myid_str[MYID_IP] - , ugh)); - if (!logged_myid_ip_txt_warning) - { - loglog(RC_LOG_SERIOUS - , "can not use our IP (%s:TXT) as identity: %s" - , myid_str[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 (%s:TXT) as identity!" - , myid_str[MYID_IP]); - logged_myid_ip_txt_warning = TRUE; - } + /* 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 KLIPS 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. + */ - 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 != NULL) - { - /* cannot use our hostname as OE identitiy for initiation */ - DBG(DBG_OPPO, DBG_log("can not use our hostname (%s:TXT) as identity: %s" - , myid_str[MYID_HOSTNAME] - , ugh)); - if (!logged_myid_fqdn_txt_warning) - { - loglog(RC_LOG_SERIOUS - , "can not use our hostname (%s:TXT) as identity: %s" - , myid_str[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 (%s:TXT) as identity!" - , myid_str[MYID_HOSTNAME]); - logged_myid_fqdn_txt_warning = TRUE; - } - next_step = fos_our_client; - } - break; + /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */ -#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 != NULL) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, DBG_log("can not use our IP (%s:KEY) as identity: %s" - , myid_str[MYID_IP] - , ugh)); - if (!logged_myid_ip_key_warning) + if(c->kind == CK_INSTANCE) { - loglog(RC_LOG_SERIOUS - , "can not use our IP (%s:KEY) as identity: %s" - , myid_str[MYID_IP] - , ugh); - logged_myid_ip_key_warning = TRUE; + 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; */ } - 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 (%s:KEY) as identity!" - , myid_str[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 != NULL) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, DBG_log("can not use our hostname (%s:KEY) as identity: %s" - , myid_str[MYID_HOSTNAME] - , ugh)); - if (!logged_myid_fqdn_key_warning) - { - loglog(RC_LOG_SERIOUS - , "can not use our hostname (%s:KEY) as identity: %s" - , myid_str[MYID_HOSTNAME] - , ugh); - logged_myid_fqdn_key_warning = TRUE; - } + /* otherwise, there is some kind of static conn that can handle + * this connection, so we initiate it */ - 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) +#ifdef KLIPS + if (b->held) { - loglog(RC_LOG_SERIOUS - , "using our hostname (%s:KEY) as identity!" - , myid_str[MYID_HOSTNAME]); - logged_myid_fqdn_key_warning = TRUE; + /* what should we do on failure? */ + (void) assign_hold(c, sr, b->transport_proto, &b->our_client, &b->peer_client); } - 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. + ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY); + b->whackfd = NULL_FD; /* protect from close */ + } + 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). */ - const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c); + enum find_oppo_step next_step = fos_myid_ip_txt; + err_t ugh = ac_ugh; + char mycredentialstr[BUF_LEN]; + char cib[CONN_INST_BUF]; - next_step = fos_his_client; /* normal situation */ + DBG(DBG_CONTROL, DBG_log("creating new instance from \"%s\"%s" + , c->name + , (fmt_conn_instance(c, cib), cib))); + - passert(sr != NULL); + idtoa(&sr->this.id, mycredentialstr, sizeof(mycredentialstr)); - if (our_RSA_pri == 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 (!same_id(&ac->sgw_id, &sr->this.id)) - { - /* this wasn't true when we started -- bail */ - ugh = "our ID changed underfoot"; - } - else + passert(c->policy & POLICY_OPPO); /* can't initiate Road Warrior connections */ + + /* handle any DNS answer; select next step */ + + switch (b->step) { - /* 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) - { - passert(same_id(&gwp->gw_id, &sr->this.id)); - - 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) + 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 != NULL) { - /* 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; + /* cannot use our IP as OE identitiy for initiation */ + DBG(DBG_OPPO, DBG_log("can not use our IP (%s:TXT) as identity: %s" + , myid_str[MYID_IP] + , ugh)); + if (!logged_myid_ip_txt_warning) + { + loglog(RC_LOG_SERIOUS + , "can not use our IP (%s:TXT) as identity: %s" + , myid_str[MYID_IP] + , ugh); + logged_myid_ip_txt_warning = TRUE; + } + + next_step = fos_myid_hostname_txt; + ugh = NULL; /* failure can be recovered from */ } - if (same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa)) + else { - ugh = NULL; /* good! */ - break; + /* we can use our IP as OE identity for initiation */ + if (!logged_myid_ip_txt_warning) + { + loglog(RC_LOG_SERIOUS + , "using our IP (%s:TXT) as identity!" + , myid_str[MYID_IP]); + logged_myid_ip_txt_warning = TRUE; + } + + next_step = fos_our_client; } - } - } - } - 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. - */ - const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c); - - next_step = fos_his_client; /* unless we decide to look for KEY RR */ + break; - if (our_RSA_pri == 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. - */ - struct gw_info *gwp; - - ugh = "no TXT RR for us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - passert(same_id(&gwp->gw_id, &sr->this.id)); - - ugh = "TXT RR for us has wrong key"; - if (gwp->gw_key_present - && same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa)) + case fos_myid_hostname_txt: /* TXT for our hostname as %myid */ + ugh = check_txt_recs(MYID_HOSTNAME, c, ac); + if (ugh != NULL) { - DBG(DBG_CONTROL, - DBG_log("initiate on demand found TXT with right public key at: %s" - , mycredentialstr)); - ugh = NULL; - break; - } - } + /* cannot use our hostname as OE identitiy for initiation */ + DBG(DBG_OPPO, DBG_log("can not use our hostname (%s:TXT) as identity: %s" + , myid_str[MYID_HOSTNAME] + , ugh)); + if (!logged_myid_fqdn_txt_warning) + { + loglog(RC_LOG_SERIOUS + , "can not use our hostname (%s:TXT) as identity: %s" + , myid_str[MYID_HOSTNAME] + , ugh); + logged_myid_fqdn_txt_warning = TRUE; + } #ifdef USE_KEYRR - if (ugh != NULL) - { - /* 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; - } + next_step = fos_myid_ip_key; + ugh = NULL; /* failure can be recovered from */ #endif - } - } - break; + } + else + { + /* we can use our hostname as OE identity for initiation */ + if (!logged_myid_fqdn_txt_warning) + { + loglog(RC_LOG_SERIOUS + , "using our hostname (%s:TXT) as identity!" + , myid_str[MYID_HOSTNAME]); + logged_myid_fqdn_txt_warning = TRUE; + } + next_step = fos_our_client; + } + 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. - */ - const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c); + case fos_myid_ip_key: /* KEY for our default IP address as %myid */ + ugh = check_key_recs(MYID_IP, c, ac); + if (ugh != NULL) + { + /* cannot use our IP as OE identitiy for initiation */ + DBG(DBG_OPPO, DBG_log("can not use our IP (%s:KEY) as identity: %s" + , myid_str[MYID_IP] + , ugh)); + if (!logged_myid_ip_key_warning) + { + loglog(RC_LOG_SERIOUS + , "can not use our IP (%s:KEY) as identity: %s" + , myid_str[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 (%s:KEY) as identity!" + , myid_str[MYID_IP]); + logged_myid_ip_key_warning = TRUE; + } + next_step = fos_our_client; + } + break; - next_step = fos_his_client; /* always */ + case fos_myid_hostname_key: /* KEY for our hostname as %myid */ + ugh = check_key_recs(MYID_HOSTNAME, c, ac); + if (ugh != NULL) + { + /* cannot use our IP as OE identitiy for initiation */ + DBG(DBG_OPPO, DBG_log("can not use our hostname (%s:KEY) as identity: %s" + , myid_str[MYID_HOSTNAME] + , ugh)); + if (!logged_myid_fqdn_key_warning) + { + loglog(RC_LOG_SERIOUS + , "can not use our hostname (%s:KEY) as identity: %s" + , myid_str[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 (%s:KEY) as identity!" + , myid_str[MYID_HOSTNAME]); + logged_myid_fqdn_key_warning = TRUE; + } + next_step = fos_our_client; + } + break; +#endif - if (our_RSA_pri == 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 - && same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa)) + case fos_our_client: /* TXT for our client */ { - /* 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; + /* 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 */ + + passert(sr != NULL); + + 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 (!same_id(&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) + { + passert(same_id(&gwp->gw_id, &sr->this.id)); + + 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; -#endif /* USE_KEYRR */ + break; - 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 */ + 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 (!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. + */ + struct gw_info *gwp; + + ugh = "no TXT RR for us"; + for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) + { + passert(same_id(&gwp->gw_id, &sr->this.id)); + + 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 != NULL) + { + /* 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; - c = build_outgoing_opportunistic_connection(ac->gateways_from_dns - , &b->our_client - , &b->peer_client); +#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 */ - if (c == NULL) - { - /* We cannot seem to instantiate a suitable connection: - * complain clearly. - */ - char ocb[ADDRTOT_BUF] - , pcb[ADDRTOT_BUF] - , pb[ADDRTOT_BUF]; - - addrtot(&b->our_client, 0, ocb, sizeof(ocb)); - addrtot(&b->peer_client, 0, pcb, sizeof(pcb)); - passert(id_is_ipaddr(&ac->gateways_from_dns->gw_id)); - addrtot(&ac->gateways_from_dns->gw_id.ip_addr, 0, pb, sizeof(pb)); - loglog(RC_OPPOFAILURE - , "no suitable connection for opportunism" - " between %s and %s with %s as peer" - , ocb, pcb, pb); + 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] + , pb[ADDRTOT_BUF]; + + addrtot(&b->our_client, 0, ocb, sizeof(ocb)); + addrtot(&b->peer_client, 0, pcb, sizeof(pcb)); + passert(id_is_ipaddr(&ac->gateways_from_dns->gw_id)); + addrtot(&ac->gateways_from_dns->gw_id.ip_addr, 0, pb, sizeof(pb)); + loglog(RC_OPPOFAILURE + , "no suitable connection for opportunism" + " between %s and %s with %s as peer" + , ocb, pcb, pb); #ifdef KLIPS - if (b->held) - { - /* Replace HOLD with PASS. - * The type of replacement *ought* to be - * specified by policy. - */ - (void) replace_bare_shunt(&b->our_client, &b->peer_client - , BOTTOM_PRIO - , SPI_PASS /* fail into PASS */ - , TRUE, b->transport_proto - , "no suitable connection"); - } + if (b->held) + { + /* Replace HOLD with PASS. + * The type of replacement *ought* to be + * specified by policy. + */ + (void) replace_bare_shunt(&b->our_client, &b->peer_client + , BOTTOM_PRIO + , SPI_PASS /* fail into PASS */ + , TRUE, b->transport_proto + , "no suitable connection"); + } #endif - } - 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)); + } + 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)); #ifdef KLIPS - if (b->held) - { - /* what should we do on failure? */ - (void) assign_hold(c, &c->spd - , b->transport_proto - , &b->our_client, &b->peer_client); - } + if (b->held) + { + /* what should we do on failure? */ + (void) assign_hold(c, &c->spd + , b->transport_proto + , &b->our_client, &b->peer_client); + } #endif - 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; + 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); - } + 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]; + /* 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"); - }); + 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 != NULL) - { - 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 = alloc_thing(struct find_oppo_continuation - , "opportunistic continuation"); - struct id 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.kind == ID_MYID - && myid_state != MYID_SPECIFIED) + if (ugh != NULL) { - 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; + b->policy_prio = c->prio; + b->failure_shunt = shunt_policy_spi(c, FALSE); + cannot_oppo(c, b, ugh); } - cr->b.step = fos_myid_hostname_txt; - /* fall through */ - - case fos_myid_hostname_txt: - if (c->spd.this.id.kind == ID_MYID - && myid_state != MYID_SPECIFIED) + 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); + struct id 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.kind == 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.kind == ID_MYID + && myid_state != MYID_SPECIFIED) + { #ifdef USE_KEYRR - cr->b.failure_ok = TRUE; + cr->b.failure_ok = TRUE; #else - cr->b.failure_ok = FALSE; + 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; - } + 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] - , (const struct id *) 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] - , (const struct id *) NULL /* security gateway meaningless */ - , T_KEY - , continue_oppo - , &cr->ac); - break; - } + 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] + , (const struct id *) 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] + , (const struct id *) 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"; - iptoid(&b->our_client, &id); - ugh = start_adns_query(&id - , &c->spd.this.id /* we are the security gateway */ - , T_TXT - , continue_oppo - , &cr->ac); - 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 XXX - maybe ignore? mcr */ - , T_TXT - , continue_oppo - , &cr->ac); - break; + 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"; + iptoid(&b->our_client, &id); + ugh = start_adns_query(&id + , &c->spd.this.id /* we are the security gateway */ + , T_TXT + , continue_oppo + , &cr->ac); + 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 XXX - maybe ignore? mcr */ + , 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 - , (const struct id *) NULL /* security gateway meaningless */ - , T_KEY - , continue_oppo - , &cr->ac); - break; + 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 + , (const struct 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; - iptoid(&b->peer_client, &id); - ugh = start_adns_query(&id - , (const struct id *) NULL /* security gateway unconstrained */ - , T_TXT - , continue_oppo - , &cr->ac); - break; - - default: - bad_case(next_step); - } + 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; + iptoid(&b->peer_client, &id); + ugh = start_adns_query(&id + , (const struct id *) NULL /* security gateway unconstrained */ + , T_TXT + , continue_oppo + , &cr->ac); + break; + + default: + bad_case(next_step); + } - if (ugh == NULL) - b->whackfd = NULL_FD; /* complete hand-off */ - else - cannot_oppo(c, b, ugh); + if (ugh == NULL) + b->whackfd = NULL_FD; /* complete hand-off */ + else + cannot_oppo(c, b, ugh); + } } - } - close_any(b->whackfd); + 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). - */ - struct connection *c = con_by_name(nm, TRUE); - - if (c == NULL || !c->ikev1) - return; + /* Loop because more than one may match (master and instances) + * But at least one is required (enforced by con_by_name). + */ + struct connection *c = con_by_name(nm, TRUE); - do - { - struct connection *n = c->ac_next; /* grab this before c might disappear */ + if (c == NULL || !c->ikev1) + return; - if (streq(c->name, nm) - && c->kind >= CK_PERMANENT - && !NEVER_NEGOTIATE(c->policy)) + do { - 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 != NULL); + struct connection *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 != NULL); } /* 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? */ +bool uniqueIDs = FALSE; /* --uniqueids? */ void ISAKMP_SA_established(struct connection *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 (!isanyaddr(&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. - */ - struct connection *d; + c->newest_isakmp_sa = serial; - for (d = connections; d != NULL; ) + /* 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 (!isanyaddr(&c->spd.that.host_srcip) && !c->spd.that.has_natip) + c->spd.that.modecfg = TRUE; + + if (uniqueIDs) { - struct connection *next = d->ac_next; /* might move underneath us */ - - if (d->kind >= CK_PERMANENT - && same_id(&c->spd.this.id, &d->spd.this.id) - && same_id(&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; + /* for all connections: if the same Phase 1 IDs are used + * for a different IP address, unorient that connection. + */ + struct connection *d; + + for (d = connections; d != NULL; ) + { + struct connection *next = d->ac_next; /* might move underneath us */ + + if (d->kind >= CK_PERMANENT + && same_id(&c->spd.this.id, &d->spd.this.id) + && same_id(&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 @@ -3056,108 +3048,108 @@ ISAKMP_SA_established(struct connection *c, so_serial_t serial) */ struct connection * route_owner(struct connection *c - , struct spd_route **srp - , struct connection **erop - , struct spd_route **esrp) + , struct spd_route **srp + , struct connection **erop + , struct spd_route **esrp) { - struct connection *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) + struct connection *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) { - 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; - passert(oriented(*d)); - if (srd->routing > best_routing) + for (srd = &d->spd; srd; srd = srd->next) { - best_ro = d; - best_sr = srd; - best_routing = srd->routing; - } + if (srd->routing == RT_UNROUTED) + continue; - 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 (srd->routing > best_erouting) - { - best_ero = d; - best_esr = srd; - best_erouting = srd->routing; + 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; + 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 (srd->routing > best_erouting) + { + best_ero = d; + best_esr = srd; + best_erouting = srd->routing; + } + } } - } } - } - DBG(DBG_CONTROL, + 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 != NULL) + { + 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 != NULL) + *erop = erouted(best_erouting)? best_ero : NULL; + + if (srp != NULL ) { - 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 != NULL) - { - 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 != NULL) - *erop = erouted(best_erouting)? best_ero : NULL; - - if (srp != NULL ) - { - *srp = best_sr; - if (esrp != NULL ) - *esrp = best_esr; - } - - return routed(best_routing)? best_ro : NULL; + *srp = best_sr; + if (esrp != NULL ) + *esrp = best_esr; + } + + return routed(best_routing)? best_ro : NULL; } /* Find a connection that owns the shunt eroute between subnets. @@ -3167,20 +3159,20 @@ route_owner(struct connection *c struct connection * shunt_owner(const ip_subnet *ours, const ip_subnet *his) { - struct connection *c; - struct spd_route *sr; + struct connection *c; + struct spd_route *sr; - for (c = connections; c != NULL; c = c->ac_next) - { - for (sr = &c->spd; sr; sr = sr->next) + for (c = connections; c != NULL; c = c->ac_next) { - if (shunt_erouted(sr->routing) - && samesubnet(ours, &sr->this.client) - && samesubnet(his, &sr->that.client)) - return c; + 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; + return NULL; } /* Find some connection with this pair of hosts. @@ -3191,25 +3183,25 @@ struct connection * find_host_connection(const ip_address *me, u_int16_t my_port , const ip_address *him, u_int16_t his_port, lset_t policy) { - struct connection *c = find_host_pair_connections(me, my_port, him, his_port); - - if (policy != LEMPTY) - { - lset_t auth_requested = policy & POLICY_ID_AUTH_MASK; + struct connection *c = find_host_pair_connections(me, my_port, him, his_port); - /* if we have requirements for the policy, - * choose the first matching connection. - */ - while (c != NULL) + if (policy != LEMPTY) { - if (c->policy & auth_requested) - { - break; - } - c = c->hp_next; + lset_t auth_requested = policy & POLICY_ID_AUTH_MASK; + + /* if we have requirements for the policy, + * choose the first matching connection. + */ + while (c != NULL) + { + if (c->policy & auth_requested) + { + break; + } + c = c->hp_next; + } } - } - return c; + return c; } /* given an up-until-now satisfactory connection, find the best connection @@ -3266,187 +3258,197 @@ find_host_connection(const ip_address *me, u_int16_t my_port * * In the Initiator case, the particular connection might have been * specified by whatever provoked Pluto to initiate. For example: - * whack --initiate connection-name + * 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 +#define PRIO_NO_MATCH_FOUND 2048 struct connection * refine_host_connection(const struct state *st, const struct id *peer_id , chunk_t peer_ca) { - struct connection *c = st->st_connection; - struct connection *d; - struct connection *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 wildcards, our_pathlen, peer_pathlen; - - if (same_id(&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: - auth_policy = POLICY_RSASIG; - 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) + struct connection *c = st->st_connection; + struct connection *d; + struct connection *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 wildcards, our_pathlen, peer_pathlen; + + if (same_id(&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) { - const char *match_name[] = {"no", "ok"}; - - bool matching_id = match_id(peer_id - , &d->spd.that.id, &wildcards); - 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 = (MAX_WILDCARDS + 1) * !matching_request + wildcards; - - prio = (MAX_CA_PATH_LEN + 1) * prio + peer_pathlen; - prio = (MAX_CA_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 */ + DBG(DBG_CONTROL, + DBG_log("current connection is a full match" + " -- no need to look further"); + ) + return c; + } - if (psk != dpsk) - if (psk->len != dpsk->len - || memcmp(psk->ptr, dpsk->ptr, psk->len) != 0) - continue; /* different secret */ + 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 OAKLEY_RSA_SIG: - case XAUTHInitRSA: - case XAUTHRespRSA: - /* - * We must at least be able to find our private key - .*/ - if (d->spd.this.sc == NULL /* no smartcard */ - && get_RSA_private_key(d) == NULL) /* no private key */ - continue; + case XAUTHInitPreShared: + case XAUTHRespPreShared: + auth_policy = POLICY_XAUTH_PSK; + psk = get_preshared_secret(c); + if (psk == NULL) + { + return NULL; /* cannot determine PSK! */ + } break; - - default: + 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); - } - - /* 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 + /* 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 = find_host_pair_connections(&c->spd.this.host_addr, c->spd.this.host_port - , (ip_address *)NULL, c->spd.that.host_port); - } + d = c->host_pair->connections; + for (wcpip = FALSE; ; wcpip = TRUE) + { + for (; d != NULL; d = d->hp_next) + { + const char *match_name[] = {"no", "ok"}; + + bool matching_id = match_id(peer_id + , &d->spd.that.id, &wildcards); + 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 = (MAX_WILDCARDS + 1) * !matching_request + wildcards; + + prio = (MAX_CA_PATH_LEN + 1) * prio + peer_pathlen; + prio = (MAX_CA_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); + } } /** @@ -3456,35 +3458,35 @@ refine_host_connection(const struct state *st, const struct id *peer_id static bool is_virtual_net_used(const ip_subnet *peer_net, const struct id *peer_id) { - struct connection *d; + struct connection *d; - for (d = connections; d != NULL; d = d->ac_next) - { - switch (d->kind) + for (d = connections; d != NULL; d = d->ac_next) { - case CK_PERMANENT: - case CK_INSTANCE: - if ((subnetinsubnet(peer_net,&d->spd.that.client) || - subnetinsubnet(&d->spd.that.client,peer_net)) - && !same_id(&d->spd.that.id, peer_id)) - { - char buf[BUF_LEN]; - char client[SUBNETTOT_BUF]; - - subnettot(peer_net, 0, client, sizeof(client)); - idtoa(&d->spd.that.id, buf, sizeof(buf)); - plog("Virtual IP %s is already used by '%s'", client, buf); - idtoa(peer_id, buf, sizeof(buf)); - plog("Your ID is '%s'", buf); - return TRUE; /* already used by another one */ - } - break; - case CK_GOING_AWAY: - default: - break; + switch (d->kind) + { + case CK_PERMANENT: + case CK_INSTANCE: + if ((subnetinsubnet(peer_net,&d->spd.that.client) || + subnetinsubnet(&d->spd.that.client,peer_net)) + && !same_id(&d->spd.that.id, peer_id)) + { + char buf[BUF_LEN]; + char client[SUBNETTOT_BUF]; + + subnettot(peer_net, 0, client, sizeof(client)); + idtoa(&d->spd.that.id, buf, sizeof(buf)); + plog("Virtual IP %s is already used by '%s'", client, buf); + idtoa(peer_id, buf, sizeof(buf)); + plog("Your ID is '%s'", buf); + return TRUE; /* already used by another one */ + } + break; + case CK_GOING_AWAY: + default: + break; + } } - } - return FALSE; /* you can safely use it */ + return FALSE; /* you can safely use it */ } /* find_client_connection: given a connection suitable for ISAKMP @@ -3512,9 +3514,9 @@ is_virtual_net_used(const ip_subnet *peer_net, const struct id *peer_id) * instantiation. They are the IDs that have been authenticated. */ -#define PATH_WEIGHT 1 -#define WILD_WEIGHT (MAX_CA_PATH_LEN+1) -#define PRIO_WEIGHT (MAX_WILDCARDS+1)*WILD_WEIGHT +#define PATH_WEIGHT 1 +#define WILD_WEIGHT (MAX_CA_PATH_LEN+1) +#define PRIO_WEIGHT (MAX_WILDCARDS+1)*WILD_WEIGHT /* fc_try: a helper function for find_client_connection */ static struct connection * @@ -3530,121 +3532,121 @@ fc_try(const struct connection *c , chunk_t peer_ca , const ietfAttrList_t *peer_list) { - struct connection *d; - struct connection *best = NULL; - policy_prio_t best_prio = BOTTOM_PRIO; - int wildcards, 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; + struct connection *d; + struct connection *best = NULL; + policy_prio_t best_prio = BOTTOM_PRIO; + int wildcards, pathlen; - if (d->policy & POLICY_GROUP) - continue; - - if (!(same_id(&c->spd.this.id, &d->spd.this.id) - && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards) - && trusted_ca(peer_ca, d->spd.that.ca, &pathlen) - && group_membership(peer_list, 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. - */ + const bool peer_net_is_host = subnetisaddr(peer_net, &c->spd.that.host_addr); - for (sr = &d->spd; best != d && sr != NULL; sr = sr->next) + for (d = hp->connections; d != NULL; d = d->hp_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]; + struct spd_route *sr; - 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 (d->policy & POLICY_GROUP) + continue; - if (!samesubnet(&sr->this.client, our_net)) - continue; + if (!(same_id(&c->spd.this.id, &d->spd.this.id) + && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards) + && trusted_ca(peer_ca, d->spd.that.ca, &pathlen) + && group_membership(peer_list, d->name, d->spd.that.groups))) + continue; - if (sr->that.has_client) - { - if (sr->that.has_client_wildcard) - { - if (!subnetinsubnet(peer_net, &sr->that.client)) + /* 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; - } - else + + /* 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) { - 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; + 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 + { + if (!peer_net_is_host) + 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 * (MAX_WILDCARDS - wildcards) + + PATH_WEIGHT * (MAX_CA_PATH_LEN - pathlen) + + 1; + if (prio > best_prio) + { + best = d; + best_prio = prio; + } } - } - else - { - if (!peer_net_is_host) - 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 * (MAX_WILDCARDS - wildcards) - + PATH_WEIGHT * (MAX_CA_PATH_LEN - pathlen) - + 1; - if (prio > best_prio) - { - best = d; - best_prio = prio; - } } - } - if (best != NULL && NEVER_NEGOTIATE(best->policy)) - best = NULL; + if (best != NULL && 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; + DBG(DBG_CONTROLMORE, + DBG_log(" fc_try concluding with %s [%ld]" + , (best ? best->name : "none"), best_prio) + ) + return best; } static struct connection * @@ -3659,92 +3661,92 @@ fc_try_oppo(const struct connection *c , chunk_t peer_ca , const ietfAttrList_t *peer_list) { - struct connection *d; - struct connection *best = NULL; - policy_prio_t best_prio = BOTTOM_PRIO; - int wildcards, pathlen; + struct connection *d; + struct connection *best = NULL; + policy_prio_t best_prio = BOTTOM_PRIO; + int wildcards, 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; - - if (!(same_id(&c->spd.this.id, &d->spd.this.id) - && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards) - && trusted_ca(peer_ca, d->spd.that.ca, &pathlen) - && group_membership(peer_list, 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) + for (d = hp->connections; d != NULL; d = d->hp_next) { -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF]; - char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF]; + struct spd_route *sr; + policy_prio_t prio; - 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); - } + if (d->policy & POLICY_GROUP) + continue; + + if (!(same_id(&c->spd.this.id, &d->spd.this.id) + && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards) + && trusted_ca(peer_ca, d->spd.that.ca, &pathlen) + && group_membership(peer_list, 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 * (MAX_WILDCARDS - wildcards) - + PATH_WEIGHT * (MAX_CA_PATH_LEN - pathlen); - if (prio > best_prio) - { - best = d; - best_prio = prio; - } + 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 * (MAX_WILDCARDS - wildcards) + + PATH_WEIGHT * (MAX_CA_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 != NULL + && (NEVER_NEGOTIATE(best->policy) + || (best->policy & POLICY_OPPO) == LEMPTY)) + { + best = NULL; } - } - - /* if the best wasn't opportunistic, we fail: it must be a shunt */ - if (best != NULL - && (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; + + DBG(DBG_CONTROLMORE, + DBG_log(" fc_try_oppo concluding with %s [%ld]" + , (best ? best->name : "none"), best_prio) + ) + return best; } @@ -3754,28 +3756,28 @@ fc_try_oppo(const struct connection *c chunk_t get_peer_ca_and_groups(struct connection *c, const ietfAttrList_t **peer_list) { - struct state *p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); - - *peer_list = NULL; + struct state *p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); - if (p1st != NULL - && p1st->st_peer_pubkey != NULL - && p1st->st_peer_pubkey->issuer.ptr != NULL) - { - x509acert_t *ac = get_x509acert(p1st->st_peer_pubkey->issuer - , p1st->st_peer_pubkey->serial);; + *peer_list = NULL; - if (ac != NULL && verify_x509acert(ac, strict_crl_policy)) - *peer_list = ac->groups; - else + if (p1st != NULL + && p1st->st_peer_pubkey != NULL + && p1st->st_peer_pubkey->issuer.ptr != NULL) { - DBG(DBG_CONTROL, - DBG_log("no valid attribute cert found") - ) + x509acert_t *ac = get_x509acert(p1st->st_peer_pubkey->issuer + , p1st->st_peer_pubkey->serial);; + + if (ac != NULL && verify_x509acert(ac, strict_crl_policy)) + *peer_list = ac->groups; + else + { + DBG(DBG_CONTROL, + DBG_log("no valid attribute cert found") + ) + } + return p1st->st_peer_pubkey->issuer; } - return p1st->st_peer_pubkey->issuer; - } - return empty_chunk; + return chunk_empty; } struct connection * @@ -3784,325 +3786,325 @@ find_client_connection(struct connection *c , const u_int8_t our_protocol, const u_int16_t our_port , const u_int8_t peer_protocol, const u_int16_t peer_port) { - struct connection *d; - struct spd_route *sr; + struct connection *d; + struct spd_route *sr; - const ietfAttrList_t *peer_list = NULL; - chunk_t peer_ca = get_peer_ca_and_groups(c, &peer_list); + const ietfAttrList_t *peer_list = NULL; + chunk_t peer_ca = get_peer_ca_and_groups(c, &peer_list); #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 */ + if (DBGP(DBG_CONTROLMORE)) + { + char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF]; - /* give priority to current connection - * but even greater priority to a routed concrete connection - */ - { - struct connection *unrouted = NULL; - int srnum = -1; + 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 */ - for (sr = &c->spd; unrouted == NULL && sr != NULL; sr = sr->next) + /* give priority to current connection + * but even greater priority to a routed concrete connection + */ { - srnum++; + struct connection *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); - } + 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 - && group_membership(peer_list, c->name, sr->that.groups)) - { - passert(oriented(*c)); - if (routed(sr->routing)) - return c; - - unrouted = c; - } - } + 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 + && group_membership(peer_list, c->name, sr->that.groups)) + { + passert(oriented(*c)); + if (routed(sr->routing)) + return 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_list); + unrouted = c; + } + } - DBG(DBG_CONTROLMORE, - DBG_log(" fc_try %s gives %s" - , c->name - , (d ? d->name : "none")) - ) + /* 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_list); - if (d == NULL) - d = unrouted; - } + DBG(DBG_CONTROLMORE, + DBG_log(" fc_try %s gives %s" + , c->name + , (d ? d->name : "none")) + ) - if (d == NULL) - { - /* look for an abstract connection to match */ - struct spd_route *sr; - struct host_pair *hp = NULL; + if (d == NULL) + d = unrouted; + } - for (sr = &c->spd; hp==NULL && sr != NULL; sr = sr->next) + if (d == NULL) { - hp = find_host_pair(&sr->this.host_addr - , sr->this.host_port - , NULL - , sr->that.host_port); + /* 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]; + 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)); + 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")); - } + DBG_log(" checking hostpair %s -> %s is %s" + , s2, d2 + , (hp ? "found" : "not found")); + } #endif /* DEBUG */ - } + } - if (hp != NULL) - { - /* 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_list); - - 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_list); - } + if (hp != NULL) + { + /* 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_list); + + 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_list); + } + } } - } - DBG(DBG_CONTROLMORE, - DBG_log(" concluding with d = %s" - , (d ? d->name : "none")) - ) - return d; + DBG(DBG_CONTROLMORE, + DBG_log(" concluding with d = %s" + , (d ? d->name : "none")) + ) + return d; } int connection_compare(const struct connection *ca , const struct connection *cb) { - int ret; - - /* DBG_log("comparing %s to %s", ca->name, cb->name); */ - - ret = strcasecmp(ca->name, cb->name); - if (ret != 0) - return ret; - - ret = ca->kind - cb->kind; /* note: enum connection_kind behaves like int */ - if (ret != 0) - 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; - } + int ret; + + /* DBG_log("comparing %s to %s", ca->name, cb->name); */ + + ret = strcasecmp(ca->name, cb->name); + if (ret != 0) + return ret; + + ret = ca->kind - cb->kind; /* note: enum connection_kind behaves like int */ + if (ret != 0) + 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 struct connection *const *)a - , *(const struct connection *const *)b); + return connection_compare(*(const struct connection *const *)a + , *(const struct connection *const *)b); } void show_connections_status(bool all, const char *name) { - struct connection *c; - int count, i; - struct connection **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 = alloc_bytes(sizeof(struct connection *)*count, "connection array"); - - 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(struct connection *), 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 */ + struct connection *c; + int count, i; + struct connection **array; + + /* make an array of connections, and sort it */ + count = 0; + for (c = connections; c != NULL; c = c->ac_next) { - char topo[CONNECTION_BUF]; - struct spd_route *sr = &c->spd; - int num=0; - - while (sr != NULL) - { - (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 (c->ikev1 && (name == NULL || streq(c->name, name))) + count++; } + array = malloc(sizeof(struct connection *)*count); - if (all) + count=0; + for (c = connections; c != NULL; c = c->ac_next) { - /* show CAs if defined */ - if (c->spd.this.ca.ptr != NULL || c->spd.that.ca.ptr != NULL) - { - char this_ca[BUF_LEN], that_ca[BUF_LEN]; - - dntoa_or_null(this_ca, BUF_LEN, c->spd.this.ca, "%any"); - dntoa_or_null(that_ca, BUF_LEN, c->spd.that.ca, "%any"); - - whack_log(RC_COMMENT - , "\"%s\"%s: CAs: '%s'...'%s'" - , c->name - , instance - , this_ca - , that_ca); - } - - /* show group attributes if defined */ - if (c->spd.that.groups != NULL) - { - char buf[BUF_LEN]; - - format_groups(c->spd.that.groups, buf, BUF_LEN); - whack_log(RC_COMMENT - , "\"%s\"%s: groups: %s" - , c->name - , instance - , buf); - } - - 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: %s;" - " dpd_delay: %lus; dpd_timeout: %lus;" - , c->name - , instance - , enum_show(&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); + if (c->ikev1 && (name == NULL || streq(c->name, name))) + array[count++]=c; } - 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) + /* sort it! */ + qsort(array, count, sizeof(struct connection *), connection_compare_qsort); + + for (i = 0; i < count; i++) { - ike_alg_show_connection(c, instance); - kernel_alg_show_connection(c, instance); + 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[CONNECTION_BUF]; + struct spd_route *sr = &c->spd; + int num=0; + + while (sr != NULL) + { + (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.ptr != NULL || c->spd.that.ca.ptr != NULL) + { + char this_ca[BUF_LEN], that_ca[BUF_LEN]; + + dntoa_or_null(this_ca, BUF_LEN, c->spd.this.ca, "%any"); + dntoa_or_null(that_ca, BUF_LEN, c->spd.that.ca, "%any"); + + whack_log(RC_COMMENT + , "\"%s\"%s: CAs: '%s'...'%s'" + , c->name + , instance + , this_ca + , that_ca); + } + + /* show group attributes if defined */ + if (c->spd.that.groups != NULL) + { + char buf[BUF_LEN]; + + format_groups(c->spd.that.groups, buf, BUF_LEN); + whack_log(RC_COMMENT + , "\"%s\"%s: groups: %s" + , c->name + , instance + , buf); + } + + 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 */ + if (count > 0) + whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ - pfree(array); + free(array); } /* struct pending, the structure representing Quick Mode @@ -4111,14 +4113,14 @@ show_connections_status(bool all, const char *name) */ struct pending { - int whack_sock; - struct state *isakmp_sa; - struct connection *connection; - lset_t policy; - unsigned long try; - so_serial_t replacing; - - struct pending *next; + int whack_sock; + struct state *isakmp_sa; + struct connection *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 */ @@ -4130,36 +4132,36 @@ add_pending(int whack_sock , unsigned long try , so_serial_t replacing) { - bool already_queued = FALSE; - struct pending *p = c->host_pair->pending; + bool already_queued = FALSE; + struct pending *p = c->host_pair->pending; - while (p != NULL) - { - if (streq(c->name, p->connection->name)) + while (p != NULL) { - already_queued = TRUE; - break; + if (streq(c->name, p->connection->name)) + { + already_queued = TRUE; + break; + } + p = p->next; } - 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 = alloc_thing(struct pending, "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; + 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. @@ -4169,157 +4171,157 @@ add_pending(int whack_sock void release_pending_whacks(struct state *st, err_t story) { - struct pending *p; - struct stat stst; + 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 */ + 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); + 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) + for (p = st->st_connection->host_pair->pending; p != NULL; p = p->next) { - struct stat pst; + 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; + 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; + struct pending *p = *pp; - *pp = p->next; - if (p->connection != NULL) - connection_discard(p->connection); - close_any(p->whack_sock); - pfree(p); + *pp = p->next; + if (p->connection != NULL) + connection_discard(p->connection); + close_any(p->whack_sock); + free(p); } void unpend(struct state *st) { - struct pending **pp - , *p; + 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 + for (pp = &st->st_connection->host_pair->pending; (p = *pp) != NULL; ) { - pp = &p->next; + 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; + 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) + for (p = os->st_connection->host_pair->pending; p != NULL; p = p->next) { - 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; + 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 != NULL) - { - struct pending **pp - , *p; + struct host_pair *hp = st->st_connection->host_pair; - for (pp = &hp->pending; (p = *pp) != NULL; ) + if (hp != NULL) { - if (p->isakmp_sa == st) - delete_pending(pp); - else - pp = &p->next; + 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(struct connection *c) { - if (c->host_pair != NULL) - { - struct pending **pp - , *p; - - for (pp = &c->host_pair->pending; (p = *pp) != NULL; ) + if (c->host_pair != NULL) { - if (p->connection == c) - { - p->connection = NULL; /* prevent delete_pending from releasing */ - delete_pending(pp); - } - else - { - pp = &p->next; - } + 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; + const struct pending *p; - for (p = hp->pending; p != NULL; p = p->next) - { - if (p->isakmp_sa == st) + for (p = hp->pending; p != NULL; p = p->next) { - /* 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); + 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. @@ -4329,18 +4331,18 @@ show_pending_phase2(const struct host_pair *hp, const struct state *st) void connection_discard(struct connection *c) { - if (c->kind == CK_INSTANCE) - { - /* see if it is being used by a pending */ - struct pending *p; + 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 */ + 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); - } + if (!states_use_connection(c)) + delete_connection(c, FALSE); + } } @@ -4354,32 +4356,32 @@ long eclipse_count = 0; struct connection * eclipsed(struct connection *c, struct spd_route **esrp) { - struct connection *ue; - struct spd_route *sr1 = &c->spd; + struct connection *ue; + struct spd_route *sr1 = &c->spd; - ue = NULL; + ue = NULL; - while (sr1 != NULL && ue != NULL) - { - for (ue = connections; ue != NULL; ue = ue->ac_next) + while (sr1 != NULL && ue != NULL) { - struct spd_route *srue = &ue->spd; - - while (srue != NULL - && srue->routing == RT_ROUTED_ECLIPSED - && !(samesubnet(&sr1->this.client, &srue->this.client) - && samesubnet(&sr1->that.client, &srue->that.client))) - { - srue = srue->next; - } - if (srue != NULL && srue->routing==RT_ROUTED_ECLIPSED) - { - *esrp = srue; - break; - } + for (ue = connections; ue != NULL; ue = ue->ac_next) + { + struct spd_route *srue = &ue->spd; + + while (srue != NULL + && srue->routing == RT_ROUTED_ECLIPSED + && !(samesubnet(&sr1->this.client, &srue->this.client) + && samesubnet(&sr1->that.client, &srue->that.client))) + { + srue = srue->next; + } + if (srue != NULL && srue->routing==RT_ROUTED_ECLIPSED) + { + *esrp = srue; + break; + } + } } - } - return ue; + return ue; } /* diff --git a/src/pluto/connections.h b/src/pluto/connections.h index b11565296..16cbbfd72 100644 --- a/src/pluto/connections.h +++ b/src/pluto/connections.h @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: connections.h 4024 2008-05-29 07:49:47Z andreas $ */ #ifndef _CONNECTIONS_H @@ -118,135 +116,135 @@ * - display format: n,m */ typedef unsigned long policy_prio_t; -#define BOTTOM_PRIO ((policy_prio_t)0) /* smaller than any real prio */ +#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) + ((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 { - struct id id; - ip_address - host_addr, - host_nexthop, - host_srcip; - ip_subnet client; - - 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 */ - chunk_t ca; /* CA distinguished name */ - struct ietfAttrList *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 */ - 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 id id; + ip_address + host_addr, + host_nexthop, + host_srcip; + ip_subnet client; + + 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 */ + chunk_t ca; /* CA distinguished name */ + struct ietfAttrList *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 */ + 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; + 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; }; struct connection { - char *name; - bool ikev1; + 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; + 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; - /* RFC 3706 DPD */ - time_t dpd_delay; - time_t dpd_timeout; - dpd_action_t dpd_action; + /* 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 */ + 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; + struct spd_route spd; - /* internal fields: */ + /* 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 */ + 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; + so_serial_t /* state object serial number */ + newest_isakmp_sa, + newest_ipsec_sa; #ifdef DEBUG - lset_t extra_debugging; + 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 */ + /* 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 */ - struct connection *policy_next; /* if multiple policies, - next one to apply */ + struct connection *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 gw_info *gw_info; + struct alg_info_esp *alg_info_esp; + struct alg_info_ike *alg_info_ike; - struct host_pair *host_pair; - struct connection *hp_next; /* host pair list link */ + struct host_pair *host_pair; + struct connection *hp_next; /* host pair list link */ - struct connection *ac_next; /* all connections list link */ + struct connection *ac_next; /* all connections list link */ - generalName_t *requested_ca; /* collected certificate requests */ - bool got_certrequest; + generalName_t *requested_ca; /* collected certificate requests */ + bool got_certrequest; }; #define oriented(c) ((c).interface != NULL) extern bool orient(struct connection *c); extern bool same_peer_ids(const struct connection *c - , const struct connection *d, const struct id *his_id); + , const struct connection *d, const struct id *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) +#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); + , 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); + , const ip_address *peer_client, int transport_proto, bool held, int whackfd); extern void terminate_connection(const char *nm); extern void release_connection(struct connection *c, bool relations); extern void delete_connection(struct connection *c, bool relations); @@ -257,87 +255,87 @@ extern void remove_group_instance(const struct connection *group, const char *na extern void release_dead_interfaces(void); extern void check_orientations(void); extern struct connection *route_owner(struct connection *c - , struct spd_route **srp - , struct connection **erop - , struct spd_route **esrp); + , struct spd_route **srp + , struct connection **erop + , struct spd_route **esrp); extern struct connection *shunt_owner(const ip_subnet *ours - , const ip_subnet *his); + , const ip_subnet *his); -extern bool uniqueIDs; /* --uniqueids? */ +extern bool uniqueIDs; /* --uniqueids? */ extern void ISAKMP_SA_established(struct connection *c, so_serial_t serial); #define his_id_was_instantiated(c) ((c)->kind == CK_INSTANCE \ - && (id_is_ipaddr(&(c)->spd.that.id)? \ - sameaddr(&(c)->spd.that.id.ip_addr, &(c)->spd.that.host_addr) : TRUE)) + && (id_is_ipaddr(&(c)->spd.that.id)? \ + sameaddr(&(c)->spd.that.id.ip_addr, &(c)->spd.that.host_addr) : TRUE)) -struct state; /* forward declaration of tag (defined in state.h) */ +struct state; /* forward declaration of tag (defined in state.h) */ extern struct connection - *con_by_name(const char *nm, bool strict), - *find_host_connection(const ip_address *me, u_int16_t my_port - , const ip_address *him, u_int16_t his_port, lset_t policy), - *refine_host_connection(const struct state *st, const struct id *id - , chunk_t peer_ca), - *find_client_connection(struct connection *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), - *find_connection_by_reqid(uint32_t reqid); + *con_by_name(const char *nm, bool strict), + *find_host_connection(const ip_address *me, u_int16_t my_port + , const ip_address *him, u_int16_t his_port, lset_t policy), + *refine_host_connection(const struct state *st, const struct id *id + , chunk_t peer_ca), + *find_client_connection(struct connection *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), + *find_connection_by_reqid(uint32_t reqid); extern struct connection * find_connection_for_clients(struct spd_route **srp - , const ip_address *our_client - , const ip_address *peer_client - , int transport_proto); + , const ip_address *our_client + , const ip_address *peer_client + , int transport_proto); extern chunk_t get_peer_ca_and_groups(struct connection *c - , const ietfAttrList_t **peer_list); - + , const ietfAttrList_t **peer_list); + /* 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) */ +struct gw_info; /* forward declaration of tag (defined in dnskey.h) */ +struct alg_info; /* forward declaration of tag (defined in alg_info.h) */ extern struct connection *rw_instantiate(struct connection *c - , const ip_address *him - , u_int16_t his_port - , const ip_subnet *his_net - , const struct id *his_id); + , const ip_address *him + , u_int16_t his_port + , const ip_subnet *his_net + , const struct id *his_id); extern struct connection *oppo_instantiate(struct connection *c - , const ip_address *him - , const struct id *his_id - , struct gw_info *gw - , const ip_address *our_client - , const ip_address *peer_client); + , const ip_address *him + , const struct id *his_id + , struct gw_info *gw + , const ip_address *our_client + , const ip_address *peer_client); extern struct connection *build_outgoing_opportunistic_connection(struct gw_info *gw - , const ip_address *our_client - , const ip_address *peer_client); + , const ip_address *our_client + , const ip_address *peer_client); /* worst case: "[" serial "] " myclient "=== ..." peer "===" hisclient '\0' */ #define CONN_INST_BUF \ - (2 + 10 + 1 + SUBNETTOT_BUF + 7 + ADDRTOT_BUF + 3 + SUBNETTOT_BUF + 1) + (2 + 10 + 1 + SUBNETTOT_BUF + 7 + ADDRTOT_BUF + 3 + SUBNETTOT_BUF + 1) extern void fmt_conn_instance(const struct connection *c - , char buf[CONN_INST_BUF]); + , 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) */ +struct pending; /* forward declaration (opaque outside connections.c) */ extern void add_pending(int whack_sock - , struct state *isakmp_sa - , struct connection *c - , lset_t policy - , unsigned long try - , so_serial_t replacing); + , struct state *isakmp_sa + , struct connection *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); @@ -360,9 +358,9 @@ extern struct connection *eclipsed(struct connection *c, struct spd_route **); extern void show_connections_status(bool all, const char *name); extern int connection_compare(const struct connection *ca - , const struct connection *cb); + , const struct connection *cb); extern void update_host_pair(const char *why, struct connection *c - , const ip_address *myaddr, u_int16_t myport - , const ip_address *hisaddr, u_int16_t hisport); + , 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 index 50a75c0aa..adcd77131 100644 --- a/src/pluto/constants.c +++ b/src/pluto/constants.c @@ -1,5 +1,6 @@ /* tables of names for values defined in constants.h - * Copyright (C) 1998-2002 D. Hugh Redelmeier. + * 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 @@ -10,8 +11,6 @@ * 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. - * - * RCSID $Id: constants.c 4612 2008-11-11 06:37:37Z andreas $ */ /* @@ -25,7 +24,6 @@ #include <netinet/in.h> #include <freeswan.h> -#include <ipsec_policy.h> #include "constants.h" #include "defs.h" @@ -36,42 +34,36 @@ const char compile_time_interop_options[] = "" #ifdef THREADS - " THREADS" -#endif -#ifdef LIBCURL - " LIBCURL" -#endif -#ifdef LIBLDAP - " LIBLDAP" + " THREADS" #endif #ifdef SMARTCARD - " SMARTCARD" + " SMARTCARD" #endif #ifdef VENDORID - " VENDORID" + " VENDORID" #endif #ifdef CISCO_QUIRKS - " CISCO_QUIRKS" + " CISCO_QUIRKS" #endif #ifdef USE_KEYRR - " KEYRR" + " KEYRR" #endif - ; + ; /* version */ static const char *const version_name[] = { - "ISAKMP Version 1.0", + "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 }; + { ISAKMP_MAJOR_VERSION<<ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, + ISAKMP_MAJOR_VERSION<<ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION, + version_name, NULL }; /* RFC 2459 CRL reason codes */ -static const char *const crl_reason_name[] = { +ENUM(crl_reason_names, REASON_UNSPECIFIED, REASON_REMOVE_FROM_CRL, "unspecified", "key compromise", "ca compromise", @@ -81,26 +73,20 @@ static const char *const crl_reason_name[] = { "certificate hold", "reason #7", "remove from crl" - }; - -enum_names crl_reason_names = - { REASON_UNSPECIFIED, REASON_REMOVE_FROM_CRL, crl_reason_name, NULL}; +); /* RFC 3706 Dead Peer Detection */ -static const char *const dpd_action_name[] = { +ENUM(dpd_action_names, DPD_ACTION_NONE, DPD_ACTION_RESTART, "none", "clear", "hold", "restart" - }; - -enum_names dpd_action_names = - { DPD_ACTION_NONE, DPD_ACTION_RESTART, dpd_action_name, NULL}; - +); + /* Timer events */ -static const char *const timer_event_name[] = { +ENUM(timer_event_names, EVENT_NULL, EVENT_LOG_DAILY, "EVENT_NULL", "EVENT_REINIT_SECRET", "EVENT_SHUNT_SCAN", @@ -113,16 +99,13 @@ static const char *const timer_event_name[] = { "EVENT_DPD", "EVENT_DPD_TIMEOUT", "EVENT_LOG_DAILY" - }; - -enum_names timer_event_names = - { EVENT_NULL, EVENT_LOG_DAILY, timer_event_name, NULL }; +); /* Domain of Interpretation */ static const char *const doi_name[] = { - "ISAKMP_DOI_ISAKMP", - "ISAKMP_DOI_IPSEC", + "ISAKMP_DOI_ISAKMP", + "ISAKMP_DOI_IPSEC", }; enum_names doi_names = { ISAKMP_DOI_ISAKMP, ISAKMP_DOI_IPSEC, doi_name, NULL }; @@ -155,7 +138,7 @@ const char *const debug_bit_names[] = { "impair-bust-mr2", NULL - }; +}; #endif /* State of exchanges */ @@ -197,78 +180,78 @@ static const char *const state_name[] = { "STATE_MODE_CFG_R4", "STATE_IKE_ROOF" - }; +}; enum_names state_names = - { STATE_MAIN_R0, STATE_IKE_ROOF-1, state_name, NULL }; + { STATE_MAIN_R0, STATE_IKE_ROOF-1, state_name, NULL }; /* story for state */ const char *const state_story[] = { - "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 */ + "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 */ + "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 */ - }; + "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 */ + "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 }; + { 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 */ - }; + "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}; + { RT_UNROUTED, RT_ROUTED_TUNNEL, routing_story_strings, NULL}; /* Payload types (RFC 2408 "ISAKMP" section 3.1) */ @@ -296,16 +279,18 @@ const char *const payload_name[] = { "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 }; +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 }; + { ISAKMP_NEXT_NONE, ISAKMP_NEXT_NATOA_RFC, payload_name, &payload_names_nat_d }; /* Exchange types (note: two discontinuous ranges) */ @@ -317,26 +302,26 @@ static const char *const exchange_name[] = { "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 }; + { 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 }; + { 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 */ @@ -345,7 +330,7 @@ const char *const sit_bit_names[] = { "SIT_SECRECY", "SIT_INTEGRITY", NULL - }; +}; /* Protocol IDs (RFC 2407 "IPsec DOI" section 4.4.1) */ @@ -354,78 +339,74 @@ static const char *const protocol_name[] = { "PROTO_IPSEC_AH", "PROTO_IPSEC_ESP", "PROTO_IPCOMP", - }; +}; enum_names protocol_names = - { PROTO_ISAKMP, PROTO_IPCOMP, protocol_name, NULL }; + { 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 }; + { KEY_IKE, KEY_IKE, isakmp_transform_name, NULL }; /* IPsec AH transform values */ static const char *const ah_transform_name[] = { - "AH_MD5", - "AH_SHA", - "AH_DES", - "AH_SHA2_256", - "AH_SHA2_384", - "AH_SHA2_512", - "AH_RIPEMD", - "AH_AES_XCBC_MAC", - "AH_RSA" - }; + "HMAC_MD5", + "HMAC_SHA1", + "DES_MAC", + "HMAC_SHA2_256", + "HMAC_SHA2_384", + "HMAC_SHA2_512", + "HMAC_RIPEMD", + "AES_XCBC_96", + "SIG_RSA" +}; enum_names ah_transformid_names = - { AH_MD5, AH_RSA, ah_transform_name, NULL }; + { AH_MD5, AH_RSA, ah_transform_name, NULL }; /* IPsec ESP transform values */ static const char *const esp_transform_name[] = { - "ESP_DES_IV64", - "ESP_DES", - "ESP_3DES", - "ESP_RC5", - "ESP_IDEA", - "ESP_CAST", - "ESP_BLOWFISH", - "ESP_3IDEA", - "ESP_DES_IV32", - "ESP_RC4", - "ESP_NULL", - "ESP_AES", - "ESP_AES-CTR", - "ESP_AES-CCM_8", - "ESP_AES-CCM_12", - "ESP_AES-CCM_16", - "ESP_UNASSIGNED_17", - "ESP_AES_GCM_8", - "ESP_AES_GCM_12", - "ESP_AES_GCM_16", - "ESP_SEED_CBC", - "ESP_CAMELLIA" - }; + "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" +}; -/* - * ipsec drafts suggest "high" ESP ids values for testing, - * assign generic ESP_ID<num> if not officially defined - */ static const char *const esp_transform_name_high[] = { - "ESP_SERPENT", - "ESP_TWOFISH" - }; + "SERPENT_CBC", + "TWOFISH_CBC" +}; enum_names esp_transformid_names_high = - { ESP_SERPENT, ESP_TWOFISH, esp_transform_name_high, NULL }; + { ESP_SERPENT, ESP_TWOFISH, esp_transform_name_high, NULL }; enum_names esp_transformid_names = - { ESP_DES_IV64, ESP_CAMELLIA, esp_transform_name, &esp_transformid_names_high }; + { ESP_DES_IV64, ESP_CAMELLIA, esp_transform_name, &esp_transformid_names_high }; /* IPCOMP transform values */ @@ -434,10 +415,10 @@ static const char *const ipcomp_transform_name[] = { "IPCOMP_DEFLAT", "IPCOMP_LZS", "IPCOMP_LZJH", - }; +}; enum_names ipcomp_transformid_names = - { IPCOMP_OUI, IPCOMP_LZJH, ipcomp_transform_name, NULL }; + { IPCOMP_OUI, IPCOMP_LZJH, ipcomp_transform_name, NULL }; /* Identification type values */ @@ -453,10 +434,10 @@ static const char *const ident_name[] = { "ID_DER_ASN1_DN", "ID_DER_ASN1_GN", "ID_KEY_ID", - }; +}; enum_names ident_names = - { ID_IPV4_ADDR, ID_KEY_ID, ident_name, NULL }; + { ID_IPV4_ADDR, ID_KEY_ID, ident_name, NULL }; /* Certificate type values */ @@ -472,21 +453,18 @@ static const char *const cert_type_name[] = { "CERT_ARL", "CERT_SPKI", "CERT_X509_ATTRIBUTE", - }; +}; enum_names cert_type_names = - { CERT_NONE, CERT_X509_ATTRIBUTE, cert_type_name, NULL }; + { CERT_NONE, CERT_X509_ATTRIBUTE, cert_type_name, NULL }; /* Certificate policy names */ -static const char *const cert_policy_name[] = { +ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND, "ALWAYS_SEND", "SEND_IF_ASKED", "NEVER_SEND", - }; - -enum_names cert_policy_names = - { CERT_ALWAYS_SEND, CERT_NEVER_SEND, cert_policy_name, NULL }; +); /* Goal BITs for establishing an SA * Note: we drop the POLICY_ prefix so that logs are more concise. @@ -494,7 +472,7 @@ enum_names cert_policy_names = const char *const sa_policy_bit_names[] = { "PSK", - "RSASIG", + "PUBKEY", "ENCRYPT", "AUTHENTICATE", "COMPRESS", @@ -517,24 +495,23 @@ const char *const sa_policy_bit_names[] = { "DONTREAUTH", "BEET", "MOBIKE", - "ECDSA", "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 @@ -560,7 +537,7 @@ const char *const oakley_attr_bit_names[] = { "OAKLEY_GROUP_ORDER", "OAKLEY_BLOCK_SIZE", NULL - }; +}; static const char *const oakley_var_attr_name[] = { "OAKLEY_GROUP_PRIME (variable length)", @@ -574,36 +551,36 @@ static const char *const oakley_var_attr_name[] = { 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 }; + 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 }; + 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 */ + 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 */ - }; + 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) */ @@ -617,7 +594,7 @@ static const char *const ipsec_attr_name[] = { "KEY_ROUNDS", "COMPRESS_DICT_SIZE", "COMPRESS_PRIVATE_ALG", - }; +}; static const char *const ipsec_var_attr_name[] = { "SA_LIFE_DURATION (variable length)", @@ -628,40 +605,40 @@ static const char *const ipsec_var_attr_name[] = { 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 }; + 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 }; + 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 */ - }; + 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 }; + { SA_LIFE_TYPE_SECONDS, SA_LIFE_TYPE_KBYTES, sa_lifetime_name, NULL }; /* Encapsulation Mode attribute */ @@ -670,55 +647,55 @@ static const char *const enc_mode_name[] = { "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", - }; + "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 }; + { 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 }; + { 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_ALGORITHM_HMAC_MD5", - "AUTH_ALGORITHM_HMAC_SHA1", - "AUTH_ALGORITHM_DES_MAC", - "AUTH_ALGORITHM_KPDK", - "AUTH_ALGORITHM_HMAC_SHA2_256", - "AUTH_ALGORITHM_HMAC_SHA2_384", - "AUTH_ALGORITHM_HMAC_SHA2_512", - "AUTH_ALGORITHM_HMAC_RIPEMD", - "AUTH_ALGORITHM_AES_XCBC_MAC", - "AUTH_ALGORITHM_SIG_RSA" - }; + "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[] = { - "AUTH_ALGORITHM_NULL" - }; + "NULL" + }; enum_names extended_auth_alg_names = - { AUTH_ALGORITHM_NULL, AUTH_ALGORITHM_NULL, extended_auth_alg_name, NULL }; + { AUTH_ALGORITHM_NULL, AUTH_ALGORITHM_NULL, extended_auth_alg_name, NULL }; enum_names auth_alg_names = - { AUTH_ALGORITHM_HMAC_MD5, AUTH_ALGORITHM_SIG_RSA, auth_alg_name - , &extended_auth_alg_names }; + { AUTH_ALGORITHM_HMAC_MD5, 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", + "Generic", + "RADIUS-CHAP", + "OTP", + "S/KEY", }; enum_names xauth_type_names = - { XAUTH_TYPE_GENERIC, XAUTH_TYPE_SKEY, xauth_type_name, NULL}; + { XAUTH_TYPE_GENERIC, XAUTH_TYPE_SKEY, xauth_type_name, NULL}; /* From draft-beaulieu-ike-xauth */ static const char *const xauth_attr_tv_name[] = { @@ -730,11 +707,11 @@ static const char *const xauth_attr_tv_name[] = { 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 }; + 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", @@ -751,8 +728,15 @@ static const char *const unity_attr_name[] = { }; enum_names unity_attr_names = - { UNITY_BANNER , UNITY_DDNS_HOSTNAME, unity_attr_name , &xauth_attr_tv_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", @@ -764,10 +748,10 @@ static const char *const xauth_attr_name[] = { "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 , &unity_attr_names }; + { XAUTH_USER_NAME , XAUTH_ANSWER, xauth_attr_name , µsoft_attr_names }; static const char *const modecfg_attr_name[] = { "INTERNAL_IP4_ADDRESS", @@ -785,97 +769,104 @@ static const char *const modecfg_attr_name[] = { "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 }; + { 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_LIFE_SECONDS, OAKLEY_LIFE_KILOBYTES, oakley_lifetime_name, NULL }; /* Oakley PRF attribute (none defined) */ enum_names oakley_prf_names = - { 1, 0, NULL, NULL }; + { 1, 0, NULL, NULL }; /* Oakley Encryption Algorithm attribute */ static const char *const oakley_enc_name[] = { - "OAKLEY_DES_CBC", - "OAKLEY_IDEA_CBC", - "OAKLEY_BLOWFISH_CBC", - "OAKLEY_RC5_R16_B64_CBC", - "OAKLEY_3DES_CBC", - "OAKLEY_CAST_CBC", - "OAKLEY_AES_CBC", - }; + "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_AES_CBC, oakley_enc_name, NULL }; + { OAKLEY_DES_CBC, OAKLEY_CAMELLIA_CBC, oakley_enc_name, NULL }; #else static const char *const oakley_enc_name_draft_aes_cbc_02[] = { - "OAKLEY_MARS_CBC" /* 65001 */, - "OAKLEY_RC6_CBC" /* 65002 */, - "OAKLEY_ID_65003" /* 65003 */, - "OAKLEY_SERPENT_CBC" /* 65004 */, - "OAKLEY_TWOFISH_CBC" /* 65005 */, + "MARS_CBC" /* 65001 */, + "RC6_CBC" /* 65002 */, + "ID_65003" /* 65003 */, + "SERPENT_CBC" /* 65004 */, + "TWOFISH_CBC" /* 65005 */, }; + static const char *const oakley_enc_name_ssh[] = { - "OAKLEY_TWOFISH_CBC_SSH", + "TWOFISH_CBC_SSH", }; + enum_names oakley_enc_names_ssh = - { OAKLEY_TWOFISH_CBC_SSH, OAKLEY_TWOFISH_CBC_SSH, oakley_enc_name_ssh - , NULL }; + { 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 }; + { 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_AES_CBC, oakley_enc_name - , &oakley_enc_names_draft_aes_cbc_02 }; + { 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[] = { - "OAKLEY_MD5", - "OAKLEY_SHA", - "OAKLEY_TIGER", - "OAKLEY_SHA2_256", - "OAKLEY_SHA2_384", - "OAKLEY_SHA2_512", - }; + "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_MD5, OAKLEY_SHA2_512, oakley_hash_name, NULL }; /* Oakley Authentication Method attribute */ static const char *const oakley_auth_name1[] = { - "OAKLEY_PRESHARED_KEY", - "OAKLEY_DSS_SIG", - "OAKLEY_RSA_SIG", - "OAKLEY_RSA_ENC", - "OAKLEY_RSA_ENC_REV", - "OAKLEY_ELGAMAL_ENC", - "OAKLEY_ELGAMAL_ENC_REV", - }; + "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", @@ -888,44 +879,64 @@ static const char *const oakley_auth_name3[] = { "XAUTHRespRSAEncryption", "XAUTHInitRSARevisedEncryption", "XAUTHRespRSARevisedEncryption", - }; +}; static enum_names oakley_auth_names1 = - { OAKLEY_PRESHARED_KEY, OAKLEY_ELGAMAL_ENC_REV - , oakley_auth_name1, NULL }; + { OAKLEY_PRESHARED_KEY, OAKLEY_ECDSA_521 + , oakley_auth_name1, NULL }; static enum_names oakley_auth_names2 = - { HybridInitRSA, HybridRespDSS - , oakley_auth_name2, &oakley_auth_names1 }; + { HybridInitRSA, HybridRespDSS + , oakley_auth_name2, &oakley_auth_names1 }; enum_names oakley_auth_names = - { XAUTHInitPreShared, XAUTHRespRSARevisedEncryption - , oakley_auth_name3, &oakley_auth_names2 }; + { XAUTHInitPreShared, XAUTHRespRSARevisedEncryption + , oakley_auth_name3, &oakley_auth_names2 }; /* Oakley Group Description attribute */ static const char *const oakley_group_name[] = { - "OAKLEY_GROUP_MODP768", - "OAKLEY_GROUP_MODP1024", - "OAKLEY_GROUP_GP155", - "OAKLEY_GROUP_GP185", - "OAKLEY_GROUP_MODP1536", - }; + "MODP_768", + "MODP_1024", + "GP_155", + "GP_185", + "MODP_1536", +}; static const char *const oakley_group_name_rfc3526[] = { - "OAKLEY_GROUP_MODP2048", - "OAKLEY_GROUP_MODP3072", - "OAKLEY_GROUP_MODP4096", - "OAKLEY_GROUP_MODP6144", - "OAKLEY_GROUP_MODP8192" + "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[] = { + "ECP_192", + "ECP_224" }; + +enum_names oakley_group_names_rfc5114 = + { ECP_192_BIT, 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 = - { OAKLEY_GROUP_MODP2048, OAKLEY_GROUP_MODP8192, - oakley_group_name_rfc3526, NULL }; + { MODP_2048_BIT, MODP_8192_BIT, + oakley_group_name_rfc3526, &oakley_group_names_rfc4753 }; enum_names oakley_group_names = - { OAKLEY_GROUP_MODP768, OAKLEY_GROUP_MODP1536, - oakley_group_name, &oakley_group_names_rfc3526 }; + { MODP_768_BIT, MODP_1536_BIT, + oakley_group_name, &oakley_group_names_rfc3526 }; /* Oakley Group Type attribute */ @@ -933,10 +944,10 @@ 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 }; + { OAKLEY_GROUP_TYPE_MODP, OAKLEY_GROUP_TYPE_EC2N, oakley_group_type_name, NULL }; /* Notify messages -- error types */ @@ -971,38 +982,38 @@ static const char *const notification_name[] = { "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", + "R_U_THERE", + "R_U_THERE_ACK", }; enum_names notification_dpd_names = - { R_U_THERE, R_U_THERE_ACK, - notification_dpd_name, NULL }; + { R_U_THERE, R_U_THERE_ACK, + notification_dpd_name, NULL }; enum_names ipsec_notification_names = - { IPSEC_RESPONDER_LIFETIME, IPSEC_INITIAL_CONTACT, - ipsec_notification_name, ¬ification_dpd_names }; + { IPSEC_RESPONDER_LIFETIME, IPSEC_INITIAL_CONTACT, + ipsec_notification_name, ¬ification_dpd_names }; enum_names notification_status_names = - { CONNECTED, CONNECTED, - notification_status_name, &ipsec_notification_names }; + { CONNECTED, CONNECTED, + notification_status_name, &ipsec_notification_names }; enum_names notification_names = - { INVALID_PAYLOAD_TYPE, UNEQUAL_PAYLOAD_LENGTHS, - notification_name, ¬ification_status_names }; + { INVALID_PAYLOAD_TYPE, UNEQUAL_PAYLOAD_LENGTHS, + notification_name, ¬ification_status_names }; /* MODECFG * From draft-dukes-ike-mode-cfg @@ -1014,20 +1025,20 @@ const char *const attr_msg_type_name[] = { "ISAKMP_CFG_SET", "ISAKMP_CFG_ACK", NULL - }; +}; enum_names attr_msg_type_names = - { 0 , ISAKMP_CFG_ACK, attr_msg_type_name , NULL }; + { 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 }; @@ -1045,7 +1056,7 @@ const struct af_info af_inet4_info = { 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, @@ -1055,29 +1066,28 @@ const struct af_info af_inet6_info = { 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; - } + 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) +bool subnetisnone(const ip_subnet *sn) { - ip_address base; + ip_address base; - networkof(sn, &base); - return isanyaddr(&base) && subnetishost(sn); + networkof(sn, &base); + return isanyaddr(&base) && subnetishost(sn); } /* BIND enumerated types */ @@ -1085,62 +1095,62 @@ subnetisnone(const ip_subnet *sn) #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 */ + "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 */ + "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 */ + "C_IN", /* 1 the arpa internet */ NULL - }; +}; enum_names rr_class_names = { C_IN, C_IN, rr_class_name, NULL }; @@ -1149,34 +1159,33 @@ enum_names rr_class_names = { C_IN, C_IN, rr_class_name, NULL }; * */ 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" + "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) +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; + 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 @@ -1185,16 +1194,16 @@ enum_name(enum_names *ed, unsigned long val) const char * enum_show(enum_names *ed, unsigned long val) { - const char *p = enum_name(ed, val); + const char *p = enum_name(ed, val); - if (p == NULL) - { - static char buf[12]; /* only one! I hope that it is big enough */ + 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; + snprintf(buf, sizeof(buf), "%lu??", val); + p = buf; + } + return p; } @@ -1203,123 +1212,126 @@ 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; + 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++) + for (p = ed; p != NULL; p = p->en_next_range) { - ptr = p->en_names[en - p->en_first]; - if (ptr == 0) continue; - /* if (strncmp(ptr, str, strlen(ptr))==0) */ - if (strcmp(ptr, str) == 0) - return en; + 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; + 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) +const char* bitnamesof(const char *const table[], lset_t val) { - char *p = bitnamesbuf; - lset_t bit; - const char *const *tp; + char *p = bitnamesbuf; + lset_t bit; + const char *const *tp; - if (val == 0) - return "none"; + if (val == 0) + return "none"; - for (tp = table, bit = 01; val != 0; bit <<= 1) - { - if (val & bit) + for (tp = table, bit = 01; val != 0; bit <<= 1) { - 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 (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 */ } - if (*tp != NULL) - tp++; /* move on, but not past end */ - } - *p = '\0'; - return bitnamesbuf; + *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* 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; + 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) +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; + 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; } @@ -1328,40 +1340,43 @@ 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; + const struct sparse_name *p; - for (p = sd; p->name != sparse_end; p++) - if (p->val == val) - return p->name; - return NULL; + 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* sparse_val_show(sparse_names sd, unsigned long val) { - const char *p = sparse_name(sd, val); + const char *p = sparse_name(sd, val); - if (p == NULL) - { - static char buf[12]; /* only one! I hope that it is big enough */ + 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; + 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(anyaddr(AF_INET, &ipv4_any)); + happy(anyaddr(AF_INET6, &ipv6_any)); - happy(addrtosubnet(&ipv4_any, &ipv4_wildcard)); - happy(addrtosubnet(&ipv6_any, &ipv6_wildcard)); + 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)); + 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 index 409dd1d61..5fe936e08 100644 --- a/src/pluto/constants.h +++ b/src/pluto/constants.h @@ -1,4 +1,3 @@ - /* manifest constants * Copyright (C) 1997 Angelos D. Keromytis. * Copyright (C) 1998-2002 D. Hugh Redelmeier. @@ -12,13 +11,15 @@ * 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. - * - * RCSID $Id: constants.h 4612 2008-11-11 06:37:37Z andreas $ */ #ifndef _CONSTANTS_H #define _CONSTANTS_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); @@ -28,8 +29,6 @@ extern void init_constants(void); * Any changes here should be reflected there. */ -#define elemsof(array) (sizeof(array) / sizeof(*(array))) /* number of elements in an array */ - /* 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. @@ -39,19 +38,10 @@ extern void init_constants(void); * <freeswan.h> defines err_t for this return type. */ -typedef int bool; -#define FALSE 0 -#define TRUE 1 - -#define NULL_FD (-1) /* NULL file descriptor */ +#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; } } -#define BITS_PER_BYTE 8 - -#define streq(a, b) (strcmp((a), (b)) == 0) /* clearer shorthand */ -#define strcaseeq(a, b) (strcasecmp((a), (b)) == 0) /* clearer shorthand */ - /* set type with room for at least 64 elements for ALG opts (was 32 in stock FS) */ typedef unsigned long long lset_t; @@ -71,8 +61,8 @@ typedef unsigned long long lset_t; # 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 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. @@ -86,10 +76,10 @@ typedef unsigned long long lset_t; */ 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 */ + 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; @@ -108,8 +98,8 @@ extern const char *bitnamesof(const char *const table[], lset_t val); * Often appropriate for enums defined by others. */ struct sparse_name { - unsigned long val; - const char *const name; + unsigned long val; + const char *const name; }; typedef const struct sparse_name sparse_names[]; @@ -119,264 +109,172 @@ extern const char sparse_end[]; #define FULL_INET_ADDRESS_SIZE 6 -/* Group parameters from draft-ietf-ike-01.txt section 6 */ - -#define MODP_GENERATOR "2" - -#define MODP768_MODULUS \ - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 " \ - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD " \ - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 " \ - "E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF" - -#define MODP1024_MODULUS \ - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 " \ - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD " \ - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 " \ - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED " \ - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 " \ - "FFFFFFFF FFFFFFFF" - -#define MODP1536_MODULUS \ - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 " \ - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD " \ - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 " \ - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED " \ - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D " \ - "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F " \ - "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D " \ - "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF " - -/* draft-ietf-ipsec-ike-modp-groups-03.txt */ -#define MODP2048_MODULUS \ - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ - "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ - "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ - "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ - "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ - "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ - "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF" - -#define MODP3072_MODULUS \ - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ - "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ - "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ - "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ - "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ - "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ - "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \ - "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \ - "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \ - "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ - "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \ - "43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF" - -#define MODP4096_MODULUS \ - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ - "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ - "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ - "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ - "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ - "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ - "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \ - "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \ - "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \ - "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ - "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \ - "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \ - "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \ - "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \ - "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \ - "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \ - "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" \ - "FFFFFFFF FFFFFFFF" - -/* copy&pasted from rfc3526: */ -#define MODP6144_MODULUS \ - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08" \ - "8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B" \ - "302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9" \ - "A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6" \ - "49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8" \ - "FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ - "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C" \ - "180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718" \ - "3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D" \ - "04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D" \ - "B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226" \ - "1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ - "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC" \ - "E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26" \ - "99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB" \ - "04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2" \ - "233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127" \ - "D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \ - "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD F8FF9406" \ - "AD9E530E E5DB382F 413001AE B06A53ED 9027D831 179727B0 865A8918" \ - "DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B DB7F1447 E6CC254B 33205151" \ - "2BD7AF42 6FB8F401 378CD2BF 5983CA01 C64B92EC F032EA15 D1721D03" \ - "F482D7CE 6E74FEF6 D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F" \ - "BEC7E8F3 23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \ - "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328 06A1D58B" \ - "B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C DA56C9EC 2EF29632" \ - "387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E" \ - "6DCC4024 FFFFFFFF FFFFFFFF" - -/* copy&pasted from rfc3526: */ -#define MODP8192_MODULUS \ - "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \ - "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \ - "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \ - "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \ - "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \ - "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \ - "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \ - "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \ - "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \ - "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \ - "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \ - "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \ - "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \ - "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \ - "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \ - "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \ - "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \ - "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \ - "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \ - "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \ - "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492" \ - "36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD" \ - "F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831" \ - "179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B" \ - "DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF" \ - "5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6" \ - "D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3" \ - "23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA" \ - "CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328" \ - "06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C" \ - "DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE" \ - "12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4" \ - "38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300" \ - "741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568" \ - "3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9" \ - "22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B" \ - "4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A" \ - "062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36" \ - "4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1" \ - "B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92" \ - "4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47" \ - "9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71" \ - "60C980DD 98EDD3DF FFFFFFFF FFFFFFFF" -#define LOCALSECRETSIZE (512 / BITS_PER_BYTE) - /* 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 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 MD2_DIGEST_SIZE (128 / BITS_PER_BYTE) -#define MD5_DIGEST_SIZE (128 / BITS_PER_BYTE) -#define SHA1_DIGEST_SIZE (160 / BITS_PER_BYTE) -#define SHA2_256_DIGEST_SIZE (256 / BITS_PER_BYTE) -#define SHA2_384_DIGEST_SIZE (384 / BITS_PER_BYTE) -#define SHA2_512_DIGEST_SIZE (512 / BITS_PER_BYTE) - -#define MD5_BLOCK_SIZE (512 / BITS_PER_BYTE) -#define SHA1_BLOCK_SIZE (512 / BITS_PER_BYTE) -#define SHA2_256_BLOCK_SIZE (512 / BITS_PER_BYTE) -#define SHA2_384_BLOCK_SIZE (1024 / BITS_PER_BYTE) -#define SHA2_512_BLOCK_SIZE (1024 / BITS_PER_BYTE) - -#define DES_CBC_BLOCK_SIZE (64 / BITS_PER_BYTE) - -#define DSS_QBITS 160 /* bits in DSS's "q" (FIPS 186-1) */ +#define DES_CBC_BLOCK_SIZE (64 / BITS_PER_BYTE) /* Maximum is required for SHA2_512 */ -#define MAX_DIGEST_LEN SHA2_512_DIGEST_SIZE -#define MAX_HASH_BLOCK_SIZE SHA2_512_BLOCK_SIZE +#define MAX_DIGEST_LEN HASH_SIZE_SHA512 /* RFC 2404 "HMAC-SHA-1-96" section 3 */ -#define HMAC_SHA1_KEY_LEN SHA1_DIGEST_SIZE +#define HMAC_SHA1_KEY_LEN HASH_SIZE_SHA1 /* RFC 2403 "HMAC-MD5-96" section 3 */ -#define HMAC_MD5_KEY_LEN MD5_DIGEST_SIZE +#define HMAC_MD5_KEY_LEN HASH_SIZE_MD5 -#define IKE_UDP_PORT 500 +#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 +}; + +extern enum_names ah_transformid_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_SERPENT = 252, + ESP_TWOFISH = 253 +}; + +extern enum_names esp_transformid_names; + +/* IPCOMP transform values + * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.5 + */ + +enum ipsec_comp_algo { + IPSCOMP_NONE = 0, + IPCOMP_OUI = 1, + IPCOMP_DEFLATE = 2, + IPCOMP_LZS = 3, + IPCOMP_LZJH = 4 +}; + +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_GOOD = 0, + CERT_REVOKED = 1, + CERT_UNKNOWN = 2, + CERT_UNDEFINED = 3 } cert_status_t; /* RFC 2459 CRL reason codes */ -extern enum_names crl_reason_names; +extern enum_name_t *crl_reason_names; typedef enum { - REASON_UNSPECIFIED = 0, - REASON_KEY_COMPROMISE = 1, - REASON_CA_COMPROMISE = 2, - REASON_AFFILIATION_CHANGED = 3, - REASON_SUPERSEDED = 4, - REASON_CESSATION_OF_OPERATON = 5, - REASON_CERTIFICATE_HOLD = 6, - REASON_REMOVE_FROM_CRL = 8 + REASON_UNSPECIFIED = 0, + REASON_KEY_COMPROMISE = 1, + REASON_CA_COMPROMISE = 2, + REASON_AFFILIATION_CHANGED = 3, + REASON_SUPERSEDED = 4, + REASON_CESSATION_OF_OPERATON = 5, + REASON_CERTIFICATE_HOLD = 6, + REASON_REMOVE_FROM_CRL = 8 } crl_reason_t; /* RFC 3706 Dead Peer Detection */ -extern enum_names dpd_action_names; +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_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_names timer_event_names; +extern enum_name_t *timer_event_names; enum event_type { - EVENT_NULL, /* non-event */ - EVENT_REINIT_SECRET, /* Refresh cookie secret */ + EVENT_NULL, /* non-event */ + EVENT_REINIT_SECRET, /* Refresh cookie secret */ #ifdef KLIPS - EVENT_SHUNT_SCAN, /* scan shunt eroutes known to kernel */ + EVENT_SHUNT_SCAN, /* scan shunt eroutes known to kernel */ #endif - 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 */ + 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 */ +#define EVENT_REINIT_SECRET_DELAY 3600 /* 1 hour */ +#define EVENT_RETRANSMIT_DELAY_0 10 /* 10 seconds */ /* Misc. stuff */ @@ -429,29 +327,29 @@ extern enum_names doi_names; 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_KLIPS LELEM(6) /* messages to KLIPS */ -#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_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_KLIPS LELEM(6) /* messages to KLIPS */ +#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 DBG_PRIVATE LELEM(11) /* private information: DANGER! */ -#define IMPAIR0 12 /* first bit for IMPAIR_* */ +#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 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 */ +#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 * @@ -484,86 +382,86 @@ extern enum_names state_names; extern const char *const state_story[]; enum state_kind { - STATE_UNDEFINED, /* 0 -- most likely accident */ + STATE_UNDEFINED, /* 0 -- most likely accident */ - /* Opportunism states: see "Opportunistic Encryption" 2.2 */ + /* Opportunism states: see "Opportunistic Encryption" 2.2 */ - OPPO_ACQUIRE, /* got an ACQUIRE message for this pair */ - OPPO_GW_DISCOVERED, /* got TXT specifying gateway */ + OPPO_ACQUIRE, /* got an ACQUIRE message for this pair */ + OPPO_GW_DISCOVERED, /* got TXT specifying gateway */ - /* IKE states */ + /* 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_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_QUICK_R0, + STATE_QUICK_I1, + STATE_QUICK_R1, + STATE_QUICK_I2, + STATE_QUICK_R2, - STATE_INFO, - STATE_INFO_PROTECTED, + STATE_INFO, + STATE_INFO_PROTECTED, - /* XAUTH states */ + /* 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, + 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 */ + /* 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, + 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 */ + /* 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_MODE_CFG_I0, /* initiator state (client) */ + STATE_MODE_CFG_R3, /* responder state (server) */ + STATE_MODE_CFG_I3, + STATE_MODE_CFG_R4, - STATE_IKE_ROOF + STATE_IKE_ROOF }; -#define STATE_IKE_FLOOR STATE_MAIN_R0 +#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 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)) + 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)) + || (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) + (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) @@ -575,11 +473,11 @@ enum state_kind { 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 */ + 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 */ }; @@ -593,14 +491,14 @@ 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 */ + 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) @@ -618,25 +516,25 @@ enum routing_t { 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_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_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) */ @@ -687,18 +585,24 @@ extern enum_names modecfg_attr_names; extern enum_names xauth_attr_names; -/* ISAKMP mode config attributes specific to the Unity vendor Id */ -#define UNITY_BANNER 28672 -#define UNITY_SAVE_PASSWD 28673 -#define UNITY_DEF_DOMAIN 28674 -#define UNITY_SPLITDNS_NAME 28675 -#define UNITY_SPLIT_INCLUDE 28676 -#define UNITY_NATT_PORT 28677 -#define UNITY_LOCAL_LAN 28678 -#define UNITY_PFS 28679 -#define UNITY_FW_TYPE 28680 -#define UNITY_BACKUP_SERVERS 28681 -#define UNITY_DDNS_HOSTNAME 28682 +/* ISAKMP mode config attributes specific to Microsoft */ +#define INTERNAL_IP4_SERVER 23456 +#define INTERNAL_IP6_SERVER 23457 + +extern enum_names microsoft_attr_names; + +/* ISAKMP mode config attributes specific to the Unity vendor ID */ +#define UNITY_BANNER 28672 +#define UNITY_SAVE_PASSWD 28673 +#define UNITY_DEF_DOMAIN 28674 +#define UNITY_SPLITDNS_NAME 28675 +#define UNITY_SPLIT_INCLUDE 28676 +#define UNITY_NATT_PORT 28677 +#define UNITY_LOCAL_LAN 28678 +#define UNITY_PFS 28679 +#define UNITY_FW_TYPE 28680 +#define UNITY_BACKUP_SERVERS 28681 +#define UNITY_DDNS_HOSTNAME 28682 #define UNITY_BASE UNITY_BANNER @@ -711,8 +615,8 @@ extern enum_names unity_attr_names; #define XAUTH_TYPE_SKEY 3 /* Values for XAUTH_STATUS */ -#define XAUTH_STATUS_FAIL 0 -#define XAUTH_STATUS_OK 1 +#define XAUTH_STATUS_FAIL 0 +#define XAUTH_STATUS_OK 1 extern enum_names xauth_type_names; @@ -732,19 +636,19 @@ 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 */ +#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 */ +#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 */ +#define ISAKMP_XCHG_ACK_INFO 34 /* Oakley Acknowledged Informational */ /* Flag bits */ @@ -774,20 +678,14 @@ extern enum_names protocol_names; /* 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)) \ - : "??") - -/* many transform values are moved to freeswan/ipsec_policy.h */ - -extern enum_names isakmp_transformid_names; + ((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 ah_transformid_names; -extern enum_names esp_transformid_names; -extern enum_names ipcomp_transformid_names; +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; @@ -801,15 +699,16 @@ typedef u_int16_t cpi_t; extern enum_names ident_names; extern enum_names cert_type_names; -extern enum_names cert_policy_names; + +extern enum_name_t *cert_policy_names; typedef enum certpolicy { - CERT_ALWAYS_SEND = 0, /* the default */ - CERT_SEND_IF_ASKED = 1, - CERT_NEVER_SEND = 2, + 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 */ + 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 @@ -825,36 +724,36 @@ extern const char *prettypolicy(lset_t policy); /* ISAKMP auth techniques (none means never negotiate) */ #define POLICY_PSK LELEM(0) -#define POLICY_RSASIG LELEM(1) +#define POLICY_PUBKEY LELEM(1) -#define POLICY_ISAKMP_SHIFT 0 /* log2(POLICY_PSK) */ -#define POLICY_ID_AUTH_MASK (POLICY_PSK | POLICY_RSASIG | POLICY_XAUTH_PSK | POLICY_XAUTH_RSASIG) -#define POLICY_ISAKMP_MASK POLICY_ID_AUTH_MASK /* all so far */ +#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_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) /* supress tunnel egress address checking */ +#define POLICY_DISABLEARRIVALCHECK LELEM(7) /* supress tunnel egress address checking */ -#define POLICY_IPSEC_SHIFT 2 /* log2(POLICY_ENCRYPT) */ -#define POLICY_IPSEC_MASK LRANGES(POLICY_ENCRYPT, POLICY_DISABLEARRIVALCHECK) +#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_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) +#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_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) @@ -864,21 +763,20 @@ extern const char *prettypolicy(lset_t policy); /* 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_ECDSASIG LELEM(25) /* ECDSA signature (IKEv2) */ -#define POLICY_PROXY LELEM(26) /* proxy transport mode (MIPv6) */ +#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.) @@ -903,17 +801,17 @@ extern const char *const oakley_attr_bit_names[]; #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_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_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_GROUP_ORDER 16 /* B/V */ #define OAKLEY_BLOCK_SIZE 17 /* for each Oakley attribute, which enum_names describes its values? */ @@ -926,14 +824,14 @@ extern enum_names *oakley_attr_val_descs[]; extern enum_names ipsec_attr_names; #define SA_LIFE_TYPE 1 -#define SA_LIFE_DURATION 2 /* B/V */ +#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 */ +#define COMPRESS_PRIVATE_ALG 9 /* B/V */ /* for each IPsec attribute, which enum_names describes its values? */ extern enum_names *ipsec_attr_val_descs[]; @@ -961,9 +859,9 @@ extern enum_names sa_lifetime_names; #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_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 @@ -971,7 +869,7 @@ extern enum_names sa_lifetime_names; extern enum_names enc_mode_names; -#define ENCAPSULATION_MODE_UNSPECIFIED 0 /* not legal -- used internally */ +#define ENCAPSULATION_MODE_UNSPECIFIED 0 /* not legal -- used internally */ #define ENCAPSULATION_MODE_TUNNEL 1 #define ENCAPSULATION_MODE_TRANSPORT 2 @@ -985,18 +883,18 @@ extern enum_names enc_mode_names; 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_NULL 251 +#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_NULL 251 /* Oakley Lifetime Type attribute * draft-ietf-ipsec-ike-01.txt appendix A @@ -1030,23 +928,24 @@ extern enum_names oakley_prf_names; 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_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_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_TWOFISH_CBC_SSH 65289 -#define OAKLEY_ENCRYPT_MAX 65535 /* pretty useless :) */ +#define OAKLEY_ENCRYPT_MAX 65535 /* pretty useless :) */ /* Oakley Hash Algorithm attribute * draft-ietf-ipsec-ike-01.txt appendix A @@ -1079,42 +978,35 @@ extern enum_names oakley_auth_names; #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 8 /* roof on auth values THAT WE SUPPORT */ +#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 HybridInitRSA 64221 +#define HybridRespRSA 64222 +#define HybridInitDSS 64223 +#define HybridRespDSS 64224 -#define XAUTHInitPreShared 65001 -#define XAUTHRespPreShared 65002 -#define XAUTHInitDSS 65003 +#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 +#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; -#define OAKLEY_GROUP_MODP768 1 -#define OAKLEY_GROUP_MODP1024 2 -#define OAKLEY_GROUP_GP155 3 -#define OAKLEY_GROUP_GP185 4 -#define OAKLEY_GROUP_MODP1536 5 - -#define OAKLEY_GROUP_MODP2048 14 -#define OAKLEY_GROUP_MODP3072 15 -#define OAKLEY_GROUP_MODP4096 16 -#define OAKLEY_GROUP_MODP6144 17 -#define OAKLEY_GROUP_MODP8192 18 -/* you must also touch: constants.c, crypto.c */ +/* you must also touch: constants.c, crypto.c */ /* Oakley Group Type attribute * draft-ietf-ipsec-ike-01.txt appendix A @@ -1134,54 +1026,54 @@ extern enum_names notification_names; extern enum_names ipsec_notification_names; typedef enum { - NOTHING_WRONG = 0, /* unofficial! */ - - INVALID_PAYLOAD_TYPE = 1, - DOI_NOT_SUPPORTED = 2, - SITUATION_NOT_SUPPORTED = 3, - INVALID_COOKIE = 4, - INVALID_MAJOR_VERSION = 5, - INVALID_MINOR_VERSION = 6, - INVALID_EXCHANGE_TYPE = 7, - INVALID_FLAGS = 8, - INVALID_MESSAGE_ID = 9, - INVALID_PROTOCOL_ID = 10, - INVALID_SPI = 11, - INVALID_TRANSFORM_ID = 12, - ATTRIBUTES_NOT_SUPPORTED = 13, - NO_PROPOSAL_CHOSEN = 14, - BAD_PROPOSAL_SYNTAX = 15, - PAYLOAD_MALFORMED = 16, - INVALID_KEY_INFORMATION = 17, - INVALID_ID_INFORMATION = 18, - INVALID_CERT_ENCODING = 19, - INVALID_CERTIFICATE = 20, - CERT_TYPE_UNSUPPORTED = 21, - INVALID_CERT_AUTHORITY = 22, - INVALID_HASH_INFORMATION = 23, - AUTHENTICATION_FAILED = 24, - INVALID_SIGNATURE = 25, - ADDRESS_NOTIFICATION = 26, - NOTIFY_SA_LIFETIME = 27, - CERTIFICATE_UNAVAILABLE = 28, - UNSUPPORTED_EXCHANGE_TYPE = 29, - UNEQUAL_PAYLOAD_LENGTHS = 30, - - /* ISAKMP status type */ - 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 - - } notification_t; + NOTHING_WRONG = 0, /* unofficial! */ + + INVALID_PAYLOAD_TYPE = 1, + DOI_NOT_SUPPORTED = 2, + SITUATION_NOT_SUPPORTED = 3, + INVALID_COOKIE = 4, + INVALID_MAJOR_VERSION = 5, + INVALID_MINOR_VERSION = 6, + INVALID_EXCHANGE_TYPE = 7, + INVALID_FLAGS = 8, + INVALID_MESSAGE_ID = 9, + INVALID_PROTOCOL_ID = 10, + INVALID_SPI = 11, + INVALID_TRANSFORM_ID = 12, + ATTRIBUTES_NOT_SUPPORTED = 13, + NO_PROPOSAL_CHOSEN = 14, + BAD_PROPOSAL_SYNTAX = 15, + PAYLOAD_MALFORMED = 16, + INVALID_KEY_INFORMATION = 17, + INVALID_ID_INFORMATION = 18, + INVALID_CERT_ENCODING = 19, + INVALID_CERTIFICATE = 20, + CERT_TYPE_UNSUPPORTED = 21, + INVALID_CERT_AUTHORITY = 22, + INVALID_HASH_INFORMATION = 23, + AUTHENTICATION_FAILED = 24, + INVALID_SIGNATURE = 25, + ADDRESS_NOTIFICATION = 26, + NOTIFY_SA_LIFETIME = 27, + CERTIFICATE_UNAVAILABLE = 28, + UNSUPPORTED_EXCHANGE_TYPE = 29, + UNEQUAL_PAYLOAD_LENGTHS = 30, + + /* ISAKMP status type */ + 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 + + } notification_t; /* Public key algorithm number @@ -1192,8 +1084,8 @@ typedef enum { enum pubkey_alg { - PUBKEY_ALG_RSA = 1, - PUBKEY_ALG_DSA = 3, + PUBKEY_ALG_RSA = 1, + PUBKEY_ALG_DSA = 3, }; /* Limits on size of RSA moduli. @@ -1203,37 +1095,37 @@ enum pubkey_alg * real security. For now, we require 512 bits. */ -#define RSA_MIN_OCTETS_RFC 12 +#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_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" +#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) +#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 */ + 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; + af_inet4_info, + af_inet6_info; extern const struct af_info *aftoinfo(int af); @@ -1245,18 +1137,18 @@ extern bool subnetisnone(const ip_subnet *sn); /* BIND enumerated types */ extern enum_names - rr_qtype_names, - rr_type_names, - rr_class_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) */ + 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) */ }; /* @@ -1272,4 +1164,7 @@ enum dns_auth_level { /* 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 index 00197321c..00c863f18 100644 --- a/src/pluto/cookie.c +++ b/src/pluto/cookie.c @@ -1,6 +1,7 @@ /* 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 @@ -11,8 +12,6 @@ * 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. - * - * RCSID $Id: cookie.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdio.h> @@ -23,45 +22,52 @@ #include <freeswan.h> +#include <library.h> +#include <crypto/rngs/rng.h> + #include "constants.h" #include "defs.h" -#include "sha1.h" -#include "rnd.h" #include "cookie.h" -const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */ +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, const ip_address *addr) +void get_cookie(bool initiator, u_int8_t *cookie, int length, ip_address *addr) { - u_char buffer[SHA1_DIGEST_SIZE]; - SHA1_CTX ctx; + 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;})]; - do { - if (initiator) - { - get_rnd_bytes(cookie, length); - } - else /* Responder cookie */ - { - /* This looks as good as any way */ - size_t addr_length; - static u_int32_t counter = 0; - unsigned char addr_buff[ - 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 */ - addr_length = addrbytesof(addr, addr_buff, sizeof(addr_buff)); - SHA1Init(&ctx); - SHA1Update(&ctx, addr_buff, addr_length); - SHA1Update(&ctx, secret_of_the_day, sizeof(secret_of_the_day)); - counter++; - SHA1Update(&ctx, (const void *) &counter, sizeof(counter)); - SHA1Final(buffer, &ctx); - 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 index b52bb2299..809d66491 100644 --- a/src/pluto/cookie.h +++ b/src/pluto/cookie.h @@ -10,15 +10,13 @@ * 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. - * - * RCSID $Id: cookie.h 3252 2007-10-06 21:24:50Z andreas $ */ #include <freeswan.h> -extern const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */ +extern const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */ -extern void get_cookie(bool initiator, u_int8_t *cookie, int length - , const ip_address *addr); +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 index c891d19e6..c800f2acc 100644 --- a/src/pluto/crl.c +++ b/src/pluto/crl.c @@ -1,5 +1,7 @@ /* Support of X.509 certificate revocation lists (CRLs) - * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * 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 @@ -10,8 +12,6 @@ * 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. - * - * RCSID $Id: crl.c 4632 2008-11-11 18:37:19Z martin $ */ #include <stdlib.h> @@ -23,13 +23,15 @@ #include <sys/types.h> #include <freeswan.h> -#include <ipsec_policy.h> + +#include <asn1/asn1.h> +#include <asn1/asn1_parser.h> +#include <asn1/oid.h> +#include <crypto/hashers/hasher.h> #include "constants.h" #include "defs.h" #include "log.h" -#include "asn1.h" -#include <asn1/oid.h> #include "x509.h" #include "crl.h" #include "ca.h" @@ -37,482 +39,482 @@ #include "keys.h" #include "whack.h" #include "fetch.h" -#include "sha1.h" + /* chained lists of X.509 crls */ static x509crl_t *x509crls = NULL; -/* ASN.1 definition of an X.509 certificate list */ - +/** + * ASN.1 definition of an X.509 certificate revocation list + */ static const asn1Object_t crlObjects[] = { - { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ - { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "version", ASN1_INTEGER, ASN1_OPT | - ASN1_BODY }, /* 2 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ - { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */ - { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ - { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */ - { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */ - { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT | - ASN1_LOOP }, /* 8 */ - { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */ - { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */ - { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */ - { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT | - ASN1_LOOP }, /* 12 */ - { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ - { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */ - { 6, "critical", ASN1_BOOLEAN, ASN1_DEF | - ASN1_BODY }, /* 15 */ - { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */ - { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */ - { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */ - { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */ - { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */ - { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */ - { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */ - { 5, "critical", ASN1_BOOLEAN, ASN1_DEF | - ASN1_BODY }, /* 23 */ - { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */ - { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ - { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */ - }; - -#define CRL_OBJ_CERTIFICATE_LIST 0 + { 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "version", ASN1_INTEGER, ASN1_OPT | + ASN1_BODY }, /* 2 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ + { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */ + { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ + { 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */ + { 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */ + { 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT | + ASN1_LOOP }, /* 8 */ + { 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */ + { 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */ + { 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */ + { 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT | + ASN1_LOOP }, /* 12 */ + { 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ + { 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */ + { 6, "critical", ASN1_BOOLEAN, ASN1_DEF | + ASN1_BODY }, /* 15 */ + { 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */ + { 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */ + { 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */ + { 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */ + { 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */ + { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */ + { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */ + { 5, "critical", ASN1_BOOLEAN, ASN1_DEF | + ASN1_BODY }, /* 23 */ + { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */ + { 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */ + { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 28 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; + +#define CRL_OBJ_CERTIFICATE_LIST 0 #define CRL_OBJ_TBS_CERT_LIST 1 -#define CRL_OBJ_VERSION 2 -#define CRL_OBJ_SIG_ALG 4 -#define CRL_OBJ_ISSUER 5 -#define CRL_OBJ_THIS_UPDATE 6 -#define CRL_OBJ_NEXT_UPDATE 7 +#define CRL_OBJ_VERSION 2 +#define CRL_OBJ_SIG_ALG 4 +#define CRL_OBJ_ISSUER 5 +#define CRL_OBJ_THIS_UPDATE 6 +#define CRL_OBJ_NEXT_UPDATE 7 #define CRL_OBJ_USER_CERTIFICATE 10 #define CRL_OBJ_REVOCATION_DATE 11 #define CRL_OBJ_CRL_ENTRY_EXTN_ID 14 #define CRL_OBJ_CRL_ENTRY_CRITICAL 15 -#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16 -#define CRL_OBJ_EXTN_ID 22 -#define CRL_OBJ_CRITICAL 23 -#define CRL_OBJ_EXTN_VALUE 24 -#define CRL_OBJ_ALGORITHM 27 -#define CRL_OBJ_SIGNATURE 28 -#define CRL_OBJ_ROOF 29 - +#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16 +#define CRL_OBJ_EXTN_ID 22 +#define CRL_OBJ_CRITICAL 23 +#define CRL_OBJ_EXTN_VALUE 24 +#define CRL_OBJ_ALGORITHM 27 +#define CRL_OBJ_SIGNATURE 28 const x509crl_t empty_x509crl = { - NULL , /* *next */ - UNDEFINED_TIME, /* installed */ - NULL , /* distributionPoints */ - { NULL, 0 } , /* certificateList */ - { NULL, 0 } , /* tbsCertList */ - 1 , /* version */ - OID_UNKNOWN , /* sigAlg */ - { NULL, 0 } , /* issuer */ - UNDEFINED_TIME, /* thisUpdate */ - UNDEFINED_TIME, /* nextUpdate */ - NULL , /* revokedCertificates */ - /* crlExtensions */ - /* extension */ - /* extnID */ - /* critical */ - /* extnValue */ - { NULL, 0 } , /* authKeyID */ - { NULL, 0 } , /* authKeySerialNumber */ - { NULL, 0 } , /* crlNumber */ - OID_UNKNOWN , /* algorithm */ - { NULL, 0 } /* signature */ + NULL , /* *next */ + UNDEFINED_TIME, /* installed */ + NULL , /* distributionPoints */ + { NULL, 0 } , /* certificateList */ + { NULL, 0 } , /* tbsCertList */ + 1 , /* version */ + OID_UNKNOWN , /* sigAlg */ + { NULL, 0 } , /* issuer */ + UNDEFINED_TIME, /* thisUpdate */ + UNDEFINED_TIME, /* nextUpdate */ + NULL , /* revokedCertificates */ + /* crlExtensions */ + /* extension */ + /* extnID */ + /* critical */ + /* extnValue */ + { NULL, 0 } , /* authKeyID */ + { NULL, 0 } , /* authKeySerialNumber */ + { NULL, 0 } , /* crlNumber */ + OID_UNKNOWN , /* algorithm */ + { NULL, 0 } /* signature */ }; -/* - * get the X.509 CRL with a given issuer +/** + * Get the X.509 CRL with a given issuer */ -static x509crl_t* -get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid) +static x509crl_t* get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid) { - x509crl_t *crl = x509crls; - x509crl_t *prev_crl = NULL; - - while (crl != NULL) - { - if ((keyid.ptr != NULL && crl->authKeyID.ptr != NULL) - ? same_keyid(keyid, crl->authKeyID) - : (same_dn(crl->issuer, issuer) && same_serial(serial, crl->authKeySerialNumber))) + x509crl_t *crl = x509crls; + x509crl_t *prev_crl = NULL; + + while (crl != NULL) { - if (crl != x509crls) - { - /* bring the CRL up front */ - prev_crl->next = crl->next; - crl->next = x509crls; - x509crls = crl; - } - return crl; + if ((keyid.ptr != NULL && crl->authKeyID.ptr != NULL) + ? same_keyid(keyid, crl->authKeyID) + : (same_dn(crl->issuer, issuer) && same_serial(serial, crl->authKeySerialNumber))) + { + if (crl != x509crls) + { + /* bring the CRL up front */ + prev_crl->next = crl->next; + crl->next = x509crls; + x509crls = crl; + } + return crl; + } + prev_crl = crl; + crl = crl->next; } - prev_crl = crl; - crl = crl->next; - } - return NULL; + return NULL; } -/* - * free the dynamic memory used to store revoked certificates +/** + * Free the dynamic memory used to store revoked certificates */ -static void -free_revoked_certs(revokedCert_t* revokedCerts) +static void free_revoked_certs(revokedCert_t* revokedCerts) { - while (revokedCerts != NULL) - { - revokedCert_t * revokedCert = revokedCerts; - revokedCerts = revokedCert->next; - pfree(revokedCert); - } + while (revokedCerts != NULL) + { + revokedCert_t * revokedCert = revokedCerts; + revokedCerts = revokedCert->next; + free(revokedCert); + } } -/* - * free the dynamic memory used to store CRLs +/** + * Free the dynamic memory used to store CRLs */ -void -free_crl(x509crl_t *crl) +void free_crl(x509crl_t *crl) { - free_revoked_certs(crl->revokedCertificates); - free_generalNames(crl->distributionPoints, TRUE); - pfree(crl->certificateList.ptr); - pfree(crl); + free_revoked_certs(crl->revokedCertificates); + free_generalNames(crl->distributionPoints, TRUE); + free(crl->certificateList.ptr); + free(crl); } -static void -free_first_crl(void) +static void free_first_crl(void) { - x509crl_t *crl = x509crls; + x509crl_t *crl = x509crls; - x509crls = crl->next; - free_crl(crl); + x509crls = crl->next; + free_crl(crl); } -void -free_crls(void) +void free_crls(void) { - lock_crl_list("free_crls"); + lock_crl_list("free_crls"); - while (x509crls != NULL) - free_first_crl(); + while (x509crls != NULL) + free_first_crl(); - unlock_crl_list("free_crls"); + unlock_crl_list("free_crls"); } -/* +/** * Insert X.509 CRL into chained list */ -bool -insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl) +bool insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl) { - x509crl_t *crl = alloc_thing(x509crl_t, "x509crl"); - - *crl = empty_x509crl; - - if (parse_x509crl(blob, 0, crl)) - { - x509cert_t *issuer_cert; - x509crl_t *oldcrl; - bool valid_sig; - generalName_t *gn; - - /* add distribution point */ - gn = alloc_thing(generalName_t, "generalName"); - gn->kind = GN_URI; - gn->name = crl_uri; - gn->next = crl->distributionPoints; - crl->distributionPoints = gn; - - lock_authcert_list("insert_crl"); - /* get the issuer cacert */ - issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber, - crl->authKeyID, AUTH_CA); - if (issuer_cert == NULL) - { - plog("crl issuer cacert not found"); - free_crl(crl); - 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 = check_signature(crl->tbsCertList, crl->signature - , crl->algorithm, crl->algorithm, issuer_cert); - unlock_authcert_list("insert_crl"); + x509crl_t *crl = malloc_thing(x509crl_t); - if (!valid_sig) - { - free_crl(crl); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("crl signature is valid") - ) - - lock_crl_list("insert_crl"); - oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber - , crl->authKeyID); + *crl = empty_x509crl; - if (oldcrl != NULL) + if (parse_x509crl(blob, 0, crl)) { - if (crl->thisUpdate > oldcrl->thisUpdate) - { - /* keep any known CRL distribution points */ - add_distribution_points(oldcrl->distributionPoints - , &crl->distributionPoints); - - /* now delete the old CRL */ - free_first_crl(); + x509cert_t *issuer_cert; + x509crl_t *oldcrl; + bool valid_sig; + generalName_t *gn; + + /* add distribution point */ + gn = malloc_thing(generalName_t); + gn->kind = GN_URI; + gn->name = crl_uri; + gn->next = crl->distributionPoints; + crl->distributionPoints = gn; + + lock_authcert_list("insert_crl"); + /* get the issuer cacert */ + issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber, + crl->authKeyID, AUTH_CA); + if (issuer_cert == NULL) + { + plog("crl issuer cacert not found"); + free_crl(crl); + unlock_authcert_list("insert_crl"); + return FALSE; + } DBG(DBG_CONTROL, - DBG_log("thisUpdate is newer - existing crl deleted") + DBG_log("crl issuer cacert found") ) - } - else - { - unlock_crl_list("insert_crls"); + + /* check the issuer's signature of the crl */ + valid_sig = x509_check_signature(crl->tbsCertList, crl->signature, + crl->algorithm, issuer_cert); + unlock_authcert_list("insert_crl"); + + if (!valid_sig) + { + free_crl(crl); + return FALSE; + } DBG(DBG_CONTROL, - DBG_log("thisUpdate is not newer - existing crl not replaced"); + DBG_log("crl signature is valid") ) - free_crl(crl); - return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval; - } - } - /* insert new CRL */ - crl->next = x509crls; - x509crls = crl; + lock_crl_list("insert_crl"); + oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber + , crl->authKeyID); - unlock_crl_list("insert_crl"); + if (oldcrl != NULL) + { + if (crl->thisUpdate > oldcrl->thisUpdate) + { + /* keep any known CRL distribution points */ + add_distribution_points(oldcrl->distributionPoints + , &crl->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(crl); + return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval; + } + } - /* If crl caching is enabled then the crl is saved locally. - * Only http or ldap URIs are cached but not local file URIs. - * The issuer's subjectKeyID is used as a unique filename - */ - if (cache_crl && strncasecmp(crl_uri.ptr, "file", 4) != 0) + /* insert new CRL */ + crl->next = x509crls; + x509crls = crl; + + 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 issuer's subjectKeyID is used as a unique filename + */ + if (cache_crl && strncasecmp(crl_uri.ptr, "file", 4) != 0) + { + char path[BUF_LEN], buf[BUF_LEN]; + char digest_buf[HASH_SIZE_SHA1]; + chunk_t subjectKeyID = chunk_from_buf(digest_buf); + bool has_keyID; + + if (issuer_cert->subjectKeyID.ptr == NULL) + { + has_keyID = compute_subjectKeyID(issuer_cert, subjectKeyID); + } + else + { + subjectKeyID = issuer_cert->subjectKeyID; + has_keyID = TRUE; + } + if (has_keyID) + { + datatot(subjectKeyID.ptr, subjectKeyID.len, 16, buf, BUF_LEN); + snprintf(path, BUF_LEN, "%s/%s.crl", CRL_PATH, buf); + chunk_write(crl->certificateList, path, "crl", 0022, TRUE); + } + } + + /* is the fetched crl valid? */ + return crl->nextUpdate - time(NULL) > 2*crl_check_interval; + } + else { - char path[BUF_LEN]; - char buf[BUF_LEN]; - char digest_buf[SHA1_DIGEST_SIZE]; - chunk_t subjectKeyID = { digest_buf, SHA1_DIGEST_SIZE }; - - if (issuer_cert->subjectKeyID.ptr == NULL) - compute_subjectKeyID(issuer_cert, subjectKeyID); - else - subjectKeyID = issuer_cert->subjectKeyID; - - datatot(subjectKeyID.ptr, subjectKeyID.len, 16, buf, BUF_LEN); - snprintf(path, BUF_LEN, "%s/%s.crl", CRL_PATH, buf); - write_chunk(path, "crl", crl->certificateList, 0022, TRUE); + plog(" error in X.509 crl"); + free_crl(crl); + return FALSE; } - - /* is the fetched crl valid? */ - return crl->nextUpdate - time(NULL) > 2*crl_check_interval; - } - else - { - plog(" error in X.509 crl"); - free_crl(crl); - return FALSE; - } } -/* +/** * Loads CRLs */ -void -load_crls(void) +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"); + 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 { - while (n--) - { - bool pgp = FALSE; - chunk_t blob = empty_chunk; - char *filename = filelist[n]->d_name; + plog("Changing to directory '%s'", CRL_PATH); + n = scandir(CRL_PATH, &filelist, file_select, alphasort); - if (load_coded_file(filename, NULL, "crl", &blob, &pgp)) + if (n < 0) + plog(" scandir() error"); + else { - chunk_t crl_uri; - - crl_uri.len = 7 + sizeof(CRL_PATH) + strlen(filename); - crl_uri.ptr = alloc_bytes(crl_uri.len + 1, "crl uri"); - - /* build CRL file URI */ - snprintf(crl_uri.ptr, crl_uri.len + 1, "file://%s/%s" - , CRL_PATH, filename); - - insert_crl(blob, crl_uri, FALSE); + while (n--) + { + bool pgp = FALSE; + chunk_t blob = chunk_empty; + char *filename = filelist[n]->d_name; + + if (load_coded_file(filename, NULL, "crl", &blob, &pgp)) + { + chunk_t crl_uri; + + crl_uri.len = 7 + sizeof(CRL_PATH) + strlen(filename); + crl_uri.ptr = malloc(crl_uri.len + 1); + + /* build CRL file URI */ + snprintf(crl_uri.ptr, crl_uri.len + 1, "file://%s/%s" + , CRL_PATH, filename); + + insert_crl(blob, crl_uri, FALSE); + } + free(filelist[n]); + } + free(filelist); } - free(filelist[n]); - } - free(filelist); } - } - /* restore directory path */ - ignore_result(chdir(save_dir)); + /* restore directory path */ + ignore_result(chdir(save_dir)); } -/* +/** * Parses a CRL revocation reason code */ -static crl_reason_t -parse_crl_reasonCode(chunk_t object) +static crl_reason_t parse_crl_reasonCode(chunk_t object) { - crl_reason_t reason = REASON_UNSPECIFIED; - - if (*object.ptr == ASN1_ENUMERATED - && asn1_length(&object) == 1) - { - reason = *object.ptr; - } - - DBG(DBG_PARSING, - DBG_log(" '%s'", enum_name(&crl_reason_names, reason)) - ) - return reason; + crl_reason_t reason = REASON_UNSPECIFIED; + + if (*object.ptr == ASN1_ENUMERATED + && asn1_length(&object) == 1) + { + reason = *object.ptr; + } + + DBG(DBG_PARSING, + DBG_log(" '%N'", crl_reason_names, reason) + ) + return reason; } /* * Parses an X.509 CRL */ -bool -parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl) +bool parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl) { - u_char buf[BUF_LEN]; - asn1_ctx_t ctx; - bool critical; - chunk_t extnID; - chunk_t userCertificate = empty_chunk; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); - - while (objectID < CRL_OBJ_ROOF) - { - if (!extract_object(crlObjects, &objectID, &object, &level, &ctx)) - return FALSE; - - /* those objects which will parsed further need the next higher level */ - level++; - - switch (objectID) { - case CRL_OBJ_CERTIFICATE_LIST: - crl->certificateList = object; - break; - case CRL_OBJ_TBS_CERT_LIST: - crl->tbsCertList = object; - break; - case CRL_OBJ_VERSION: - crl->version = (object.len) ? (1+(u_int)*object.ptr) : 1; - DBG(DBG_PARSING, - DBG_log(" v%d", crl->version); - ) - break; - case CRL_OBJ_SIG_ALG: - crl->sigAlg = parse_algorithmIdentifier(object, level, NULL); - break; - case CRL_OBJ_ISSUER: - crl->issuer = object; - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'",buf) - ) - break; - case CRL_OBJ_THIS_UPDATE: - crl->thisUpdate = parse_time(object, level); - break; - case CRL_OBJ_NEXT_UPDATE: - crl->nextUpdate = parse_time(object, level); - break; - case CRL_OBJ_USER_CERTIFICATE: - userCertificate = object; - break; - case CRL_OBJ_REVOCATION_DATE: - { - /* put all the serial numbers and the revocation date in a chained list - with revocedCertificates pointing to the first revoked certificate */ - - revokedCert_t *revokedCert = alloc_thing(revokedCert_t, "revokedCert"); - revokedCert->userCertificate = userCertificate; - revokedCert->revocationDate = parse_time(object, level); - revokedCert->revocationReason = REASON_UNSPECIFIED; - revokedCert->next = crl->revokedCertificates; - crl->revokedCertificates = revokedCert; - } - break; - case CRL_OBJ_CRL_ENTRY_EXTN_ID: - case CRL_OBJ_EXTN_ID: - extnID = object; - break; - case CRL_OBJ_CRL_ENTRY_CRITICAL: - case CRL_OBJ_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - break; - case CRL_OBJ_CRL_ENTRY_EXTN_VALUE: - case CRL_OBJ_EXTN_VALUE: - { - u_int extn_oid = known_oid(extnID); - - if (extn_oid == OID_CRL_REASON_CODE) - { - crl->revokedCertificates->revocationReason = - parse_crl_reasonCode(object); - } - else if (extn_oid == OID_AUTHORITY_KEY_ID) - { - parse_authorityKeyIdentifier(object, level - , &crl->authKeyID, &crl->authKeySerialNumber); - } - else if (extn_oid == OID_CRL_NUMBER) - { - if (!parse_asn1_simple_object(&object, ASN1_INTEGER, level, "crlNumber")) - return FALSE; - crl->crlNumber = object; + u_char buf[BUF_LEN]; + asn1_parser_t *parser; + chunk_t extnID; + chunk_t userCertificate = chunk_empty; + chunk_t object; + int objectID; + bool success = FALSE; + bool critical; + + parser = asn1_parser_create(crlObjects, blob); + + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser)+1; + + switch (objectID) { + case CRL_OBJ_CERTIFICATE_LIST: + crl->certificateList = object; + break; + case CRL_OBJ_TBS_CERT_LIST: + crl->tbsCertList = object; + break; + case CRL_OBJ_VERSION: + crl->version = (object.len) ? (1+(u_int)*object.ptr) : 1; + DBG(DBG_PARSING, + DBG_log(" v%d", crl->version); + ) + break; + case CRL_OBJ_SIG_ALG: + crl->sigAlg = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case CRL_OBJ_ISSUER: + crl->issuer = object; + DBG(DBG_PARSING, + dntoa(buf, BUF_LEN, object); + DBG_log(" '%s'",buf) + ) + break; + case CRL_OBJ_THIS_UPDATE: + crl->thisUpdate = asn1_parse_time(object, level); + break; + case CRL_OBJ_NEXT_UPDATE: + crl->nextUpdate = asn1_parse_time(object, level); + break; + case CRL_OBJ_USER_CERTIFICATE: + userCertificate = object; + break; + case CRL_OBJ_REVOCATION_DATE: + { + /* put all the serial numbers and the revocation date in a chained list + with revocedCertificates pointing to the first revoked certificate */ + + revokedCert_t *revokedCert = malloc_thing(revokedCert_t); + revokedCert->userCertificate = userCertificate; + revokedCert->revocationDate = asn1_parse_time(object, level); + revokedCert->revocationReason = REASON_UNSPECIFIED; + revokedCert->next = crl->revokedCertificates; + crl->revokedCertificates = revokedCert; + } + break; + case CRL_OBJ_CRL_ENTRY_EXTN_ID: + case CRL_OBJ_EXTN_ID: + extnID = object; + break; + case CRL_OBJ_CRL_ENTRY_CRITICAL: + case CRL_OBJ_CRITICAL: + critical = object.len && *object.ptr; + DBG(DBG_PARSING, + DBG_log(" %s",(critical)?"TRUE":"FALSE"); + ) + break; + case CRL_OBJ_CRL_ENTRY_EXTN_VALUE: + case CRL_OBJ_EXTN_VALUE: + { + u_int extn_oid = asn1_known_oid(extnID); + + if (extn_oid == OID_CRL_REASON_CODE) + { + crl->revokedCertificates->revocationReason = + parse_crl_reasonCode(object); + } + else if (extn_oid == OID_AUTHORITY_KEY_ID) + { + parse_authorityKeyIdentifier(object, level + , &crl->authKeyID, &crl->authKeySerialNumber); + } + else if (extn_oid == OID_CRL_NUMBER) + { + if (!asn1_parse_simple_object(&object, ASN1_INTEGER, + level, "crlNumber")) + { + goto end; + } + crl->crlNumber = object; + } + } + break; + case CRL_OBJ_ALGORITHM: + crl->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case CRL_OBJ_SIGNATURE: + crl->signature = object; + break; + default: + break; } - } - break; - case CRL_OBJ_ALGORITHM: - crl->algorithm = parse_algorithmIdentifier(object, level, NULL); - break; - case CRL_OBJ_SIGNATURE: - crl->signature = object; - break; - default: - break; } - objectID++; - } - time(&crl->installed); - return TRUE; + success = parser->success(parser); + time(&crl->installed); + +end: + parser->destroy(parser); + return success; } /* Checks if the current certificate is revoked. It goes through the @@ -523,28 +525,28 @@ static cert_status_t check_revocation(const x509crl_t *crl, chunk_t serial , time_t *revocationDate, crl_reason_t * revocationReason) { - revokedCert_t *revokedCert = crl->revokedCertificates; - - *revocationDate = UNDEFINED_TIME; - *revocationReason = REASON_UNSPECIFIED; - - DBG(DBG_CONTROL, - DBG_dump_chunk("serial number:", serial) - ) - - while(revokedCert != NULL) - { - /* compare serial numbers */ - if (revokedCert->userCertificate.len == serial.len && - memcmp(revokedCert->userCertificate.ptr, serial.ptr, serial.len) == 0) + revokedCert_t *revokedCert = crl->revokedCertificates; + + *revocationDate = UNDEFINED_TIME; + *revocationReason = REASON_UNSPECIFIED; + + DBG(DBG_CONTROL, + DBG_dump_chunk("serial number:", serial) + ) + + while(revokedCert != NULL) { - *revocationDate = revokedCert->revocationDate; - *revocationReason = revokedCert->revocationReason; - return CERT_REVOKED; + /* compare serial numbers */ + if (revokedCert->userCertificate.len == serial.len && + memeq(revokedCert->userCertificate.ptr, serial.ptr, serial.len)) + { + *revocationDate = revokedCert->revocationDate; + *revocationReason = revokedCert->revocationReason; + return CERT_REVOKED; + } + revokedCert = revokedCert->next; } - revokedCert = revokedCert->next; - } - return CERT_GOOD; + return CERT_GOOD; } /* @@ -553,37 +555,37 @@ check_revocation(const x509crl_t *crl, chunk_t serial void check_crls(void) { - x509crl_t *crl; + x509crl_t *crl; - lock_crl_list("check_crls"); - crl = x509crls; - - while (crl != NULL) - { - time_t time_left = crl->nextUpdate - time(NULL); - u_char buf[BUF_LEN]; + lock_crl_list("check_crls"); + crl = x509crls; - DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, crl->issuer); - DBG_log("issuer: '%s'",buf); - if (crl->authKeyID.ptr != NULL) - { - datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); - } - DBG_log("%ld seconds left", time_left) - ) - if (time_left < 2*crl_check_interval) + while (crl != NULL) { - fetch_req_t *req = build_crl_fetch_request(crl->issuer - , crl->authKeySerialNumber - , crl->authKeyID, crl->distributionPoints); - add_crl_fetch_request(req); + time_t time_left = crl->nextUpdate - time(NULL); + u_char buf[BUF_LEN]; + + DBG(DBG_CONTROL, + dntoa(buf, BUF_LEN, crl->issuer); + DBG_log("issuer: '%s'",buf); + if (crl->authKeyID.ptr != NULL) + { + datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':' + , buf, BUF_LEN); + DBG_log("authkey: %s", buf); + } + DBG_log("%ld seconds left", time_left) + ) + if (time_left < 2*crl_check_interval) + { + fetch_req_t *req = build_crl_fetch_request(crl->issuer + , crl->authKeySerialNumber + , crl->authKeyID, crl->distributionPoints); + add_crl_fetch_request(req); + } + crl = crl->next; } - crl = crl->next; - } - unlock_crl_list("check_crls"); + unlock_crl_list("check_crls"); } /* @@ -593,118 +595,117 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate , crl_reason_t *revocationReason) { - x509crl_t *crl; - - ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID); + x509crl_t *crl; - generalName_t *crluri = (ca == NULL)? NULL : ca->crluri; + ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber + , cert->authKeyID); - *revocationDate = UNDEFINED_TIME; - *revocationReason = REASON_UNSPECIFIED; + generalName_t *crluri = (ca == NULL)? NULL : ca->crluri; - lock_crl_list("verify_by_crl"); - crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID); + *revocationDate = UNDEFINED_TIME; + *revocationReason = REASON_UNSPECIFIED; - if (crl == NULL) - { - unlock_crl_list("verify_by_crl"); - plog("crl not found"); + lock_crl_list("verify_by_crl"); + crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID); - if (cert->crlDistributionPoints != NULL) + if (crl == NULL) { - fetch_req_t *req = build_crl_fetch_request(cert->issuer - , cert->authKeySerialNumber - , cert->authKeyID, cert->crlDistributionPoints); - add_crl_fetch_request(req); - } + unlock_crl_list("verify_by_crl"); + plog("crl not found"); - if (crluri != NULL) - { - fetch_req_t *req = build_crl_fetch_request(cert->issuer - , cert->authKeySerialNumber - , cert->authKeyID, crluri); - add_crl_fetch_request(req); - } + if (cert->crlDistributionPoints != NULL) + { + fetch_req_t *req = build_crl_fetch_request(cert->issuer + , cert->authKeySerialNumber + , cert->authKeyID, cert->crlDistributionPoints); + add_crl_fetch_request(req); + } - if (cert->crlDistributionPoints != 0 || crluri != NULL) - { - wake_fetch_thread("verify_by_crl"); - return CERT_UNKNOWN; + if (crluri != NULL) + { + fetch_req_t *req = build_crl_fetch_request(cert->issuer + , cert->authKeySerialNumber + , cert->authKeyID, crluri); + add_crl_fetch_request(req); + } + + if (cert->crlDistributionPoints != 0 || crluri != NULL) + { + wake_fetch_thread("verify_by_crl"); + return CERT_UNKNOWN; + } + else + return CERT_UNDEFINED; } else - return CERT_UNDEFINED; - } - else - { - x509cert_t *issuer_cert; - bool valid; - - DBG(DBG_CONTROL, - DBG_log("crl found") - ) - - add_distribution_points(cert->crlDistributionPoints - , &crl->distributionPoints); - - add_distribution_points(crluri - , &crl->distributionPoints); - - lock_authcert_list("verify_by_crl"); - - issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber - , crl->authKeyID, AUTH_CA); - valid = check_signature(crl->tbsCertList, crl->signature - , crl->algorithm, crl->algorithm, issuer_cert); - - unlock_authcert_list("verify_by_crl"); - - if (valid) { - cert_status_t status; + x509cert_t *issuer_cert; + bool valid; - DBG(DBG_CONTROL, - DBG_log("crl signature is valid") - ) - /* return the expiration date */ - *until = crl->nextUpdate; + DBG(DBG_CONTROL, + DBG_log("crl found") + ) - /* has the certificate been revoked? */ - status = check_revocation(crl, cert->serialNumber, revocationDate - , revocationReason); + add_distribution_points(cert->crlDistributionPoints + , &crl->distributionPoints); - if (*until < time(NULL)) - { - fetch_req_t *req; + add_distribution_points(crluri + , &crl->distributionPoints); - plog("crl update is overdue since %s" - , timetoa(until, TRUE)); + lock_authcert_list("verify_by_crl"); - /* try to fetch a crl update */ - req = build_crl_fetch_request(crl->issuer - , crl->authKeySerialNumber - , crl->authKeyID, crl->distributionPoints); - unlock_crl_list("verify_by_crl"); + issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber + , crl->authKeyID, AUTH_CA); + valid = x509_check_signature(crl->tbsCertList, crl->signature, + crl->algorithm, issuer_cert); + + unlock_authcert_list("verify_by_crl"); - add_crl_fetch_request(req); - wake_fetch_thread("verify_by_crl"); - } - else - { - unlock_crl_list("verify_by_crl"); - DBG(DBG_CONTROL, - DBG_log("crl is valid") - ) - } - return status; - } - else - { - unlock_crl_list("verify_by_crl"); - plog("crl signature is invalid"); - return CERT_UNKNOWN; + if (valid) + { + cert_status_t status; + + DBG(DBG_CONTROL, + DBG_log("crl signature is valid") + ) + /* return the expiration date */ + *until = crl->nextUpdate; + + /* has the certificate been revoked? */ + status = check_revocation(crl, cert->serialNumber, revocationDate + , revocationReason); + + if (*until < time(NULL)) + { + fetch_req_t *req; + + plog("crl update is overdue since %T", until, TRUE); + + /* try to fetch a crl update */ + req = build_crl_fetch_request(crl->issuer + , crl->authKeySerialNumber + , crl->authKeyID, crl->distributionPoints); + unlock_crl_list("verify_by_crl"); + + add_crl_fetch_request(req); + wake_fetch_thread("verify_by_crl"); + } + else + { + unlock_crl_list("verify_by_crl"); + DBG(DBG_CONTROL, + DBG_log("crl is valid") + ) + } + return status; + } + else + { + unlock_crl_list("verify_by_crl"); + plog("crl signature is invalid"); + return CERT_UNKNOWN; + } } - } } /* @@ -713,63 +714,63 @@ verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate void list_crls(bool utc, bool strict) { - x509crl_t *crl; + x509crl_t *crl; - lock_crl_list("list_crls"); - crl = x509crls; + lock_crl_list("list_crls"); + crl = x509crls; - if (crl != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 CRLs:"); - whack_log(RC_COMMENT, " "); - } - - while (crl != NULL) - { - u_char buf[BUF_LEN]; - u_int revoked = 0; - revokedCert_t *revokedCert = crl->revokedCertificates; - - /* count number of revoked certificates in CRL */ - while (revokedCert != NULL) - { - revoked++; - revokedCert = revokedCert->next; - } - - whack_log(RC_COMMENT, "%s, revoked certs: %d", - timetoa(&crl->installed, utc), revoked); - dntoa(buf, BUF_LEN, crl->issuer); - whack_log(RC_COMMENT, " issuer: '%s'", buf); - if (crl->crlNumber.ptr != NULL) + if (crl != NULL) { - datatot(crl->crlNumber.ptr, crl->crlNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " crlnumber: %s", buf); + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of X.509 CRLs:"); + whack_log(RC_COMMENT, " "); } - list_distribution_points(crl->distributionPoints); - - whack_log(RC_COMMENT, " updates: this %s", - timetoa(&crl->thisUpdate, utc)); - whack_log(RC_COMMENT, " next %s %s", - timetoa(&crl->nextUpdate, utc), - check_expiry(crl->nextUpdate, CRL_WARNING_INTERVAL, strict)); - if (crl->authKeyID.ptr != NULL) - { - datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); - } - if (crl->authKeySerialNumber.ptr != NULL) + + while (crl != NULL) { - datatot(crl->authKeySerialNumber.ptr, crl->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); - } + u_char buf[BUF_LEN]; + u_int revoked = 0; + revokedCert_t *revokedCert = crl->revokedCertificates; + + /* count number of revoked certificates in CRL */ + while (revokedCert != NULL) + { + revoked++; + revokedCert = revokedCert->next; + } + + whack_log(RC_COMMENT, "%T, revoked certs: %d", + &crl->installed, utc, revoked); + dntoa(buf, BUF_LEN, crl->issuer); + whack_log(RC_COMMENT, " issuer: '%s'", buf); + if (crl->crlNumber.ptr != NULL) + { + datatot(crl->crlNumber.ptr, crl->crlNumber.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " crlnumber: %s", buf); + } + list_distribution_points(crl->distributionPoints); + + whack_log(RC_COMMENT, " updates: this %T", + &crl->thisUpdate, utc); + whack_log(RC_COMMENT, " next %T %s", + &crl->nextUpdate, utc, + check_expiry(crl->nextUpdate, CRL_WARNING_INTERVAL, strict)); + if (crl->authKeyID.ptr != NULL) + { + datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " authkey: %s", buf); + } + if (crl->authKeySerialNumber.ptr != NULL) + { + datatot(crl->authKeySerialNumber.ptr, crl->authKeySerialNumber.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " aserial: %s", buf); + } - crl = crl->next; - } - unlock_crl_list("list_crls"); + crl = crl->next; + } + unlock_crl_list("list_crls"); } diff --git a/src/pluto/crl.h b/src/pluto/crl.h index b5051dcac..7c110ad5a 100644 --- a/src/pluto/crl.h +++ b/src/pluto/crl.h @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: crl.h 3252 2007-10-06 21:24:50Z andreas $ */ #include "constants.h" @@ -22,9 +20,9 @@ typedef struct revokedCert revokedCert_t; struct revokedCert{ revokedCert_t *next; - chunk_t userCertificate; - time_t revocationDate; - crl_reason_t revocationReason; + chunk_t userCertificate; + time_t revocationDate; + crl_reason_t revocationReason; }; /* storage structure for an X.509 CRL */ @@ -33,28 +31,28 @@ typedef struct x509crl x509crl_t; struct x509crl { x509crl_t *next; - time_t installed; + time_t installed; generalName_t *distributionPoints; chunk_t certificateList; chunk_t tbsCertList; u_int version; - /* signature */ + /* signature */ int sigAlg; chunk_t issuer; time_t thisUpdate; time_t nextUpdate; revokedCert_t *revokedCertificates; - /* v2 extensions */ - /* crlExtensions */ - /* extension */ - /* extnID */ - /* critical */ - /* extnValue */ - chunk_t authKeyID; - chunk_t authKeySerialNumber; - chunk_t crlNumber; + /* v2 extensions */ + /* crlExtensions */ + /* extension */ + /* extnID */ + /* critical */ + /* extnValue */ + chunk_t authKeyID; + chunk_t authKeySerialNumber; + chunk_t crlNumber; - /* signatureAlgorithm */ + /* signatureAlgorithm */ int algorithm; chunk_t signature; }; @@ -82,7 +80,7 @@ extern void load_crls(void); extern void check_crls(void); extern bool insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl); extern cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until - , time_t *revocationDate, crl_reason_t *revocationReason); + , 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 index 207192e14..1adccc74e 100644 --- a/src/pluto/crypto.c +++ b/src/pluto/crypto.c @@ -1,6 +1,6 @@ /* crypto interfaces - * Copyright (C) 1998-2001 D. Hugh Redelmeier - * Copyright (C) 2007 Andreas Steffen + * Copyright (C) 1998-2001 D. Hugh Redelmeier + * Copyright (C) 2007-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 @@ -11,617 +11,582 @@ * 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. - * - * RCSID $Id: crypto.c 3252 2007-10-06 21:24:50Z andreas $ */ -#include <stdio.h> -#include <string.h> -#include <stddef.h> -#include <sys/types.h> - #include <freeswan.h> -#define HEADER_DES_LOCL_H /* stupid trick to force prototype decl in <des.h> */ -#include <libdes/des.h> - -#include <errno.h> #include "constants.h" #include "defs.h" -#include "state.h" +#include "crypto.h" #include "log.h" -#include "md5.h" -#include "sha1.h" -#include "crypto.h" /* requires sha1.h and md5.h */ -#include "alg_info.h" -#include "ike_alg.h" - - -/* moduli and generator. */ - -static MP_INT - modp1024_modulus, - modp1536_modulus, - modp2048_modulus, - modp3072_modulus, - modp4096_modulus, - modp6144_modulus, - modp8192_modulus; - -MP_INT groupgenerator; /* MODP group generator (2) */ - -static void do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc); - -static struct encrypt_desc crypto_encryptor_3des = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_3DES_CBC, - algo_next: NULL, - enc_ctxsize: sizeof(des_key_schedule) * 3, - enc_blocksize: DES_CBC_BLOCK_SIZE, - keydeflen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE, - keyminlen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE, - keymaxlen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE, - do_crypt: do_3des, -}; - -/* MD5 hash test vectors - * from RFC 1321 "MD5 Message-Digest Algorithm" - * April 1992, R. Rivest, RSA Data Security - */ - -static const u_char md5_test0_msg[] = { - -}; - -static const u_char md5_test0_msg_digest[] = { - 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, - 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e -}; - -static const u_char md5_test1_msg[] = { - 0x61 -}; - -static const u_char md5_test1_msg_digest[] = { - 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, - 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 -}; - -static const u_char md5_test2_msg[] = { - 0x61, 0x62, 0x63 -}; - -static const u_char md5_test2_msg_digest[] = { - 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, - 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 -}; - -static const u_char md5_test3_msg[] = { - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, - 0x64, 0x69, 0x67, 0x65, 0x73, 0x74 -}; - -static const u_char md5_test3_msg_digest[] = { - 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, - 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 -}; - -static const u_char md5_test4_msg[] = { - 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, - 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, - 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a -}; -static const u_char md5_test4_msg_digest[] = { - 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, - 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b -}; - -static const u_char md5_test5_msg[] = { - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, - 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, - 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, - 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 -}; +static struct encrypt_desc encrypt_desc_3des = +{ + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_3DES_CBC, + algo_next: NULL, -static const u_char md5_test5_msg_digest[] = { - 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, - 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f + 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, }; -static const u_char md5_test6_msg[] = { - 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, - 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, - 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, - 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30 -}; +#define AES_KEY_MIN_LEN 128 +#define AES_KEY_DEF_LEN 128 +#define AES_KEY_MAX_LEN 256 -static const u_char md5_test6_msg_digest[] = { - 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, - 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a -}; - -static const hash_testvector_t md5_hash_testvectors[] = { - { sizeof(md5_test0_msg), md5_test0_msg, md5_test0_msg_digest }, - { sizeof(md5_test1_msg), md5_test1_msg, md5_test1_msg_digest }, - { sizeof(md5_test2_msg), md5_test2_msg, md5_test2_msg_digest }, - { sizeof(md5_test3_msg), md5_test3_msg, md5_test3_msg_digest }, - { sizeof(md5_test4_msg), md5_test4_msg, md5_test4_msg_digest }, - { sizeof(md5_test5_msg), md5_test5_msg, md5_test5_msg_digest }, - { sizeof(md5_test6_msg), md5_test6_msg, md5_test6_msg_digest }, - { 0, NULL, NULL } -}; - -/* MD5 hmac test vectors - * from RFC 2202 "Test Cases for HMAC-MD5 and HMAC-SHA-1" - * September 1997, P. Cheng, IBM & R. Glenn, NIST - */ - -static const u_char md5_hmac1_key[] = { - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b -}; - -static const u_char md5_hmac1_msg[] = { - 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 -}; - -static const u_char md5_hmac1[] = { - 0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c, - 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d -}; - -static const u_char md5_hmac2_key[] = { - 0x4a, 0x65, 0x66, 0x65 -}; - -static const u_char md5_hmac2_msg[] = { - 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, - 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, - 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, - 0x69, 0x6e, 0x67, 0x3f -}; +static struct encrypt_desc encrypt_desc_aes = +{ + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_AES_CBC, + algo_next: NULL, -static const u_char md5_hmac2[] = { - 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, - 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 + enc_blocksize: AES_BLOCK_SIZE, + keyminlen: AES_KEY_MIN_LEN, + keydeflen: AES_KEY_DEF_LEN, + keymaxlen: AES_KEY_MAX_LEN, }; -static const u_char md5_hmac3_key[] = { - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa -}; +#define BLOWFISH_KEY_MIN_LEN 128 +#define BLOWFISH_KEY_MAX_LEN 448 -static const u_char md5_hmac3_msg[] = { - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd -}; +static struct encrypt_desc encrypt_desc_blowfish = +{ + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_BLOWFISH_CBC, + algo_next: NULL, -static const u_char md5_hmac3[] = { - 0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88, - 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6 + enc_blocksize: BLOWFISH_BLOCK_SIZE, + keyminlen: BLOWFISH_KEY_MIN_LEN, + keydeflen: BLOWFISH_KEY_MIN_LEN, + keymaxlen: BLOWFISH_KEY_MAX_LEN, }; -static const u_char md5_hmac4_key[] = { - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19 -}; +#define SERPENT_KEY_MIN_LEN 128 +#define SERPENT_KEY_DEF_LEN 128 +#define SERPENT_KEY_MAX_LEN 256 -static const u_char md5_hmac4_msg[] = { - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd -}; - -static const u_char md5_hmac4[] = { - 0x69, 0x7e, 0xaf, 0x0a, 0xca, 0x3a, 0x3a, 0xea, - 0x3a, 0x75, 0x16, 0x47, 0x46, 0xff, 0xaa, 0x79 -}; +static struct encrypt_desc encrypt_desc_serpent = +{ + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_SERPENT_CBC, + algo_next: NULL, -static const u_char md5_hmac6_key[] = { - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + enc_blocksize: SERPENT_BLOCK_SIZE, + keyminlen: SERPENT_KEY_MIN_LEN, + keydeflen: SERPENT_KEY_DEF_LEN, + keymaxlen: SERPENT_KEY_MAX_LEN, }; -static const u_char md5_hmac6_msg[] = { - 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, - 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, - 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, - 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, - 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, - 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 -}; +#define TWOFISH_KEY_MIN_LEN 128 +#define TWOFISH_KEY_DEF_LEN 128 +#define TWOFISH_KEY_MAX_LEN 256 -static const u_char md5_hmac6[] = { - 0x6b, 0x1a, 0xb7, 0xfe, 0x4b, 0xd7, 0xbf, 0x8f, - 0x0b, 0x62, 0xe6, 0xce, 0x61, 0xb9, 0xd0, 0xcd -}; +static struct encrypt_desc encrypt_desc_twofish = +{ + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_TWOFISH_CBC, + algo_next: NULL, -static const u_char md5_hmac7_msg[] = { - 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, - 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, - 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, - 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x61, 0x6e, - 0x64, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x72, - 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x4f, 0x6e, - 0x65, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, - 0x53, 0x69, 0x7a, 0x65, 0x20, 0x44, 0x61, 0x74, - 0x61 + enc_blocksize: TWOFISH_BLOCK_SIZE, + keydeflen: TWOFISH_KEY_MIN_LEN, + keyminlen: TWOFISH_KEY_DEF_LEN, + keymaxlen: TWOFISH_KEY_MAX_LEN, }; -static const u_char md5_hmac7[] = { - 0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee, - 0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e -}; +static struct encrypt_desc encrypt_desc_twofish_ssh = +{ + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_TWOFISH_CBC_SSH, + algo_next: NULL, -static const hmac_testvector_t md5_hmac_testvectors[] = { - { sizeof(md5_hmac1_key), md5_hmac1_key, sizeof(md5_hmac1_msg), md5_hmac1_msg, md5_hmac1 }, - { sizeof(md5_hmac2_key), md5_hmac2_key, sizeof(md5_hmac2_msg), md5_hmac2_msg, md5_hmac2 }, - { sizeof(md5_hmac3_key), md5_hmac3_key, sizeof(md5_hmac3_msg), md5_hmac3_msg, md5_hmac3 }, - { sizeof(md5_hmac4_key), md5_hmac4_key, sizeof(md5_hmac4_msg), md5_hmac4_msg, md5_hmac4 }, - { sizeof(md5_hmac6_key), md5_hmac6_key, sizeof(md5_hmac6_msg), md5_hmac6_msg, md5_hmac6 }, - { sizeof(md5_hmac6_key), md5_hmac6_key, sizeof(md5_hmac7_msg), md5_hmac7_msg, md5_hmac7 }, - { 0, NULL, 0, NULL, 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 crypto_hasher_md5 = -{ +static struct hash_desc hash_desc_md5 = +{ algo_type: IKE_ALG_HASH, algo_id: OAKLEY_MD5, algo_next: NULL, - hash_ctx_size: sizeof(MD5_CTX), - hash_block_size: MD5_BLOCK_SIZE, - hash_digest_size: MD5_DIGEST_SIZE, - hash_testvectors: md5_hash_testvectors, - hmac_testvectors: md5_hmac_testvectors, - hash_init: (void (*)(void *)) MD5Init, - hash_update: (void (*)(void *, const u_int8_t *, size_t)) MD5Update, - hash_final: (void (*)(u_char *, void *)) MD5Final + hash_digest_size: HASH_SIZE_MD5, }; -/* SHA-1 test vectors - * from "The Secure Hash Algorithm Validation System (SHAVS)" - * July 22, 2004, Lawrence E. Bassham III, NIST - */ - -static const u_char sha1_short2_msg[] = { - 0x5e +static struct hash_desc hash_desc_sha1 = +{ + algo_type: IKE_ALG_HASH, + algo_id: OAKLEY_SHA, + algo_next: NULL, + hash_digest_size: HASH_SIZE_SHA1, }; -static const u_char sha1_short2_msg_digest[] = { - 0x5e, 0x6f, 0x80, 0xa3, 0x4a, 0x97, 0x98, 0xca, - 0xfc, 0x6a, 0x5d, 0xb9, 0x6c, 0xc5, 0x7b, 0xa4, - 0xc4, 0xdb, 0x59, 0xc2 +static struct hash_desc hash_desc_sha2_256 = { + algo_type: IKE_ALG_HASH, + algo_id: OAKLEY_SHA2_256, + algo_next: NULL, + hash_digest_size: HASH_SIZE_SHA256, }; -static const u_char sha1_short4_msg[] = { - 0x9a, 0x7d, 0xfd, 0xf1, 0xec, 0xea, 0xd0, 0x6e, - 0xd6, 0x46, 0xaa, 0x55, 0xfe, 0x75, 0x71, 0x46 +static struct hash_desc hash_desc_sha2_384 = { + algo_type: IKE_ALG_HASH, + algo_id: OAKLEY_SHA2_384, + algo_next: NULL, + hash_digest_size: HASH_SIZE_SHA384, }; -static const u_char sha1_short4_msg_digest[] = { - 0x82, 0xab, 0xff, 0x66, 0x05, 0xdb, 0xe1, 0xc1, - 0x7d, 0xef, 0x12, 0xa3, 0x94, 0xfa, 0x22, 0xa8, - 0x2b, 0x54, 0x4a, 0x35 +static struct hash_desc hash_desc_sha2_512 = { + algo_type: IKE_ALG_HASH, + algo_id: OAKLEY_SHA2_512, + algo_next: NULL, + hash_digest_size: HASH_SIZE_SHA512, }; -static const u_char sha1_long2_msg[] = { - 0xf7, 0x8f, 0x92, 0x14, 0x1b, 0xcd, 0x17, 0x0a, - 0xe8, 0x9b, 0x4f, 0xba, 0x15, 0xa1, 0xd5, 0x9f, - 0x3f, 0xd8, 0x4d, 0x22, 0x3c, 0x92, 0x51, 0xbd, - 0xac, 0xbb, 0xae, 0x61, 0xd0, 0x5e, 0xd1, 0x15, - 0xa0, 0x6a, 0x7c, 0xe1, 0x17, 0xb7, 0xbe, 0xea, - 0xd2, 0x44, 0x21, 0xde, 0xd9, 0xc3, 0x25, 0x92, - 0xbd, 0x57, 0xed, 0xea, 0xe3, 0x9c, 0x39, 0xfa, - 0x1f, 0xe8, 0x94, 0x6a, 0x84, 0xd0, 0xcf, 0x1f, - 0x7b, 0xee, 0xad, 0x17, 0x13, 0xe2, 0xe0, 0x95, - 0x98, 0x97, 0x34, 0x7f, 0x67, 0xc8, 0x0b, 0x04, - 0x00, 0xc2, 0x09, 0x81, 0x5d, 0x6b, 0x10, 0xa6, - 0x83, 0x83, 0x6f, 0xd5, 0x56, 0x2a, 0x56, 0xca, - 0xb1, 0xa2, 0x8e, 0x81, 0xb6, 0x57, 0x66, 0x54, - 0x63, 0x1c, 0xf1, 0x65, 0x66, 0xb8, 0x6e, 0x3b, - 0x33, 0xa1, 0x08, 0xb0, 0x53, 0x07, 0xc0, 0x0a, - 0xff, 0x14, 0xa7, 0x68, 0xed, 0x73, 0x50, 0x60, - 0x6a, 0x0f, 0x85, 0xe6, 0xa9, 0x1d, 0x39, 0x6f, - 0x5b, 0x5c, 0xbe, 0x57, 0x7f, 0x9b, 0x38, 0x80, - 0x7c, 0x7d, 0x52, 0x3d, 0x6d, 0x79, 0x2f, 0x6e, - 0xbc, 0x24, 0xa4, 0xec, 0xf2, 0xb3, 0xa4, 0x27, - 0xcd, 0xbb, 0xfb +const struct dh_desc unset_group = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: MODP_NONE, + algo_next: NULL, + ke_size: 0 }; -static const u_char sha1_long2_msg_digest[] = { - 0xcb, 0x00, 0x82, 0xc8, 0xf1, 0x97, 0xd2, 0x60, - 0x99, 0x1b, 0xa6, 0xa4, 0x60, 0xe7, 0x6e, 0x20, - 0x2b, 0xad, 0x27, 0xb3 +static struct dh_desc dh_desc_modp_1024 = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: MODP_1024_BIT, + algo_next: NULL, + ke_size: 1024 / BITS_PER_BYTE }; -static const hash_testvector_t sha1_hash_testvectors[] = { - { sizeof(sha1_short2_msg), sha1_short2_msg, sha1_short2_msg_digest }, - { sizeof(sha1_short4_msg), sha1_short4_msg, sha1_short4_msg_digest }, - { sizeof(sha1_long2_msg), sha1_long2_msg, sha1_long2_msg_digest }, - { 0, NULL, NULL } +static struct dh_desc dh_desc_modp_1536 = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: MODP_1536_BIT, + algo_next: NULL, + ke_size: 1536 / BITS_PER_BYTE }; -/* SHA-1 hmac test vectors - * from RFC 2202 "Test Cases for HMAC-MD5 and HMAC-SHA-1" - * September 1997, P. Cheng, IBM & R. Glenn, NIST - */ - -static const u_char sha1_hmac1_key[] = { - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b +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 const u_char sha1_hmac1[] = { - 0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, - 0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e, - 0xf1, 0x46, 0xbe, 0x00 +static struct dh_desc dh_desc_modp_3072 = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: MODP_3072_BIT, + algo_next: NULL, + ke_size: 3072 / BITS_PER_BYTE }; -static const u_char sha1_hmac2[] = { - 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2, - 0xd2, 0x74, 0x16, 0xd5, 0xf1, 0x84, 0xdf, 0x9c, - 0x25, 0x9a, 0x7c, 0x79 +static struct dh_desc dh_desc_modp_4096 = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: MODP_4096_BIT, + algo_next: NULL, + ke_size: 4096 / BITS_PER_BYTE }; -static const u_char sha1_hmac3_key[] = { - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa +static struct dh_desc dh_desc_modp_6144 = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: MODP_6144_BIT, + algo_next: NULL, + ke_size: 6144 / BITS_PER_BYTE }; -static const u_char sha1_hmac3[] = { - 0x12, 0x5d, 0x73, 0x42, 0xb9, 0xac, 0x11, 0xcd, - 0x91, 0xa3, 0x9a, 0xf4, 0x8a, 0xa1, 0x7b, 0x4f, - 0x63, 0xf1, 0x75, 0xd3 +static struct dh_desc dh_desc_modp_8192 = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: MODP_8192_BIT, + algo_next: NULL, + ke_size: 8192 / BITS_PER_BYTE }; -static const u_char sha1_hmac4[] = { - 0x4c, 0x90, 0x07, 0xf4, 0x02, 0x62, 0x50, 0xc6, - 0xbc, 0x84, 0x14, 0xf9, 0xbf, 0x50, 0xc8, 0x6c, - 0x2d, 0x72, 0x35, 0xda +static struct dh_desc dh_desc_ecp_256 = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: ECP_256_BIT, + algo_next: NULL, + ke_size: 2*256 / BITS_PER_BYTE }; -static const u_char sha1_hmac6[] = { - 0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e, - 0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55, - 0xed, 0x40, 0x21, 0x12 +static struct dh_desc dh_desc_ecp_384 = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: ECP_384_BIT, + algo_next: NULL, + ke_size: 2*384 / BITS_PER_BYTE }; -static const u_char sha1_hmac7[] = { - 0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, - 0x6d, 0x6b, 0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08, - 0xbb, 0xff, 0x1a, 0x91 +static struct dh_desc dh_desc_ecp_521 = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: ECP_521_BIT, + algo_next: NULL, + ke_size: 2*528 / BITS_PER_BYTE }; -static const hmac_testvector_t sha1_hmac_testvectors[] = { - { sizeof(sha1_hmac1_key), sha1_hmac1_key, sizeof(md5_hmac1_msg), md5_hmac1_msg, sha1_hmac1 }, - { sizeof(md5_hmac2_key), md5_hmac2_key, sizeof(md5_hmac2_msg), md5_hmac2_msg, sha1_hmac2 }, - { sizeof(sha1_hmac3_key), sha1_hmac3_key, sizeof(md5_hmac3_msg), md5_hmac3_msg, sha1_hmac3 }, - { sizeof(md5_hmac4_key), md5_hmac4_key, sizeof(md5_hmac4_msg), md5_hmac4_msg, sha1_hmac4 }, - { sizeof(md5_hmac6_key), md5_hmac6_key, sizeof(md5_hmac6_msg), md5_hmac6_msg, sha1_hmac6 }, - { sizeof(md5_hmac6_key), md5_hmac6_key, sizeof(md5_hmac7_msg), md5_hmac7_msg, sha1_hmac7 }, - { 0, NULL, 0, NULL, NULL } +static struct dh_desc dh_desc_ecp_192 = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: ECP_192_BIT, + algo_next: NULL, + ke_size: 2*192 / BITS_PER_BYTE }; -static struct hash_desc crypto_hasher_sha1 = -{ - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA, - algo_next: NULL, - hash_ctx_size: sizeof(SHA1_CTX), - hash_block_size: SHA1_BLOCK_SIZE, - hash_digest_size: SHA1_DIGEST_SIZE, - hash_testvectors: sha1_hash_testvectors, - hmac_testvectors: sha1_hmac_testvectors, - hash_init: (void (*)(void *)) SHA1Init, - hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update, - hash_final: (void (*)(u_char *, void *)) SHA1Final +static struct dh_desc dh_desc_ecp_224 = { + algo_type: IKE_ALG_DH_GROUP, + algo_id: ECP_224_BIT, + algo_next: NULL, + ke_size: 2*224 / BITS_PER_BYTE }; -void -init_crypto(void) +void init_crypto(void) { - if (mpz_init_set_str(&groupgenerator, MODP_GENERATOR, 10) != 0 - || mpz_init_set_str(&modp1024_modulus, MODP1024_MODULUS, 16) != 0 - || mpz_init_set_str(&modp1536_modulus, MODP1536_MODULUS, 16) != 0 - || mpz_init_set_str(&modp2048_modulus, MODP2048_MODULUS, 16) != 0 - || mpz_init_set_str(&modp3072_modulus, MODP3072_MODULUS, 16) != 0 - || mpz_init_set_str(&modp4096_modulus, MODP4096_MODULUS, 16) != 0 - || mpz_init_set_str(&modp6144_modulus, MODP6144_MODULUS, 16) != 0 - || mpz_init_set_str(&modp8192_modulus, MODP8192_MODULUS, 16) != 0) - exit_log("mpz_init_set_str() failed in init_crypto()"); - - ike_alg_add((struct ike_alg *) &crypto_encryptor_3des); - ike_alg_add((struct ike_alg *) &crypto_hasher_sha1); - ike_alg_add((struct ike_alg *) &crypto_hasher_md5); - ike_alg_init(); - ike_alg_test(); + enumerator_t *enumerator; + encryption_algorithm_t encryption_alg; + hash_algorithm_t hash_alg; + diffie_hellman_group_t dh_group; + bool no_md5 = TRUE; + bool no_sha1 = TRUE; + + enumerator = lib->crypto->create_hasher_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &hash_alg)) + { + 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); + } + enumerator->destroy(enumerator); + + if (no_sha1) + { + exit_log("pluto cannot run without a SHA-1 hasher"); + } + if (no_md5) + { + exit_log("pluto cannot run without an MD5 hasher"); + } + + enumerator = lib->crypto->create_crypter_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &encryption_alg)) + { + 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_TWOFISH_CBC: + desc = &encrypt_desc_twofish; + ike_alg_add((struct ike_alg *)&encrypt_desc_twofish_ssh); + break; + case ENCR_SERPENT_CBC: + desc = &encrypt_desc_serpent; + break; + default: + continue; + } + ike_alg_add((struct ike_alg *)desc); + } + enumerator->destroy(enumerator); + + enumerator = lib->crypto->create_dh_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &dh_group)) + { + 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 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); + } + enumerator->destroy(enumerator); } -/* Oakley group description - * - * See RFC2409 "The Internet key exchange (IKE)" 6. - */ - -const struct oakley_group_desc unset_group = {0, NULL, 0}; /* magic signifier */ - -const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE] = { -# define BYTES(bits) (((bits) + BITS_PER_BYTE - 1) / BITS_PER_BYTE) - { OAKLEY_GROUP_MODP1024, &modp1024_modulus, BYTES(1024) }, - { OAKLEY_GROUP_MODP1536, &modp1536_modulus, BYTES(1536) }, - { OAKLEY_GROUP_MODP2048, &modp2048_modulus, BYTES(2048) }, - { OAKLEY_GROUP_MODP3072, &modp3072_modulus, BYTES(3072) }, - { OAKLEY_GROUP_MODP4096, &modp4096_modulus, BYTES(4096) }, - { OAKLEY_GROUP_MODP6144, &modp6144_modulus, BYTES(6144) }, - { OAKLEY_GROUP_MODP8192, &modp8192_modulus, BYTES(8192) }, -# undef BYTES -}; - -const struct oakley_group_desc * -lookup_group(u_int16_t group) +void free_crypto(void) { - int i; - - for (i = 0; i != elemsof(oakley_group); i++) - if (group == oakley_group[i].group) - return &oakley_group[i]; - return NULL; + /* currently nothing to do */ } -/* Encryption Routines - * - * Each uses and updates the state object's st_new_iv. - * This must already be initialized. +/** + * 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_SERPENT_CBC: + return ENCR_SERPENT_CBC; + case OAKLEY_TWOFISH_CBC: + case OAKLEY_TWOFISH_CBC_SSH: + return ENCR_TWOFISH_CBC; + default: + return ENCR_UNDEFINED; + } +} -/* encrypt or decrypt part of an IKE message using DES - * See RFC 2409 "IKE" Appendix B +/** + * Converts IKEv1 hash algorithm name to hasher name */ -static void __attribute__ ((unused)) -do_des(bool enc, void *buf, size_t buf_len, struct state *st) +hash_algorithm_t oakley_to_hash_algorithm(int alg) { - des_key_schedule ks; - - (void) des_set_key((des_cblock *)st->st_enc_key.ptr, ks); - - passert(st->st_new_iv_len >= DES_CBC_BLOCK_SIZE); - st->st_new_iv_len = DES_CBC_BLOCK_SIZE; /* truncate */ - - des_ncbc_encrypt((des_cblock *)buf, (des_cblock *)buf, buf_len, - ks, - (des_cblock *)st->st_new_iv, enc); + 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; + } } -/* encrypt or decrypt part of an IKE message using 3DES - * See RFC 2409 "IKE" Appendix B +/** + * Converts IKEv1 hash algorithm name to IKEv2 prf name */ -static void -do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc) +pseudo_random_function_t oakley_to_prf(int alg) { - des_key_schedule ks[3]; - - passert (!key_size || (key_size==(DES_CBC_BLOCK_SIZE * 3))) - (void) des_set_key((des_cblock *)key + 0, ks[0]); - (void) des_set_key((des_cblock *)key + 1, ks[1]); - (void) des_set_key((des_cblock *)key + 2, ks[2]); - - des_ede3_cbc_encrypt((des_cblock *)buf, (des_cblock *)buf, buf_len, - ks[0], ks[1], ks[2], - (des_cblock *)iv, enc); + 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; + } } -/* hash and prf routines */ -void -crypto_cbc_encrypt(const struct encrypt_desc *e, bool enc, u_int8_t *buf, size_t size, struct state *st) +/** + * Maps IKEv1 authentication method to IKEv2 signature scheme + */ +signature_scheme_t oakley_to_signature_scheme(int method) { - passert(st->st_new_iv_len >= e->enc_blocksize); - st->st_new_iv_len = e->enc_blocksize; /* truncate */ - - e->do_crypt(buf, size, st->st_enc_key.ptr, st->st_enc_key.len, st->st_new_iv, enc); - /* - e->set_key(&ctx, st->st_enc_key.ptr, st->st_enc_key.len); - e->cbc_crypt(&ctx, buf, size, st->st_new_iv, enc); - */ + 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; + } } -/* HMAC package - * rfc2104.txt specifies how HMAC works. +/** + * Converts IKEv2 encryption to IKEv1 encryption algorithm */ - -void -hmac_init(struct hmac_ctx *ctx, - const struct hash_desc *h, - const u_char *key, size_t key_len) +int oakley_from_encryption_algorithm(encryption_algorithm_t alg) { - int k; - - ctx->h = h; - ctx->hmac_digest_size = h->hash_digest_size; - - /* Prepare the two pads for the HMAC */ - - memset(ctx->buf1, '\0', h->hash_block_size); - - if (key_len <= h->hash_block_size) - { - memcpy(ctx->buf1, key, key_len); - } - else - { - h->hash_init(&ctx->hash_ctx); - h->hash_update(&ctx->hash_ctx, key, key_len); - h->hash_final(ctx->buf1, &ctx->hash_ctx); - } - - memcpy(ctx->buf2, ctx->buf1, h->hash_block_size); - - for (k = 0; k < h->hash_block_size; k++) - { - ctx->buf1[k] ^= HMAC_IPAD; - ctx->buf2[k] ^= HMAC_OPAD; - } - - hmac_reinit(ctx); + switch (alg) + { + case ENCR_DES: + return OAKLEY_DES_CBC; + case ENCR_3DES: + return OAKLEY_3DES_CBC; + case ENCR_RC5: + return OAKLEY_RC5_R16_B64_CBC; + case ENCR_IDEA: + return OAKLEY_IDEA_CBC; + case ENCR_CAST: + return OAKLEY_CAST_CBC; + case ENCR_BLOWFISH: + return OAKLEY_BLOWFISH_CBC; + case ENCR_AES_CBC: + return OAKLEY_AES_CBC; + case ENCR_CAMELLIA_CBC: + return OAKLEY_CAMELLIA_CBC; + case ENCR_SERPENT_CBC: + return OAKLEY_SERPENT_CBC; + case ENCR_TWOFISH_CBC: + return OAKLEY_TWOFISH_CBC; + default: + return 0; + } } -void -hmac_reinit(struct hmac_ctx *ctx) +/** + * Converts IKEv2 integrity to IKEv1 hash algorithm + */ +int oakley_from_integrity_algorithm(integrity_algorithm_t alg) { - ctx->h->hash_init(&ctx->hash_ctx); - ctx->h->hash_update(&ctx->hash_ctx, ctx->buf1, ctx->h->hash_block_size); + switch (alg) + { + case AUTH_HMAC_MD5_96: + return OAKLEY_MD5; + case AUTH_HMAC_SHA1_96: + return OAKLEY_SHA; + case AUTH_HMAC_SHA2_256_128: + return OAKLEY_SHA2_256; + case AUTH_HMAC_SHA2_384_192: + return OAKLEY_SHA2_384; + case AUTH_HMAC_SHA2_512_256: + return OAKLEY_SHA2_512; + default: + return 0; + } } -void -hmac_update(struct hmac_ctx *ctx, - const u_char *data, size_t data_len) +/** + * Converts IKEv2 encryption to IKEv1 ESP encryption algorithm + */ +int esp_from_encryption_algorithm(encryption_algorithm_t alg) { - ctx->h->hash_update(&ctx->hash_ctx, data, data_len); + switch (alg) + { + case ENCR_DES: + return ESP_DES; + case ENCR_3DES: + return ESP_3DES; + case ENCR_RC5: + return ESP_RC5; + case ENCR_IDEA: + return ESP_IDEA; + case ENCR_CAST: + return ESP_CAST; + case ENCR_BLOWFISH: + return ESP_BLOWFISH; + case ENCR_NULL: + return ESP_NULL; + case ENCR_AES_CBC: + return ESP_AES; + case ENCR_AES_CTR: + return ESP_AES_CTR; + case ENCR_AES_CCM_ICV8: + return ESP_AES_CCM_8; + case ENCR_AES_CCM_ICV12: + return ESP_AES_CCM_12; + case ENCR_AES_CCM_ICV16: + return ESP_AES_CCM_16; + case ENCR_AES_GCM_ICV8: + return ESP_AES_GCM_8; + case ENCR_AES_GCM_ICV12: + return ESP_AES_GCM_12; + case ENCR_AES_GCM_ICV16: + return ESP_AES_GCM_16; + case ENCR_CAMELLIA_CBC: + return ESP_CAMELLIA; + case ENCR_SERPENT_CBC: + return ESP_SERPENT; + case ENCR_TWOFISH_CBC: + return ESP_TWOFISH; + default: + return 0; + } } -void -hmac_final(u_char *output, struct hmac_ctx *ctx) +/** + * Converts IKEv2 integrity to IKEv1 ESP authentication algorithm + */ +int esp_from_integrity_algorithm(integrity_algorithm_t alg) { - const struct hash_desc *h = ctx->h; - - h->hash_final(output, &ctx->hash_ctx); - - h->hash_init(&ctx->hash_ctx); - h->hash_update(&ctx->hash_ctx, ctx->buf2, h->hash_block_size); - h->hash_update(&ctx->hash_ctx, output, h->hash_digest_size); - h->hash_final(output, &ctx->hash_ctx); + switch (alg) + { + case AUTH_HMAC_MD5_96: + return AUTH_ALGORITHM_HMAC_MD5; + case AUTH_HMAC_SHA1_96: + return AUTH_ALGORITHM_HMAC_SHA1; + case AUTH_AES_XCBC_96: + return AUTH_ALGORITHM_AES_XCBC_MAC; + case AUTH_HMAC_SHA2_256_128: + return AUTH_ALGORITHM_HMAC_SHA2_256; + case AUTH_HMAC_SHA2_384_192: + return AUTH_ALGORITHM_HMAC_SHA2_384; + case AUTH_HMAC_SHA2_512_256: + return AUTH_ALGORITHM_HMAC_SHA2_512; + default: + return 0; + } } diff --git a/src/pluto/crypto.h b/src/pluto/crypto.h index e773d86df..06c4e1d1a 100644 --- a/src/pluto/crypto.h +++ b/src/pluto/crypto.h @@ -10,31 +10,20 @@ * 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. - * - * RCSID $Id: crypto.h 3252 2007-10-06 21:24:50Z andreas $ */ -#include <gmp.h> /* GNU MP library */ +#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 "libsha2/sha2.h" #include "ike_alg.h" extern void init_crypto(void); +extern void free_crypto(void); -/* Oakley group descriptions */ - -extern MP_INT groupgenerator; /* MODP group generator (2) */ - -struct oakley_group_desc { - u_int16_t group; - MP_INT *modulus; - size_t bytes; -}; - -extern const struct oakley_group_desc unset_group; /* magic signifier */ -extern const struct oakley_group_desc *lookup_group(u_int16_t group); -#define OAKLEY_GROUP_SIZE 7 -extern const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE]; +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. @@ -46,63 +35,23 @@ extern const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE]; #define MAX_OAKLEY_KEY_LEN0 (3 * DES_CBC_BLOCK_SIZE) #define MAX_OAKLEY_KEY_LEN (256/BITS_PER_BYTE) -struct state; /* forward declaration, dammit */ +struct state; /* forward declaration, dammit */ -void crypto_cbc_encrypt(const struct encrypt_desc *e, bool enc, u_int8_t *buf, size_t size, struct state *st); - -#define update_iv(st) memcpy((st)->st_iv, (st)->st_new_iv \ - , (st)->st_iv_len = (st)->st_new_iv_len) +#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); + 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 */ -#ifndef NO_HASH_CTX -union hash_ctx { - MD5_CTX ctx_md5; - SHA1_CTX ctx_sha1; - sha256_context ctx_sha256; - sha512_context ctx_sha512; - }; - -/* HMAC package - * Note that hmac_ctx can be (and is) copied since there are - * no persistent pointers into it. - */ - -struct hmac_ctx { - const struct hash_desc *h; /* underlying hash function */ - size_t hmac_digest_size; /* copy of h->hash_digest_size */ - union hash_ctx hash_ctx; /* ctx for hash function */ - u_char buf1[MAX_HASH_BLOCK_SIZE]; - u_char buf2[MAX_HASH_BLOCK_SIZE]; - }; - -extern void hmac_init( - struct hmac_ctx *ctx, - const struct hash_desc *h, - const u_char *key, - size_t key_len); - -#define hmac_init_chunk(ctx, h, ch) hmac_init((ctx), (h), (ch).ptr, (ch).len) - -extern void hmac_reinit(struct hmac_ctx *ctx); /* saves recreating pads */ - -extern void hmac_update( - struct hmac_ctx *ctx, - const u_char *data, - size_t data_len); - -#define hmac_update_chunk(ctx, ch) hmac_update((ctx), (ch).ptr, (ch).len) - -extern void hmac_final(u_char *output, struct hmac_ctx *ctx); +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); -#define hmac_final_chunk(ch, name, ctx) { \ - pfreeany((ch).ptr); \ - (ch).len = (ctx)->hmac_digest_size; \ - (ch).ptr = alloc_bytes((ch).len, name); \ - hmac_final((ch).ptr, (ctx)); \ - } -#endif diff --git a/src/pluto/db_ops.c b/src/pluto/db_ops.c index 993baf53e..4ba4fa324 100644 --- a/src/pluto/db_ops.c +++ b/src/pluto/db_ops.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: db_ops.c 3252 2007-10-06 21:24:50Z andreas $ */ /* @@ -31,22 +29,22 @@ * 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 - * +---------------------+ + * +---------------------+ + * | 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. */ @@ -69,50 +67,31 @@ #include <assert.h> -#ifndef NO_PLUTO -#else -#define passert(x) assert(x) -extern int debug; /* eg: spi.c */ -#define DBG(cond, action) { if (debug) { action ; } } -#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args); -#define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name) -void * alloc_bytes(size_t size, const char *name) { - void *p=malloc(size); - if (p == NULL) - fprintf(stderr, "unable to malloc %lu bytes for %s", - (unsigned long) size, name); - memset(p, '\0', size); - return p; -} -#define pfreeany(ptr) free(ptr) - -#endif - #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 + * 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; + void *ptr; + int size; }; #endif #ifndef NO_DB_OPS_STATS -/* - * stats: do account for allocations - * displayed in db_ops_show_status() +/* + * 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 */ + 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}" @@ -121,239 +100,233 @@ struct db_ops_stats { 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 * alloc_bytes_st (size_t size, const char *str, struct db_ops_stats *st) +static __inline__ void *malloc_bytes_st(size_t size, struct db_ops_stats *st) { - void *ptr = alloc_bytes(size, str); - if (ptr) { - st->st_curr_cnt++; - st->st_total_cnt++; - if (size > st->st_maxsz) st->st_maxsz=size; - } - return ptr; + 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,s,st) alloc_bytes_st(z, s, &st); -#define PFREE_ST(p,st) do { st.st_curr_cnt--; pfree(p); } while (0); +#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,s,n) alloc_bytes(z, s); -#define PFREE_ST(p,n) pfree(p); +#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 +/* 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) { - int ret=-1; + ctx->trans0 = NULL; + ctx->attrs0 = NULL; - 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_trans > 0) { /* quite silly if not */ - ctx->trans0 = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans, - "db_context->trans", db_trans_st); - if (!ctx->trans0) goto out; - } + 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); + } - if (max_attrs > 0) { /* quite silly if not */ - ctx->attrs0 = ALLOC_BYTES_ST (sizeof (struct db_attr) * max_attrs, - "db_context->attrs", db_attrs_st); - if (!ctx->attrs0) goto out; - } - ret = 0; -out: - if (ret < 0 && ctx->trans0) { - PFREE_ST(ctx->trans0, db_trans_st); - ctx->trans0 = NULL; - } - 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 ret; + 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 */ +/* 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; + 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_context->trans (expand)", 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); + 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; + { + 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; + return ret; } -/* - * Expand storage for attributes by delta_attrs number AND - * rewrite trans->attr pointers +/* + * 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; + 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; - old_attrs = ctx->attrs0; - new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs, - "db_context->attrs (expand)", 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; + } - 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); - /* 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; + 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; + return ret; } -/* Allocate a new db object */ +/* 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", 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; - } + 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; + return ctx; } -/* Free a db object */ +/* 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); + 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 */ +/* 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; + /* 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 */ +/* 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; + /* + * 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(). +/* 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); + 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; + 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 */ /* @@ -362,51 +335,51 @@ db_ops_show_status(void) #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)); + 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); + 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 @@ -415,25 +388,25 @@ 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 */ + 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; + 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 index 4004e710a..464c245dd 100644 --- a/src/pluto/db_ops.h +++ b/src/pluto/db_ops.h @@ -10,47 +10,45 @@ * 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. - * - * RCSID $Id: db_ops.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _DB_OPS_H #define _DB_OPS_H /* - * Main db object, (quite proposal "oriented") + * 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 */ + 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 + * 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 */ +/* 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 */ +/* Free all resourses for this db */ void db_destroy(struct db_context *ctx); -/* Start a new transform */ +/* 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 */ +/* 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 */ +/* 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 */ +/* Get proposal from db object */ static __inline__ struct db_prop *db_prop_get(struct db_context *ctx) { - return &ctx->prop; + return &ctx->prop; } -/* Show stats (allocation, etc) */ +/* 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 index f2c1eab48..f83318e12 100644 --- a/src/pluto/defs.c +++ b/src/pluto/defs.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: defs.c 4632 2008-11-11 18:37:19Z martin $ */ #include <stdlib.h> @@ -27,296 +25,62 @@ #include "constants.h" #include "defs.h" #include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ - -const chunk_t empty_chunk = { NULL, 0 }; +#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; -} - -/* memory allocation - * - * LEAK_DETECTIVE puts a wrapper around each allocation and maintains - * a list of live ones. If a dead one is freed, an assertion MIGHT fail. - * If the live list is currupted, that will often be detected. - * In the end, report_leaks() is called, and the names of remaining - * live allocations are printed. At the moment, it is hoped, not that - * the list is empty, but that there will be no surprises. - * - * Accepted Leaks: - * - "struct iface" and "device name" (for "discovered" net interfaces) - * - "struct event in event_schedule()" (events not associated with states) - * - "Pluto lock name" (one only, needed until end -- why bother?) - */ - -#ifdef LEAK_DETECTIVE - -/* this magic number is 3671129837 decimal (623837458 complemented) */ -#define LEAK_MAGIC 0xDAD0FEEDul - -union mhdr { - struct { - const char *name; - union mhdr *older, *newer; - unsigned long magic; - } i; /* info */ - unsigned long junk; /* force maximal alignment */ -}; - -static union mhdr *allocs = NULL; - -void *alloc_bytes(size_t size, const char *name) -{ - union mhdr *p = malloc(sizeof(union mhdr) + size); - - if (p == NULL) - exit_log("unable to malloc %lu bytes for %s" - , (unsigned long) size, name); - p->i.name = name; - p->i.older = allocs; - if (allocs != NULL) - allocs->i.newer = p; - allocs = p; - p->i.newer = NULL; - p->i.magic = LEAK_MAGIC; - - memset(p+1, '\0', size); - return p+1; -} - -void * -clone_bytes(const void *orig, size_t size, const char *name) -{ - void *p = alloc_bytes(size, name); - - memcpy(p, orig, size); - return p; -} - -void -pfree(void *ptr) -{ - union mhdr *p; - - passert(ptr != NULL); - p = ((union mhdr *)ptr) - 1; - passert(p->i.magic == LEAK_MAGIC); - if (p->i.older != NULL) - { - passert(p->i.older->i.newer == p); - p->i.older->i.newer = p->i.newer; - } - if (p->i.newer == NULL) - { - passert(p == allocs); - allocs = p->i.older; - } - else - { - passert(p->i.newer->i.older == p); - p->i.newer->i.older = p->i.older; - } - p->i.magic = ~LEAK_MAGIC; - free(p); -} - -void -report_leaks(void) -{ - union mhdr - *p = allocs, - *pprev = NULL; - unsigned long n = 0; - - while (p != NULL) - { - passert(p->i.magic == LEAK_MAGIC); - passert(pprev == p->i.newer); - pprev = p; - p = p->i.older; - n++; - if (p == NULL || pprev->i.name != p->i.name) - { - if (n != 1) - plog("leak: %lu * %s", n, pprev->i.name); - else - plog("leak: %s", pprev->i.name); - n = 0; - } - } -} - -#else /* !LEAK_DETECTIVE */ - -void *alloc_bytes(size_t size, const char *name) -{ - void *p = malloc(size); - - if (p == NULL) - exit_log("unable to malloc %lu bytes for %s" - , (unsigned long) size, name); - memset(p, '\0', size); - return p; -} - -void *clone_bytes(const void *orig, size_t size, const char *name) -{ - void *p = malloc(size); + size_t i; - if (p == NULL) - exit_log("unable to malloc %lu bytes for %s" - , (unsigned long) size, name); - memcpy(p, orig, size); - return p; + for (i = 0; i != len; i++) + if (m[i] != '\0') + return FALSE; + return TRUE; } -#endif /* !LEAK_DETECTIVE */ /* 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 +#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 */ + 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 */ + 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 */ -const char* -concatenate_paths(const char *a, const char *b) +char* concatenate_paths(char *a, char *b) { - char *c; + char *c; - if (*b == '/' || *b == '.') - return b; + if (*b == '/' || *b == '.') + return b; - c = temporary_cyclic_buffer(); - snprintf(c, BUF_LEN, "%s/%s", a, b); - return c; + c = temporary_cyclic_buffer(); + snprintf(c, BUF_LEN, "%s/%s", a, b); + return c; } -/* compare two chunks, returns zero if a equals b - * negative/positive if a is earlier/later in the alphabet than b - */ -int -cmp_chunk(chunk_t a, chunk_t b) -{ - int cmp_len, len, cmp_value; - - cmp_len = a.len - b.len; - len = (cmp_len < 0)? a.len : b.len; - cmp_value = memcmp(a.ptr, b.ptr, len); - - return (cmp_value == 0)? cmp_len : cmp_value; -}; - /* 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); - freeanychunk(content); - } -} - -/* - * write the binary contents of a chunk_t to a file - */ -bool -write_chunk(const char *filename, const char *label, chunk_t ch -, mode_t mask, bool force) -{ - mode_t oldmask; - FILE *fd; - size_t written; - - if (!force) - { - fd = fopen(filename, "r"); - if (fd) - { - fclose(fd); - plog(" %s file '%s' already exists", label, filename); - return FALSE; - } - } - - /* set umask */ - oldmask = umask(mask); - - fd = fopen(filename, "w"); - - if (fd) - { - written = fwrite(ch.ptr, sizeof(u_char), ch.len, fd); - fclose(fd); - if (written != ch.len) + if (content.len > 0) { - plog(" writing to %s file '%s' failed", label, filename); - umask(oldmask); - return FALSE; + chunkcpy(*pos, content); + free(content.ptr); } - plog(" written %s file '%s' (%d bytes)", label, filename, (int)ch.len); - umask(oldmask); - return TRUE; - } - else - { - plog(" could not open %s file '%s' for writing", label, filename); - umask(oldmask); - return FALSE; - } -} - -/* Names of the months */ - -static const char* months[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; - - -/* - * Display a date either in local or UTC time - */ -char* -timetoa(const time_t *time, bool utc) -{ - static char buf[TIMETOA_BUF]; - - if (*time == UNDEFINED_TIME) - sprintf(buf, "--- -- --:--:--%s----", (utc)?" UTC ":" "); - else - { - struct tm *t = (utc)? gmtime(time) : localtime(time); - - sprintf(buf, "%s %02d %02d:%02d:%02d%s%04d", - months[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, - (utc)?" UTC ":" ", t->tm_year + 1900 - ); - } - return buf; } /* checks if the expiration date has been reached and @@ -327,44 +91,44 @@ timetoa(const time_t *time, bool utc) const char* check_expiry(time_t expiration_date, int warning_interval, bool strict) { - time_t now; - int time_left; - - if (expiration_date == UNDEFINED_TIME) - return "ok (expires never)"; + time_t now; + int time_left; - /* determine the current time */ - time(&now); + if (expiration_date == UNDEFINED_TIME) + return "ok (expires never)"; - time_left = (expiration_date - now); - if (time_left < 0) - return strict? "fatal (expired)" : "warning (expired)"; + /* determine the current time */ + time(&now); - if (time_left > 86400*warning_interval) - return "ok"; - { - static char buf[35]; /* temporary storage */ - const char* unit = "second"; + time_left = (expiration_date - now); + if (time_left < 0) + return strict? "fatal (expired)" : "warning (expired)"; - if (time_left > 172800) - { - time_left /= 86400; - unit = "day"; - } - else if (time_left > 7200) - { - time_left /= 3600; - unit = "hour"; - } - else if (time_left > 120) + if (time_left > 86400*warning_interval) + return "ok"; { - time_left /= 60; - unit = "minute"; + 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 %d %s%s)", time_left, + unit, (time_left == 1)?"":"s"); + return buf; } - snprintf(buf, 35, "warning (expires in %d %s%s)", time_left, - unit, (time_left == 1)?"":"s"); - return buf; - } } @@ -374,8 +138,8 @@ check_expiry(time_t expiration_date, int warning_interval, bool strict) int file_select(const struct dirent *entry) { - return strcmp(entry->d_name, "." ) && - strcmp(entry->d_name, ".."); + return strcmp(entry->d_name, "." ) && + strcmp(entry->d_name, ".."); } diff --git a/src/pluto/defs.h b/src/pluto/defs.h index 574ce4a1a..8491f4ae8 100644 --- a/src/pluto/defs.h +++ b/src/pluto/defs.h @@ -11,128 +11,77 @@ * 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. - * - * RCSID $Id: defs.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _DEFS_H #define _DEFS_H +#include <string.h> #include <sys/types.h> +#include <chunk.h> + #ifdef KLIPS -# define USED_BY_KLIPS /* ignore */ +# define USED_BY_KLIPS /* ignore */ #else -# define USED_BY_KLIPS UNUSED +# define USED_BY_KLIPS UNUSED #endif #ifdef DEBUG -# define USED_BY_DEBUG /* ignore */ +# define USED_BY_DEBUG /* ignore */ #else -# define USED_BY_DEBUG UNUSED +# define USED_BY_DEBUG UNUSED #endif -/* Length of temporary buffers */ - -#define BUF_LEN 512 - /* 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 */ +#define SOS_NOBODY 0 /* null serial number */ +#define SOS_FIRST 1 /* first normal serial number */ /* memory allocation */ -extern void *alloc_bytes(size_t size, const char *name); -#define alloc_thing(thing, name) (alloc_bytes(sizeof(thing), (name))) +#define clone_thing(orig) clalloc((void *)&(orig), sizeof(orig)) -extern void *clone_bytes(const void *orig, size_t size, const char *name); -#define clone_thing(orig, name) clone_bytes((const void *)&(orig), sizeof(orig), (name)) -#define clone_str(str, name) \ - ((str) == NULL? NULL : clone_bytes((str), strlen((str))+1, (name))) +#define clone_str(str) \ + ((str) == NULL? NULL : strdup(str)) + +#define replace(p, q) \ + { free(p); (p) = (q); } -#ifdef LEAK_DETECTIVE - extern void pfree(void *ptr); - extern void report_leaks(void); -#else -# define pfree(ptr) free(ptr) /* ordinary stdc free */ -#endif -#define pfreeany(p) { if ((p) != NULL) pfree(p); } -#define replace(p, q) { pfreeany(p); (p) = (q); } - - -/* chunk is a simple pointer-and-size abstraction */ - -struct chunk { - u_char *ptr; - size_t len; - }; -typedef struct chunk chunk_t; - -#define setchunk(ch, addr, size) { (ch).ptr = (addr); (ch).len = (size); } -#define strchunk(str) { str, sizeof(str) } -/* NOTE: freeanychunk, unlike pfreeany, NULLs .ptr */ -#define freeanychunk(ch) { pfreeany((ch).ptr); (ch).ptr = NULL; } -#define clonetochunk(ch, addr, size, name) \ - { (ch).ptr = clone_bytes((addr), (ch).len = (size), name); } -#define clonereplacechunk(ch, addr, size, name) \ - { pfreeany((ch).ptr); clonetochunk(ch, addr, size, name); } #define chunkcpy(dst, chunk) \ - { memcpy(dst, chunk.ptr, chunk.len); dst += chunk.len;} -#define same_chunk(a, b) \ - ( (a).len == (b).len && memcmp((a).ptr, (b).ptr, (b).len) == 0 ) + { memcpy(dst, chunk.ptr, chunk.len); dst += chunk.len;} extern char* temporary_cyclic_buffer(void); -extern const char* concatenate_paths(const char *a, const char *b); - -extern const chunk_t empty_chunk; - -/* compare two chunks */ -extern int cmp_chunk(chunk_t a, chunk_t b); +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); -/* write the binary contents of a chunk_t to a file */ -extern bool write_chunk(const char *filename, const char *label, chunk_t ch - ,mode_t mask, bool force); - -/* display a date either in local or UTC time */ -extern char* timetoa(const time_t *time, bool utc); - /* warns a predefined interval before expiry */ extern const char* check_expiry(time_t expiration_date, - int warning_interval, bool strict); + int warning_interval, bool strict); -#define MAX_PROMPT_PASS_TRIALS 5 -#define PROMPT_PASS_LEN 64 +#define MAX_PROMPT_PASS_TRIALS 5 +#define PROMPT_PASS_LEN 64 /* 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; + char secret[PROMPT_PASS_LEN+1]; + bool prompt; + int fd; } prompt_pass_t; -/* no time defined in time_t */ -#define UNDEFINED_TIME 0 - -/* size of timetoa string buffer */ -#define TIMETOA_BUF 30 - /* 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))) diff --git a/src/pluto/demux.c b/src/pluto/demux.c index 04728a4a8..3cfc909af 100644 --- a/src/pluto/demux.c +++ b/src/pluto/demux.c @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: demux.c 3686 2008-03-28 11:48:14Z martin $ */ /* Ordering Constraints on Payloads @@ -110,8 +108,8 @@ #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/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> @@ -119,9 +117,9 @@ #include <sys/queue.h> #if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) -# include <asm/types.h> /* for __u8, __u32 */ +# include <asm/types.h> /* for __u8, __u32 */ # include <linux/errqueue.h> -# include <sys/uio.h> /* struct iovec */ +# include <sys/uio.h> /* struct iovec */ #endif #include <freeswan.h> @@ -132,15 +130,13 @@ #include "connections.h" #include "state.h" #include "packet.h" -#include "md5.h" -#include "sha1.h" -#include "crypto.h" /* requires sha1.h and md5.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 "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 "whack.h" /* requires connections.h */ #include "server.h" #include "nat_traversal.h" #include "vendor.h" @@ -173,14 +169,14 @@ u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE]; */ 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; + 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 */ @@ -190,19 +186,21 @@ struct state_microcode { * 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)) -#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)) +#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_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) @@ -210,14 +208,14 @@ struct state_microcode { #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) +#define SMF_RELEASE_PENDING_P2 LELEM(OAKLEY_AUTH_ROOF + 6) /* end of flags */ -static state_transition_fn /* forward declaration */ - unexpected, - informational; +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). @@ -228,288 +226,288 @@ static state_transition_fn /* forward declaration */ */ static const struct state_microcode - *ike_microcode_index[STATE_IKE_ROOF - STATE_IKE_FLOOR]; + *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 }, + /***** 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_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_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_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 }, + { STATE_MODE_CFG_R4, STATE_UNDEFINED + , SMF_ALL_AUTH | SMF_ENCRYPTED + , LEMPTY, LEMPTY, PT(NONE) + , EVENT_NULL, unexpected }, #undef P #undef PT @@ -518,23 +516,23 @@ static const struct state_microcode state_microcode_table[] = { 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[elemsof(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); - } + /* 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 @@ -586,357 +584,357 @@ init_demux(void) static bool check_msg_errqueue(const struct iface *ifp, short interest) { - struct pollfd pfd; + struct pollfd pfd; - pfd.fd = ifp->fd; - pfd.events = interest | POLLPRI | POLLOUT; + 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 + while (pfd.revents = 0 + , poll(&pfd, 1, -1) > 0 && (pfd.revents & POLLERR)) { - struct sockaddr sa; - struct sockaddr_in sa_in4; - struct sockaddr_in6 sa_in6; - } from; + 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 from_len = sizeof(from); - int packet_len; + int packet_len; - struct msghdr emh; - struct iovec eiov; - union { - /* force alignment (not documented as necessary) */ - struct cmsghdr ecms; + 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; + /* 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; + struct cmsghdr *cm; + char fromstr[sizeof(" for message to port 65536") + INET6_ADDRSTRLEN]; + struct state *sender = NULL; - zero(&from.sa); - from_len = sizeof(from); + 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; + 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); + eiov.iov_base = buffer; /* see readv(2) */ + eiov.iov_len = sizeof(buffer); - packet_len = recvmsg(ifp->fd, &emh, MSG_ERRQUEUE); + 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. - */ + 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); + } - /* ??? 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. + 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. */ - struct sock_extended_err *ee = (void *)CMSG_DATA(cm); - const char *offstr = "unspecified"; - char offstrspace[INET6_ADDRSTRLEN]; - char orname[50]; + passert(emh.msg_name == &from.sa); + DBG_cond_dump(DBG_ALL, "name:\n", emh.msg_name + , emh.msg_namelen); - if (cm->cmsg_len > CMSG_LEN(sizeof(struct sock_extended_err))) + fromstr[0] = '\0'; /* usual case :-( */ + switch (from.sa.sa_family) { - 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)); + 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; - default: - offstr = "unknown"; + 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; - } } - switch (ee->ee_origin) + for (cm = CMSG_FIRSTHDR(&emh) + ; cm != NULL + ; cm = CMSG_NXTHDR(&emh,cm)) { - 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) + 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) + && ((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; + ) { + /* 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); + } } - } - 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; + return (pfd.revents & interest) != 0; } #endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */ bool send_packet(struct state *st, const char *where) { - struct connection *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))) + struct connection *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) { - DBG_log("send_packet(): really too big"); - return FALSE; + 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); } - 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, + else { - 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); + 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); + (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; - } + 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; + 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; + 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 */ @@ -947,54 +945,57 @@ static struct msg_digest *md_pool = NULL; void free_md_pool(void) { - for (;;) - { - struct msg_digest *md = md_pool; + for (;;) + { + struct msg_digest *md = md_pool; - if (md == NULL) - break; - md_pool = md->next; - pfree(md); - } + if (md == NULL) + break; + md_pool = md->next; + free(md); + } } static struct msg_digest * -alloc_md(void) +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; - - if (md == NULL) - md = alloc_thing(struct msg_digest, "msg_digest"); - 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; + struct msg_digest *md = md_pool; + + /* convenient initializer: + * - all pointers NULL + * - .note = NOTHING_WRONG + * - .encrypted = FALSE + */ + static const struct msg_digest blank_md; + + 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) { - freeanychunk(md->raw_packet); - pfreeany(md->packet_pbs.start); - md->packet_pbs.start = NULL; - md->next = md_pool; - md_pool = 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 @@ -1013,35 +1014,35 @@ release_md(struct msg_digest *md) void comm_handle(const struct iface *ifp) { - static struct msg_digest *md; + 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 */ + /* 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 = alloc_md(); - md->iface = ifp; + md = malloc_md(); + md->iface = ifp; - if (read_packet(md)) - process_packet(&md); + if (read_packet(md)) + process_packet(&md); - if (md != NULL) - release_md(md); + if (md != NULL) + release_md(md); - cur_state = NULL; - reset_cur_connection(); - cur_from = NULL; + cur_state = NULL; + reset_cur_connection(); + cur_from = NULL; } /* read the message. @@ -1052,177 +1053,177 @@ comm_handle(const struct iface *ifp) 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 = alloc_bytes(packet_len, "buffer read packet"); - 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) + const struct iface *ifp = md->iface; + int packet_len; + u_int8_t *buffer; + u_int8_t *buffer_nat; + union { - from_ugh = "unexpected Address Family"; + 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)afi->sa_sz) + else if (from_len + < (int) (offsetof(struct sockaddr, sa_family) + sizeof(from.sa.sa_family))) { - from_ugh = "wrong length"; + from_ugh = "truncated"; } 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; - } + 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) + /* now we report any actual I/O error */ + if (packet_len == -1) { - /* 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)"); + 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)); + } + + return FALSE; } 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)); + plog("recvfrom on %s returned misformed source sockaddr: %s" + , ifp->rname, from_ugh); + return FALSE; } + cur_from = &md->sender; + cur_from_port = md->sender_port; - return FALSE; - } - else if (from_ugh != NULL) - { - plog("recvfrom on %s returned misformed source sockaddr: %s" - , ifp->rname, from_ugh); - 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); - return FALSE; - } - memcpy(&non_esp, buffer, sizeof(u_int32_t)); - if (non_esp != 0) + if (ifp->ike_float == TRUE) { - plog("recvfrom %s:%u has no Non-ESP marker" - , ip_str(cur_from), (unsigned) cur_from_port); - return FALSE; + 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); + 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); + 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; } - packet_len -= sizeof(u_int32_t); - buffer_nat = alloc_bytes(packet_len, "buffer read packet"); - memcpy(buffer_nat, buffer + sizeof(u_int32_t), packet_len); - pfree(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))); + /* Clone actual message contents + * and set up md->packet_pbs to describe it. + */ + init_pbs(&md->packet_pbs, buffer, packet_len, "packet"); - 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; - } + 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))); -#define IKEV2_VERSION_OFFSET 17 -#define IKEV2_VERSION 0x20 + 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; + } - /* 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] == IKEV2_VERSION) - { - DBG(DBG_CONTROLMORE, - DBG_log(" ignoring IKEv2 packet") - ) - 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] == IKEV2_VERSION) + { + DBG(DBG_CONTROLMORE, + DBG_log(" ignoring IKEv2 packet") + ) + return FALSE; + } - return TRUE; + return TRUE; } /* process an input packet, possibly generating a reply. @@ -1233,860 +1234,881 @@ read_packet(struct msg_digest *md) 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 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 */ + 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 (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) + if (!in_struct(&md->hdr, &isakmp_hdr_desc, &md->packet_pbs, &md->message_pbs)) { - struct isakmp_hdr *hdr = (struct isakmp_hdr *)md->packet_pbs.cur; - if ((hdr->isa_version >> ISA_MAJ_SHIFT) != ISAKMP_MAJOR_VERSION) - { - SEND_NOTIFICATION(INVALID_MAJOR_VERSION); - return; - } - else if ((hdr->isa_version & ISA_MIN_MASK) != ISAKMP_MINOR_VERSION) - { - SEND_NOTIFICATION(INVALID_MINOR_VERSION); + /* 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(INVALID_MAJOR_VERSION); + return; + } + else if ((hdr->isa_version & ISA_MIN_MASK) != ISAKMP_MINOR_VERSION) + { + SEND_NOTIFICATION(INVALID_MINOR_VERSION); + return; + } + } + SEND_NOTIFICATION(PAYLOAD_MALFORMED); return; - } } - SEND_NOTIFICATION(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); + + 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 + if (pbs_room(&md->packet_pbs) - md->hdr.isa_length == 16) + plog("Cisco VPN client appends 16 surplus NULL bytes"); + else #endif - return; - } + return; + } - switch (md->hdr.isa_xchg) - { + switch (md->hdr.isa_xchg) + { #ifdef NOTYET - case ISAKMP_XCHG_NONE: - case ISAKMP_XCHG_BASE: + 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(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(INVALID_COOKIE); - return; - } + 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(INVALID_MESSAGE_ID); + 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(INVALID_FLAGS); - return; - } + if (is_zero_cookie(md->hdr.isa_icookie)) + { + plog("Initiator Cookie must not be zero in Main Mode message"); + SEND_NOTIFICATION(INVALID_COOKIE); + return; + } - /* don't build a state until the message looks tasty */ - from_state = STATE_MAIN_R0; - } - else - { - /* not an initial message */ + 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(INVALID_FLAGS); + return; + } - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); + /* don't build a state until the message looks tasty */ + from_state = STATE_MAIN_R0; + } + else + { + /* not an initial message */ - 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); + st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie + , &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; + 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; } - } - set_cur_state(st); - from_state = st->st_state; - } - break; + break; #ifdef NOTYET - case ISAKMP_XCHG_AO: - case ISAKMP_XCHG_AGGR: + 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); + 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 (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 (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 (!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 (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 (!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; + 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; + } - 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(INVALID_COOKIE); - 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; - if (is_zero_cookie(md->hdr.isa_rcookie)) - { - plog("Quick Mode message is invalid because" - " it has a Responder Cookie of 0"); - SEND_NOTIFICATION(INVALID_COOKIE); - return; - } + 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; - if (md->hdr.isa_msgid == MAINMODE_MSGID) - { - plog("Quick Mode message is invalid because" - " it has a Message ID of 0"); - SEND_NOTIFICATION(INVALID_MESSAGE_ID); - return; - } + 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(INVALID_COOKIE); + return; + } - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); + if (is_zero_cookie(md->hdr.isa_rcookie)) + { + plog("Quick Mode message is invalid because" + " it has a Responder Cookie of 0"); + SEND_NOTIFICATION(INVALID_COOKIE); + return; + } - 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; - } + if (md->hdr.isa_msgid == MAINMODE_MSGID) + { + plog("Quick Mode message is invalid because" + " it has a Message ID of 0"); + SEND_NOTIFICATION(INVALID_MESSAGE_ID); + return; + } - set_cur_state(st); + st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie + , &md->sender, md->hdr.isa_msgid); - 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(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(INVALID_MESSAGE_ID); - return; - } + 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); - /* Quick Mode Initial IV */ - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; + if (st == NULL) + { + plog("Quick Mode message is for a non-existent (expired?)" + " ISAKMP SA"); + /* XXX Could send notification back */ + return; + } - from_state = STATE_QUICK_R0; - } - else - { - set_cur_state(st); - from_state = st->st_state; - } + set_cur_state(st); - break; + 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(PAYLOAD_MALFORMED /* XXX ? */); + return; + } - 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; - } + /* 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(INVALID_MESSAGE_ID); + 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; - } + /* Quick Mode Initial IV */ + init_phase2_iv(st, &md->hdr.isa_msgid); + new_iv_set = TRUE; - 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; - } + from_state = STATE_QUICK_R0; + } + else + { + set_cur_state(st); + from_state = st->st_state; + } - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); + break; - 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; - } + 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; + } - set_cur_state(st); + st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie + , &md->sender, md->hdr.isa_msgid); - /* 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; + 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 oustanding 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; - } - - 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 oustanding 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: + 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(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; + plog("unsupported exchange type %s in message" + , enum_show(&exchange_names, md->hdr.isa_xchg)); + SEND_NOTIFICATION(UNSUPPORTED_EXCHANGE_TYPE); + return; } - - while (!LHAS(smc->flags, auth)) + + /* 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) { - smc++; - passert(smc->state == from_state); + plog("IKE message has the Commit Flag set but Pluto doesn't implement this feature; ignoring flag"); } - } - - /* 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) - && memcmp(st->st_rpacket.ptr, md->packet_pbs.start, st->st_rpacket.len) == 0) - { - if (smc->flags & SMF_RETRANSMIT_ON_DUPLICATE) + + /* 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) { - 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)); - } + 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); + } } - else + + /* 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_SERIOUS, "discarding duplicate packet; already %s" - , enum_name(&state_names, st->st_state)); + loglog(RC_LOG, "discarding packet received during DNS lookup in %s" + , enum_name(&state_names, st->st_state)); + return; } - 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) + /* 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)) { - plog("discarding encrypted message for an unknown ISAKMP SA"); - SEND_NOTIFICATION(PAYLOAD_MALFORMED /* XXX ? */); - return; + 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 (st->st_skeyid_e.ptr == (u_char *) NULL) + + if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION) { - loglog(RC_LOG_SERIOUS, "discarding encrypted message" - " because we haven't yet negotiated keying materiel"); - SEND_NOTIFICATION(INVALID_FLAGS); - return; - } + DBG(DBG_CRYPT, DBG_log("received encrypted packet from %s:%u" + , ip_str(&md->sender), (unsigned)md->sender_port)); - /* Mark as encrypted */ - md->encrypted = TRUE; + if (st == NULL) + { + plog("discarding encrypted message for an unknown ISAKMP SA"); + SEND_NOTIFICATION(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(INVALID_FLAGS); + return; + } - 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))); + /* Mark as encrypted */ + md->encrypted = TRUE; - /* 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. - */ - { - const struct encrypt_desc *e = st->st_oakley.encrypter; + 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))); - if (pbs_left(&md->message_pbs) % e->enc_blocksize != 0) - { - loglog(RC_LOG_SERIOUS, "malformed message: not a multiple of encryption blocksize"); - SEND_NOTIFICATION(PAYLOAD_MALFORMED); - return; - } - - /* XXX Detect weak keys */ - - /* grab a copy of raw packet (for duplicate packet detection) */ - clonetochunk(md->raw_packet, md->packet_pbs.start - , pbs_room(&md->packet_pbs), "raw packet"); - - /* 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); - } - crypto_cbc_encrypt(e, FALSE, md->message_pbs.cur, - pbs_left(&md->message_pbs) , st); - if (restore_iv) - { - memcpy(st->st_new_iv, new_iv, new_iv_len); - st->st_new_iv_len = new_iv_len; - } - } + /* 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; + 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); + + if (pbs_left(&md->message_pbs) % crypter_block_size != 0) + { + loglog(RC_LOG_SERIOUS, "malformed message: not a multiple of encryption blocksize"); + SEND_NOTIFICATION(PAYLOAD_MALFORMED); + return; + } - DBG_cond_dump(DBG_CRYPT, "decrypted:\n", md->message_pbs.cur - , md->message_pbs.roof - md->message_pbs.cur); + /* XXX Detect weak keys */ - 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? */ + /* 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); - if (smc->flags & SMF_INPUT_ENCRYPTED) - { - loglog(RC_LOG_SERIOUS, "packet rejected: should have been encrypted"); - SEND_NOTIFICATION(INVALID_FLAGS); - return; + 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_block_size; + iv = chunk_create(st->st_new_iv, st->st_new_iv_len); + new_iv = alloca(crypter_block_size); + memcpy(new_iv, data.ptr + data.len - crypter_block_size, + crypter_block_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_block_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); } - } - - /* 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) + else { - struct_desc *sd = np < ISAKMP_NEXT_ROOF? payload_descs[np] : NULL; + /* packet was not encryped -- should it have been? */ - if (pd == &md->digest[PAYLIMIT]) - { - loglog(RC_LOG_SERIOUS, "more than %d payloads in message; ignored", PAYLIMIT); - SEND_NOTIFICATION(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) + if (smc->flags & SMF_INPUT_ENCRYPTED) { - 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(INVALID_PAYLOAD_TYPE); - return; + loglog(RC_LOG_SERIOUS, "packet rejected: should have been encrypted"); + SEND_NOTIFICATION(INVALID_FLAGS); + return; } - } - - { - lset_t s = LELEM(np); + } - if (LDISJOINT(s - , needed | smc->opt_payloads| LELEM(ISAKMP_NEXT_N) | LELEM(ISAKMP_NEXT_D))) + /* 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) { - loglog(RC_LOG_SERIOUS, "%smessage ignored because it " - "contains an unexpected payload type (%s)" - , excuse, enum_show(&payload_names, np)); - SEND_NOTIFICATION(INVALID_PAYLOAD_TYPE); - return; + 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(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(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(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(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 = ""; } - 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(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; + 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))); + 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; + md->message_pbs.roof = md->message_pbs.cur; - /* check that all mandatory payloads appeared */ + /* 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(PAYLOAD_MALFORMED); - return; + 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(PAYLOAD_MALFORMED); + return; + } } - } - /* more sanity checking: enforce most ordering constraints */ + /* 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) + if (IS_PHASE1(from_state)) { - loglog(RC_LOG_SERIOUS, "malformed Phase 1 message: does not start with an SA payload"); - SEND_NOTIFICATION(PAYLOAD_MALFORMED); - return; + /* 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(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) + else if (IS_QUICK(from_state)) { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: does not start with a HASH payload"); - SEND_NOTIFICATION(PAYLOAD_MALFORMED); - return; - } + /* 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." + */ - { - struct payload_digest *p; - int i; + 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(PAYLOAD_MALFORMED); + return; + } - 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(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(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(PAYLOAD_MALFORMED); + return; + } + if (id+1 != id->next) + { + loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:" + " the ID payloads are not adjacent"); + SEND_NOTIFICATION(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." + /* Ignore payloads that we don't handle: + * Delete, Notification, VendorID */ + /* XXX Handle deletions */ + /* XXX Handle Notifications */ + /* XXX Handle VID payloads */ { - struct payload_digest *id = md->chain[ISAKMP_NEXT_ID]; + struct payload_digest *p; - if (id != NULL) - { - if (id->next == NULL || id->next->next != NULL) + for (p = md->chain[ISAKMP_NEXT_N]; p != NULL; p = p->next) { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:" - " if any ID payload is present," - " there must be exactly two"); - SEND_NOTIFICATION(PAYLOAD_MALFORMED); - return; + 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)); } - if (id+1 != id->next) + + for (p = md->chain[ISAKMP_NEXT_D]; p != NULL; p = p->next) { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:" - " the ID payloads are not adjacent"); - SEND_NOTIFICATION(PAYLOAD_MALFORMED); - return; + accept_delete(st, md, p); + DBG_cond_dump(DBG_PARSING, "del:", p->pbs.cur, pbs_left(&p->pbs)); } - } - } - } - - /* 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)); + 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; + 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); + /* 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_state_transition(mdp, smc->processor(md)); } /* complete job started by the state-specific state transition function */ @@ -2094,406 +2116,406 @@ process_packet(struct msg_digest **mdp) 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 */ - - pfreeany(st->st_rpacket.ptr); - - if (md->encrypted) - { - /* if encrypted, duplication already done */ - st->st_rpacket = md->raw_packet; - md->raw_packet.ptr = NULL; - } - else - { - clonetochunk(st->st_rpacket - , md->packet_pbs.start - , pbs_room(&md->packet_pbs), "raw packet"); - } - - /* free previous transmit packet */ - freeanychunk(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 */ - - clonetochunk(st->st_tpacket, md->reply.start - , pbs_offset(&md->reply), "reply packet"); - - 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)); - } + 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; - /* Schedule for whatever timeout is specified */ - { - time_t delay = UNDEFINED_TIME; - enum event_type kind = smc->timeout_event; - bool agreed_time = FALSE; - struct connection *c = st->st_connection; + cur_state = st = md->st; /* might have changed */ - 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. + /* 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. */ - delay = c->sa_ike_life_seconds; - if ((c->policy & POLICY_DONT_REKEY) - || delay >= st->st_oakley.life_seconds) + delete_event(st); + + /* replace previous receive packet with latest */ + + free(st->st_rpacket.ptr); + + if (md->encrypted) { - agreed_time = TRUE; - delay = st->st_oakley.life_seconds; + /* if encrypted, duplication already done */ + st->st_rpacket = md->raw_packet; + md->raw_packet.ptr = NULL; } - } - 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) + else { - agreed_time = TRUE; - delay = st->st_ah.attrs.life_seconds; + st->st_rpacket = chunk_create(md->packet_pbs.start, + pbs_room(&md->packet_pbs)); + st->st_rpacket = chunk_clone(st->st_rpacket); } - if (st->st_esp.present - && delay >= st->st_esp.attrs.life_seconds) + + /* free previous transmit packet */ + chunk_free(&st->st_tpacket); + + /* if requested, send the new reply packet */ + if (smc->flags & SMF_REPLY) { - agreed_time = TRUE; - delay = st->st_esp.attrs.life_seconds; + 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)); } - if (st->st_ipcomp.present - && delay >= st->st_ipcomp.attrs.life_seconds) + + /* Schedule for whatever timeout is specified */ { - agreed_time = TRUE; - delay = st->st_ipcomp.attrs.life_seconds; + time_t delay = UNDEFINED_TIME; + enum event_type kind = smc->timeout_event; + bool agreed_time = FALSE; + struct connection *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); } - } - - /* 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) + /* tell whack and log of progress */ { - delay -= marg; - st->st_margin = marg; + const char *story = state_story[st->st_state - STATE_MAIN_R0]; + 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); } - else + + 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) { - kind = EVENT_SA_EXPIRE; + DBG(DBG_CONTROL, + DBG_log("starting XAUTH server") + ) + xauth_send_request(st); + break; } - } - 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 - STATE_MAIN_R0]; - enum rc_type w = RC_NEW_STATE + st->st_state; - char sadetails[128]; - - sadetails[0]='\0'; + /* 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; + } - 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); - } + /* 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; + } - 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; - } + /* 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; + } - /* 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; - } + /* 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; - } + 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 index 0348b3579..4faf6e532 100644 --- a/src/pluto/demux.h +++ b/src/pluto/demux.h @@ -10,13 +10,11 @@ * 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. - * - * RCSID $Id: demux.h 3252 2007-10-06 21:24:50Z andreas $ */ #include "packet.h" -struct state; /* forward declaration of tag */ +struct state; /* forward declaration of tag */ extern void init_demux(void); extern bool send_packet(struct state *st, const char *where); extern void comm_handle(const struct iface *ifp); @@ -36,9 +34,9 @@ extern u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE]; */ struct payload_digest { - pb_stream pbs; - union payload payload; - struct payload_digest *next; /* of same kind */ + pb_stream pbs; + union payload payload; + struct payload_digest *next; /* of same kind */ }; /* message digest @@ -46,30 +44,30 @@ struct payload_digest { */ 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 */ + 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 */ # define PAYLIMIT 40 - struct payload_digest - digest[PAYLIMIT], - *digest_roof, - *chain[ISAKMP_NEXT_ROOF]; - unsigned short nat_traversal_vid; + struct payload_digest + digest[PAYLIMIT], + *digest_roof, + *chain[ISAKMP_NEXT_ROOF]; + unsigned short nat_traversal_vid; }; extern void release_md(struct msg_digest *md); @@ -79,11 +77,11 @@ extern void release_md(struct msg_digest *md); */ 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_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); diff --git a/src/pluto/dnskey.c b/src/pluto/dnskey.c index 8ba0f7b73..ed901ade5 100644 --- a/src/pluto/dnskey.c +++ b/src/pluto/dnskey.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: dnskey.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdlib.h> @@ -26,32 +24,34 @@ #include <netinet/in.h> #include <arpa/nameser.h> #include <resolv.h> -#include <netdb.h> /* ??? for h_errno */ +#include <netdb.h> /* ??? for h_errno */ #include <sys/queue.h> #include <freeswan.h> -#include <ipsec_policy.h> + +#include <utils/identification.h> +#include <credentials/keys/public_key.h> #include "constants.h" -#include "adns.h" /* needs <resolv.h> */ +#include "adns.h" /* needs <resolv.h> */ #include "defs.h" #include "log.h" #include "id.h" #include "connections.h" -#include "keys.h" /* needs 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 */ +#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 */ +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 */ +const char *pluto_adns_option = NULL; /* path from --pluto_adns */ int adns_restart_count; #define ADNS_RESTART_MAX 20 @@ -59,152 +59,168 @@ int adns_restart_count; void init_adns(void) { - const char *adns_path = pluto_adns_option; + const char *adns_path = pluto_adns_option; #ifndef USE_LWRES - static const char adns_name[] = "_pluto_adns"; - const char *helper_bin_dir = getenv("IPSEC_LIBDIR"); + static const char adns_name[] = "_pluto_adns"; + const char *helper_bin_dir = getenv("IPSEC_LIBDIR"); #else /* USE_LWRES */ - static const char adns_name[] = "lwdnsq"; - const char *helper_bin_dir = getenv("IPSEC_EXECDIR"); + static const char adns_name[] = "lwdnsq"; + const char *helper_bin_dir = getenv("IPSEC_EXECDIR"); #endif /* USE_LWRES */ - 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; + char adns_path_space[4096]; /* plenty long? */ + int qfds[2]; + int afds[2]; - if (helper_bin_dir != NULL) + /* find a pathname to the ADNS program */ + if (adns_path == 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); + /* pathname was not specified as an option: build it. + * First, figure out the directory to be used. + */ + ssize_t n; - while (n > 0 && adns_path_space[n - 1] != '/') - 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()")); + } + } - 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 ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name)) + { + exit_log("path to %s is too long", adns_name); + } - if (pipe(qfds) != 0 || pipe(afds) != 0) - exit_log_errno((e, "pipe(2) failed in init_adns()")); + 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)); + } - adns_pid = fork(); - switch (adns_pid) - { - case -1: - exit_log_errno((e, "fork() failed in init_adns()")); + if (pipe(qfds) != 0 || pipe(afds) != 0) + { + exit_log_errno((e, "pipe(2) failed in init_adns()")); + } - case 0: - /* child */ + adns_pid = fork(); + switch (adns_pid) { - /* 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); + 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]); - } - if (afds[1] != 1) - { - dup2(afds[1], 1); - close(qfds[1]); - } - if (afds[0] > 1) - close(afds[0]); - if (afds[1] > 1) + adns_qfd = qfds[1]; + adns_afd = afds[0]; 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)); + fcntl(adns_qfd, F_SETFD, FD_CLOEXEC); + fcntl(adns_afd, F_SETFD, FD_CLOEXEC); + fcntl(adns_qfd, F_SETFL, O_NONBLOCK); + break; } - - 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); + close_any(adns_qfd); + adns_qfd = NULL_FD; + close_any(adns_afd); + adns_afd = NULL_FD; - if (p == -1) - { - log_errno((e, "waitpid for ADNS process failed")); - } - else if (WIFEXITED(status)) + if (adns_pid != 0) { - 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); + 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; } +#define TRY(x) { err_t ugh = x; if (ugh != NULL) return ugh; } /* Process TXT X-IPsec-Server record, accumulating relevant ones @@ -225,246 +241,270 @@ static const char our_TXT_attr[] = our_TXT_attr_string; static err_t decode_iii(u_char **pp, struct id *gw_id) { - u_char *p = *pp + strspn(*pp, " \t"); - u_char *e = p + strcspn(p, " \t"); - u_char under = *e; - - if (p == e) - return "TXT " our_TXT_attr_string " badly formed (no gateway specified)"; - - *e = '\0'; - if (*p == '@') - { - /* gateway specification in this record is @FQDN */ - err_t ugh = atoid(p, gw_id, FALSE); - - if (ugh != NULL) - return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s" - , ugh); - } - else - { - /* gateway specification is numeric */ - ip_address ip; - err_t ugh = tnatoaddr(p, e-p - , strchr(p, ':') == NULL? AF_INET : AF_INET6 - , &ip); - - if (ugh != NULL) - return builddiag("malformed IP address in TXT " our_TXT_attr_string ": %s" - , ugh); - - if (isanyaddr(&ip)) - return "gateway address must not be 0.0.0.0 or 0::0"; - - iptoid(&ip, gw_id); - } - - *e = under; - *pp = e + strspn(e, " \t"); - - return NULL; + u_char *p = *pp + strspn(*pp, " \t"); + u_char *e = p + strcspn(p, " \t"); + u_char under = *e; + + if (p == e) + { + return "TXT " our_TXT_attr_string " badly formed (no gateway specified)"; + } + *e = '\0'; + if (*p == '@') + { + /* gateway specification in this record is @FQDN */ + err_t ugh = atoid(p, gw_id, FALSE); + + if (ugh != NULL) + { + return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s" + , ugh); + } + } + else + { + /* gateway specification is numeric */ + ip_address ip; + err_t ugh = tnatoaddr(p, e-p + , strchr(p, ':') == NULL? AF_INET : AF_INET6 + , &ip); + + if (ugh != NULL) + { + return builddiag("malformed IP address in TXT " our_TXT_attr_string ": %s" + , ugh); + } + if (isanyaddr(&ip)) + { + return "gateway address must not be 0.0.0.0 or 0::0"; + } + iptoid(&ip, gw_id); + } + + *e = under; + *pp = e + strspn(e, " \t"); + + return NULL; } static err_t process_txt_rr_body(u_char *str -, bool doit /* should we capture information? */ +, bool doit /* should we capture information? */ , enum dns_auth_level dns_auth_level , struct adns_continuation *const cr) { - const struct id *client_id = &cr->id; /* subject of query */ - u_char *p = str; - unsigned long pref = 0; - struct gw_info gi; + const struct id *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 */ - 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 */ + } - /* 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 */ - 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 '('"; + } - /* decode '(' nnn ')' */ - if (*p != '(') - return "X-IPsec-Server missing '('"; + { + char *e; - { - char *e; + p++; + pref = strtoul(p, &e, 0); + if ((u_char *)e == p) + { + return "malformed X-IPsec-Server priority"; + } + p = e + strspn(e, " \t"); - p++; - pref = strtoul(p, &e, 0); - if ((u_char *)e == p) - return "malformed X-IPsec-Server priority"; + if (*p != ')') + { + return "X-IPsec-Server priority missing ')'"; + } + p++; + p += strspn(p, " \t"); - p = e + strspn(e, " \t"); + if (pref > 0xFFFF) + { + return "X-IPsec-Server priority larger than 0xFFFF"; + } + } - if (*p != ')') - return "X-IPsec-Server priority missing ')'"; + /* time for '=' */ + 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 '=' */ + /* Decode iii (Security Gateway ID). */ - if (*p != '=') - return "X-IPsec-Server priority missing '='"; + zero(&gi); /* before first use */ - p++; - p += strspn(p, " \t"); + TRY(decode_iii(&p, &gi.gw_id)); /* will need to unshare_id_content */ - /* Decode iii (Security Gateway ID). */ - - zero(&gi); /* before first use */ - - TRY(decode_iii(&p, &gi.gw_id)); /* will need to unshare_id_content */ - - 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 (!id_is_ipaddr(&gi.gw_id)) + if (!cr->sgw_specified) { - DBG(DBG_DNS, + /* 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 (!id_is_ipaddr(&gi.gw_id)) { - char cidb[BUF_LEN]; - char gwidb[BUF_LEN]; - - idtoa(client_id, cidb, sizeof(cidb)); - idtoa(&gi.gw_id, gwidb, sizeof(gwidb)); - DBG_log("TXT %s record for %s: security gateway %s;" - " ignored because gateway's IP is unspecified" - , our_TXT_attr, cidb, gwidb); - }); - return NULL; /* we cannot use this record, but it isn't wrong */ + DBG(DBG_DNS, + { + char cidb[BUF_LEN]; + char gwidb[BUF_LEN]; + + idtoa(client_id, cidb, sizeof(cidb)); + idtoa(&gi.gw_id, gwidb, sizeof(gwidb)); + DBG_log("TXT %s record for %s: security gateway %s;" + " ignored because gateway's IP is unspecified" + , our_TXT_attr, cidb, gwidb); + }); + 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. - */ - const struct id *peer_id = &cr->sgw_id; - - if (!same_id(peer_id, &gi.gw_id)) + else { - DBG(DBG_DNS, + /* We do know the peer's ID (because we are responding) + * So we're looking for gateway specs specifying this known ID. + */ + const struct id *peer_id = &cr->sgw_id; + + if (!same_id(peer_id, &gi.gw_id)) { - char cidb[BUF_LEN]; - char gwidb[BUF_LEN]; - char pidb[BUF_LEN]; - - idtoa(client_id, cidb, sizeof(cidb)); - idtoa(&gi.gw_id, gwidb, sizeof(gwidb)); - idtoa(peer_id, pidb, sizeof(pidb)); - DBG_log("TXT %s record for %s: security gateway %s;" - " ignored -- looking to confirm %s as gateway" - , our_TXT_attr, cidb, gwidb, pidb); - }); - return NULL; /* we cannot use this record, but it isn't wrong */ + DBG(DBG_DNS, + { + char cidb[BUF_LEN]; + char gwidb[BUF_LEN]; + char pidb[BUF_LEN]; + + idtoa(client_id, cidb, sizeof(cidb)); + idtoa(&gi.gw_id, gwidb, sizeof(gwidb)); + idtoa(peer_id, pidb, sizeof(pidb)); + DBG_log("TXT %s record for %s: security gateway %s;" + " ignored -- looking to confirm %s as gateway" + , our_TXT_attr, cidb, gwidb, pidb); + }); + 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) + if (doit) { - /* Decode base 64 encoding of key. - * Similar code is in process_lwdnsq_key. - */ - u_char kb[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */ - chunk_t kbc; - struct RSA_public_key r; - - err_t ugh = ttodatav(p, 0, 64, kb, sizeof(kb), &kbc.len - , diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); - - if (ugh != NULL) - return builddiag("malformed key data: %s", ugh); - - if (kbc.len > sizeof(kb)) - return builddiag("key data larger than %lu bytes" - , (unsigned long) sizeof(kb)); - - kbc.ptr = kb; - ugh = unpack_RSA_public_key(&r, &kbc); - if (ugh != NULL) - return builddiag("invalid key data: %s", ugh); - - /* now find a key entry to put it in */ - gi.key = public_key_from_rsa(&r); - - free_RSA_public_content(&r); + /* really accept gateway */ + struct gw_info **gwip; /* gateway insertion point */ - 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) - ; + gi.client_id = *client_id; /* will need to unshare_id_content */ - DBG(DBG_DNS, - { - char cidb[BUF_LEN]; - char gwidb[BUF_LEN]; + /* decode optional kkk: base 64 encoding of key */ - idtoa(client_id, cidb, sizeof(cidb)); - idtoa(&gi.gw_id, gwidb, sizeof(gwidb)); + gi.gw_key_present = *p != '\0'; if (gi.gw_key_present) { - DBG_log("gateway for %s is %s with key %s" - , cidb, gwidb, gi.key->u.rsa.keyid); + /* 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_RFC_3110, 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); } - else - { - DBG_log("gateway for %s is %s; no key specified" - , cidb, gwidb); - } - }); - gi.next = *gwip; - *gwip = clone_thing(gi, "gateway info"); - unshare_id_content(&(*gwip)->gw_id); - unshare_id_content(&(*gwip)->client_id); - } + /* 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, + { + char cidb[BUF_LEN]; + char gwidb[BUF_LEN]; + identification_t *keyid; + public_key_t *pub_key; + + idtoa(client_id, cidb, sizeof(cidb)); + idtoa(&gi.gw_id, gwidb, sizeof(gwidb)); + pub_key = gi.key->public_key; + keyid = pub_key->get_id(pub_key, ID_PUBKEY_SHA1); + + if (gi.gw_key_present) + { + DBG_log("gateway for %s is %s with key %Y" + , cidb, gwidb, keyid); + } + else + { + DBG_log("gateway for %s is %s; no key specified" + , cidb, gwidb); + } + }); + + gi.next = *gwip; + *gwip = clone_thing(gi); + unshare_id_content(&(*gwip)->gw_id); + unshare_id_content(&(*gwip)->client_id); + } - return NULL; + return NULL; } static const char * rr_typename(int type) { - switch (type) - { - case T_TXT: - return "TXT"; - case T_KEY: - return "KEY"; - default: - return "???"; - } + switch (type) + { + case T_TXT: + return "TXT"; + case T_KEY: + return "KEY"; + default: + return "???"; + } } @@ -476,72 +516,72 @@ process_lwdnsq_key(u_char *str , enum dns_auth_level dns_auth_level , struct adns_continuation *const cr) { - /* fields of KEY record. See RFC 2535 3.1 KEY RDATA format. */ - unsigned long flags /* 16 bits */ - , protocol /* 8 bits */ - , algorithm; /* 8 bits */ - - char *rest = str - , *p - , *endofnumber; - - /* flags */ - p = strsep(&rest, " \t"); - if (p == NULL) - return "lwdnsq KEY: missing flags"; - - flags = strtoul(p, &endofnumber, 10); - if (*endofnumber != '\0') - return "lwdnsq KEY: malformed flags"; - - /* protocol */ - p = strsep(&rest, " \t"); - if (p == NULL) - return "lwdnsq KEY: missing protocol"; - - protocol = strtoul(p, &endofnumber, 10); - if (*endofnumber != '\0') - return "lwdnsq KEY: malformed protocol"; - - /* algorithm */ - p = strsep(&rest, " \t"); - if (p == NULL) - return "lwdnsq KEY: missing algorithm"; - - algorithm = strtoul(p, &endofnumber, 10); - if (*endofnumber != '\0') - return "lwdnsq KEY: malformed algorithm"; - - /* is this key interesting? */ - if (protocol == 4 /* IPSEC (RFC 2535 3.1.3) */ - && algorithm == 1 /* RSA/MD5 (RFC 2535 3.2) */ - && (flags & 0x8000ul) == 0 /* use for authentication (3.1.2) */ - && (flags & 0x2CF0ul) == 0) /* must be zero */ - { - /* Decode base 64 encoding of key. - * Similar code is in process_txt_rr_body. - */ - u_char kb[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */ - chunk_t kbc; - err_t ugh = ttodatav(rest, 0, 64, kb, sizeof(kb), &kbc.len - , diag_space, sizeof(diag_space), TTODATAV_IGNORESPACE); - - if (ugh != NULL) - return builddiag("malformed key data: %s", ugh); - - if (kbc.len > sizeof(kb)) - return builddiag("key data larger than %lu bytes" - , (unsigned long) sizeof(kb)); - - kbc.ptr = kb; - TRY(add_public_key(&cr->id, dns_auth_level, PUBKEY_ALG_RSA, &kbc - , &cr->keys_from_dns)); - - /* keep a reference to last one */ - unreference_key(&cr->last_info); - cr->last_info = reference_key(cr->keys_from_dns->key); - } - return NULL; + /* fields of KEY record. See RFC 2535 3.1 KEY RDATA format. */ + unsigned long flags /* 16 bits */ + , protocol /* 8 bits */ + , algorithm; /* 8 bits */ + + char *rest = str + , *p + , *endofnumber; + + /* flags */ + p = strsep(&rest, " \t"); + if (p == NULL) + return "lwdnsq KEY: missing flags"; + + flags = strtoul(p, &endofnumber, 10); + if (*endofnumber != '\0') + return "lwdnsq KEY: malformed flags"; + + /* protocol */ + p = strsep(&rest, " \t"); + if (p == NULL) + return "lwdnsq KEY: missing protocol"; + + protocol = strtoul(p, &endofnumber, 10); + if (*endofnumber != '\0') + return "lwdnsq KEY: malformed protocol"; + + /* algorithm */ + p = strsep(&rest, " \t"); + if (p == NULL) + return "lwdnsq KEY: missing algorithm"; + + algorithm = strtoul(p, &endofnumber, 10); + if (*endofnumber != '\0') + return "lwdnsq KEY: malformed algorithm"; + + /* is this key interesting? */ + if (protocol == 4 /* IPSEC (RFC 2535 3.1.3) */ + && algorithm == 1 /* RSA/MD5 (RFC 2535 3.2) */ + && (flags & 0x8000ul) == 0 /* use for authentication (3.1.2) */ + && (flags & 0x2CF0ul) == 0) /* must be zero */ + { + /* Decode base 64 encoding of key. + * Similar code is in process_txt_rr_body. + */ + u_char kb[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */ + chunk_t kbc; + err_t ugh = ttodatav(rest, 0, 64, kb, sizeof(kb), &kbc.len + , diag_space, sizeof(diag_space), TTODATAV_IGNORESPACE); + + if (ugh != NULL) + return builddiag("malformed key data: %s", ugh); + + if (kbc.len > sizeof(kb)) + return builddiag("key data larger than %lu bytes" + , (unsigned long) sizeof(kb)); + + kbc.ptr = kb; + TRY(add_public_key(&cr->id, dns_auth_level, PUBKEY_ALG_RSA, &kbc + , &cr->keys_from_dns)); + + /* keep a reference to last one */ + unreference_key(&cr->last_info); + cr->last_info = reference_key(cr->keys_from_dns->key); + } + return NULL; } # endif /* USE_KEYRR */ @@ -580,158 +620,158 @@ process_lwdnsq_key(u_char *str * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ struct qr_header { - u_int16_t id; /* 16-bit identifier to match query */ + u_int16_t id; /* 16-bit identifier to match query */ - u_int16_t stuff; /* packed crud: */ + u_int16_t stuff; /* packed crud: */ -#define QRS_QR 0x8000 /* QR: on if this is a response */ +#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_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_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 +#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 */ + 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 } + { 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) + "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 */ - }; + 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; + u_char name_buf[NS_MAXDNAME + 2]; + u_char *ip = pbs->cur; + unsigned oi = 0; + unsigned jump_count = 0; - 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) + for (;;) { - case 0x00: - /* we grab the next b characters */ - if (oi + b > NS_MAXDNAME) - return "domain name too long"; + u_int8_t b; - if (pbs->roof - ip <= b) - return "domain name falls off end of message"; + if (ip >= pbs->roof) + return "ran out of message while skipping domain name"; - if (oi != 0) - name_buf[oi++] = '.'; - - memcpy(name_buf + oi, ip, b); - oi += b; - ip += b; + b = *ip++; 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"; + if (b == 0) + break; - /* 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; + 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"; } - break; - - default: - return "invalid code in label"; } - } - name_buf[oi++] = '\0'; + name_buf[oi++] = '\0'; - DBG(DBG_DNS, DBG_log("skipping name %s", name_buf)); + DBG(DBG_DNS, DBG_log("skipping name %s", name_buf)); - return NULL; + return NULL; } static err_t eat_name_helpfully(pb_stream *pbs, const char *context) { - err_t ugh = eat_name(pbs); + err_t ugh = eat_name(pbs); - return ugh == NULL? ugh - : builddiag("malformed name within DNS record of %s: %s", context, ugh); + 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: @@ -749,20 +789,20 @@ eat_name_helpfully(pb_stream *pbs, const char *context) */ struct qs_fixed { - u_int16_t qtype; - u_int16_t qclass; + 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 } + { 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) + "Question Section entry fixed part", + qs_fixed_fields, + sizeof(struct qs_fixed) }; /* 4.1.3. Resource record format: @@ -789,26 +829,26 @@ static struct_desc qs_fixed_desc = { */ struct rr_fixed { - u_int16_t type; - u_int16_t class; - u_int32_t ttl; /* actually signed */ - u_int16_t rdlength; + 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 } + { 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) + "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. @@ -830,22 +870,22 @@ static struct_desc rr_fixed_desc = { */ struct key_rdata { - u_int16_t flags; - u_int8_t protocol; - u_int8_t algorithm; + 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 } + { 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) + "KEY RR RData fixed part", + key_rdata_fields, + sizeof(struct key_rdata) }; /* RFC 2535 4.1 SIG RDATA format: @@ -872,30 +912,30 @@ static struct_desc key_rdata_desc = { */ 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; + 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 } + { 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) + "SIG RR RData fixed part", + sig_rdata_fields, + sizeof(struct sig_rdata) }; /* handle a KEY Resource Record. */ @@ -903,38 +943,37 @@ static struct_desc sig_rdata_desc = { #ifdef USE_KEYRR static err_t process_key_rr(u_char *ptr, size_t len -, bool doit /* should we capture information? */ +, 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"; + pb_stream pbs; + struct key_rdata kr; - init_pbs(&pbs, ptr, len, "KEY RR"); + if (len < sizeof(struct key_rdata)) + return "KEY Resource Record's RD Length is too small"; - if (!in_struct(&kr, &key_rdata_desc, &pbs, NULL)) - return "failed to get fixed part of KEY Resource Record RDATA"; + init_pbs(&pbs, ptr, len, "KEY RR"); - 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 (!in_struct(&kr, &key_rdata_desc, &pbs, NULL)) + return "failed to get fixed part of KEY Resource Record RDATA"; - if (doit) + 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 */ { - chunk_t k; + /* we have what seems to be a tasty key */ + + if (doit) + { + chunk_t k = { pbs.cur, pbs_left(&pbs) }; - setchunk(k, pbs.cur, pbs_left(&pbs)); - TRY(add_public_key(&cr->id, dns_auth_level, PUBKEY_ALG_RSA, &k - , &cr->keys_from_dns)); + TRY(add_public_key(&cr->id, dns_auth_level, PUBKEY_ALG_RSA, &k + , &cr->keys_from_dns)); + } } - } - return NULL; + return NULL; } #endif /* USE_KEYRR */ @@ -946,130 +985,130 @@ process_key_rr(u_char *ptr, size_t len 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; + size_t i = 0 + , o = 0; - while (i < slen) - { - size_t cl = s[i++]; + while (i < slen) + { + size_t cl = s[i++]; - if (i + cl > slen) - return "TXT rr RDATA representation malformed"; + if (i + cl > slen) + return "TXT rr RDATA representation malformed"; - if (o + cl >= dlen) - return "TXT rr RDATA too large"; + 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"; + 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; + return NULL; } static err_t process_txt_rr(u_char *rdata, size_t rdlen -, bool doit /* should we capture information? */ +, 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 */ + 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); + 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? */ +, bool doit /* should we capture information? */ , enum dns_auth_level *dns_auth_level -, u_int16_t ancount /* number of RRs in the answer section */ +, 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; + const int type = cr->query.type; /* type of RR of interest */ + unsigned c; - DBG(DBG_DNS, DBG_log("*Answer Section:")); + DBG(DBG_DNS, DBG_log("*Answer Section:")); - for (c = 0; c != ancount; c++) - { - struct rr_fixed rrf; - size_t tail; + for (c = 0; c != ancount; c++) + { + struct rr_fixed rrf; + size_t tail; - /* ??? do we need to match the name? */ + /* ??? do we need to match the name? */ - TRY(eat_name_helpfully(pbs, "Answer Section")); + 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 (!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"; + if (rrf.rdlength > pbs_left(pbs)) + return "RD Length extends beyond end of message"; - /* ??? should we care about ttl? */ + /* ??? should we care about ttl? */ - tail = rrf.rdlength; + tail = rrf.rdlength; - if (rrf.type == type && rrf.class == C_IN) - { - err_t ugh = NULL; + if (rrf.type == type && rrf.class == C_IN) + { + err_t ugh = NULL; - switch (type) - { + switch (type) + { #ifdef USE_KEYRR - case T_KEY: - ugh = process_key_rr(pbs->cur, tail, doit, *dns_auth_level, cr); - break; + 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; + 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; } - break; - default: - ugh = builddiag("unexpected RR type %d", type); - break; - } - if (ugh != NULL) - return ugh; + in_raw(NULL, tail, pbs, "RR RDATA"); } - in_raw(NULL, tail, pbs, "RR RDATA"); - } - return doit - && cr->gateways_from_dns == NULL + return doit + && cr->gateways_from_dns == NULL #ifdef USE_KEYRR - && cr->keys_from_dns == NULL + && cr->keys_from_dns == NULL #endif /* USE_KEYRR */ - ? builddiag("no suitable %s record found in DNS", rr_typename(type)) - : NULL; + ? builddiag("no suitable %s record found in DNS", rr_typename(type)) + : NULL; } /* process DNS answer -- TXT or KEY query */ @@ -1078,153 +1117,153 @@ 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; + 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"); + init_pbs(&pbs, ans, anslen, "Query Response Message"); - /* decode and check header */ + /* decode and check header */ - if (!in_struct(&qr_header, &qr_header_desc, &pbs, NULL)) - return "malformed header"; + if (!in_struct(&qr_header, &qr_header_desc, &pbs, NULL)) + return "malformed header"; - /* ID: nothing to do with us */ + /* ID: nothing to do with us */ - /* stuff -- lots of things */ - if ((qr_header.stuff & QRS_QR) == 0) - return "not a response?!?"; + /* 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"; + if (((qr_header.stuff >> QRS_OPCODE_SHIFT) & QRS_OPCODE_MASK) != QRSO_QUERY) + return "unexpected opcode"; - /* I don't think we care about AA */ + /* I don't think we care about AA */ - if (qr_header.stuff & QRS_TC) - return "response truncated"; + if (qr_header.stuff & QRS_TC) + return "response truncated"; - /* I don't think we care about RD, RA, or CD */ + /* 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; + /* 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"; + 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)elemsof(rcode_text)? rcode_text[r] : "unknown rcode"; + 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)); + if (qr_header.ancount == 0) + return builddiag("no %s RR found by DNS", rr_typename(type)); - /* end of header checking */ + /* end of header checking */ - /* Question Section processing */ + /* 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 | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ + /* 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:")); + DBG(DBG_DNS, DBG_log("*Question Section:")); - for (c = 0; c != qr_header.qdcount; c++) - { - struct qs_fixed qsf; + for (c = 0; c != qr_header.qdcount; c++) + { + struct qs_fixed qsf; - TRY(eat_name_helpfully(&pbs, "Question Section")); + 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 (!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.qtype != type) + return "unexpected QTYPE in Question Section"; - if (qsf.qclass != C_IN) - return "unexpected QCLASS in Question Section"; - } + if (qsf.qclass != C_IN) + return "unexpected QCLASS in Question Section"; + } - /* rest of sections are made up of Resource Records */ + /* rest of sections are made up of Resource Records */ - /* Answer Section processing -- error checking, noting T_SIG */ + /* Answer Section processing -- error checking, noting T_SIG */ - ans_start = pbs.cur; /* remember start of answer section */ + ans_start = pbs.cur; /* remember start of answer section */ - TRY(process_answer_section(&pbs, FALSE, &dns_auth_level - , qr_header.ancount, cr)); + TRY(process_answer_section(&pbs, FALSE, &dns_auth_level + , qr_header.ancount, cr)); - /* Authority Section processing (just sanity checking) */ + /* Authority Section processing (just sanity checking) */ - DBG(DBG_DNS, DBG_log("*Authority Section:")); + DBG(DBG_DNS, DBG_log("*Authority Section:")); - for (c = 0; c != qr_header.nscount; c++) - { - struct rr_fixed rrf; - size_t tail; + for (c = 0; c != qr_header.nscount; c++) + { + struct rr_fixed rrf; + size_t tail; - TRY(eat_name_helpfully(&pbs, "Authority Section")); + 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 (!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"; + if (rrf.rdlength > pbs_left(&pbs)) + return "RD Length extends beyond end of message"; - /* ??? should we care about ttl? */ + /* ??? should we care about ttl? */ - tail = rrf.rdlength; + tail = rrf.rdlength; - in_raw(NULL, tail, &pbs, "RR RDATA"); - } + in_raw(NULL, tail, &pbs, "RR RDATA"); + } - /* Additional Section processing (just sanity checking) */ + /* Additional Section processing (just sanity checking) */ - DBG(DBG_DNS, DBG_log("*Additional Section:")); + DBG(DBG_DNS, DBG_log("*Additional Section:")); - for (c = 0; c != qr_header.arcount; c++) - { - struct rr_fixed rrf; - size_t tail; + for (c = 0; c != qr_header.arcount; c++) + { + struct rr_fixed rrf; + size_t tail; - TRY(eat_name_helpfully(&pbs, "Additional Section")); + 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 (!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"; + if (rrf.rdlength > pbs_left(&pbs)) + return "RD Length extends beyond end of message"; - /* ??? should we care about ttl? */ + /* ??? should we care about ttl? */ - tail = rrf.rdlength; + tail = rrf.rdlength; - in_raw(NULL, tail, &pbs, "RR RDATA"); - } + in_raw(NULL, tail, &pbs, "RR RDATA"); + } - /* done all sections */ + /* done all sections */ - /* ??? is padding legal, or can we complain if more left in record? */ + /* ??? is padding legal, or can we complain if more left in record? */ - /* process Answer Section again -- accept contents */ + /* process Answer Section again -- accept contents */ - pbs.cur = ans_start; /* go back to start of answer section */ + pbs.cur = ans_start; /* go back to start of answer section */ - return process_answer_section(&pbs, TRUE, &dns_auth_level - , qr_header.ancount, cr); + return process_answer_section(&pbs, TRUE, &dns_auth_level + , qr_header.ancount, cr); } #endif /* ! USE_LWRES */ @@ -1239,101 +1278,101 @@ build_dns_name(u_char name_buf[NS_MAXDNAME + 2] , const char *typename USED_BY_DEBUG , const char *gwname USED_BY_DEBUG) { - /* note: all end in "." to suppress relative searches */ - id = resolve_myid(id); - switch (id->kind) - { - case ID_IPV4_ADDR: - { - /* XXX: this is really ugly and only temporary until addrtot can - * generate the correct format - */ - const unsigned char *b; - size_t bl USED_BY_DEBUG = addrbytesptr(&id->ip_addr, &b); - - passert(bl == 4); - snprintf(name_buf, NS_MAXDNAME + 2, "%d.%d.%d.%d.in-addr.arpa." - , b[3], b[2], b[1], b[0]); - break; - } - - case ID_IPV6_ADDR: - { - /* ??? is this correct? */ - const unsigned char *b; - size_t bl; - u_char *op = name_buf; - static const char suffix[] = "IP6.INT."; - - for (bl = addrbytesptr(&id->ip_addr, &b); bl-- != 0; ) + /* note: all end in "." to suppress relative searches */ + id = resolve_myid(id); + switch (id->kind) + { + case ID_IPV4_ADDR: { - if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1) - return "IPv6 reverse name too long"; - op += sprintf(op, "%x.%x.", b[bl] & 0xF, b[bl] >> 4); + /* XXX: this is really ugly and only temporary until addrtot can + * generate the correct format + */ + const unsigned char *b; + size_t bl USED_BY_DEBUG = addrbytesptr(&id->ip_addr, &b); + + passert(bl == 4); + snprintf(name_buf, NS_MAXDNAME + 2, "%d.%d.%d.%d.in-addr.arpa." + , b[3], b[2], b[1], b[0]); + break; } - strcpy(op, suffix); - break; - } - case ID_FQDN: - /* strip trailing "." characters, then add one */ + case ID_IPV6_ADDR: { - size_t il = id->name.len; - - while (il > 0 && id->name.ptr[il - 1] == '.') - il--; - if (il > NS_MAXDNAME) - return "FQDN too long for domain name"; + /* ??? is this correct? */ + const unsigned char *b; + size_t bl; + u_char *op = name_buf; + static const char suffix[] = "IP6.INT."; - memcpy(name_buf, id->name.ptr, il); - strcpy(name_buf + il, "."); + for (bl = addrbytesptr(&id->ip_addr, &b); bl-- != 0; ) + { + if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1) + return "IPv6 reverse name too long"; + op += sprintf(op, "%x.%x.", b[bl] & 0xF, b[bl] >> 4); + } + strcpy(op, suffix); + break; } - break; - default: - return "can only query DNS for key for ID that is a FQDN, IPV4_ADDR, or IPV6_ADDR"; - } + case ID_FQDN: + /* strip trailing "." characters, then add one */ + { + size_t il = id->name.len; + + while (il > 0 && id->name.ptr[il - 1] == '.') + il--; + if (il > NS_MAXDNAME) + return "FQDN too long for domain name"; - DBG(DBG_CONTROL | DBG_DNS, DBG_log("DNS query %lu for %s for %s (gw: %s)" - , serial, typename, name_buf, gwname)); - return NULL; + memcpy(name_buf, id->name.ptr, il); + strcpy(name_buf + il, "."); + } + 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: %s)" + , serial, typename, name_buf, gwname)); + 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++; - } + 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)); + struct gw_info *gw = *gwp; - passert(gw->refcnt != 0); - gw->refcnt--; - if (gw->refcnt == 0) + if (gw != NULL) { - free_id_content(&gw->client_id); - free_id_content(&gw->gw_id); - if (gw->gw_key_present) - unreference_key(&gw->key); - gw_delref(&gw->next); - pfree(gw); /* trickery could make this a tail-call */ + DBG(DBG_DNS, DBG_log("gw_delref: %p refcnt: %d--", gw, gw->refcnt)); + + passert(gw->refcnt != 0); + gw->refcnt--; + if (gw->refcnt == 0) + { + free_id_content(&gw->client_id); + free_id_content(&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; } - *gwp = NULL; - } } -static int adns_in_flight = 0; /* queries outstanding */ +static int adns_in_flight = 0; /* queries outstanding */ /* Start an asynchronous DNS query. * @@ -1372,123 +1411,123 @@ static int adns_in_flight = 0; /* queries outstanding */ * 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 *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; + struct adns_continuation *cr = NULL; - if (qtid != 0) - for (cr = continuations; cr != NULL && cr->qtid != qtid; cr = cr->previous) - ; - return cr; + 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); + passert(cr != next_query); + gw_delref(&cr->gateways_from_dns); #ifdef USE_KEYRR - free_public_keys(&cr->keys_from_dns); + free_public_keys(&cr->keys_from_dns); #endif /* USE_KEYRR */ - unshare_id_content(&cr->id); - unshare_id_content(&cr->sgw_id); - - /* unlink from doubly-linked list */ - if (cr->next == NULL) - { - passert(continuations == cr); - continuations = cr->previous; - } - else - { - passert(cr->next->previous == cr); - cr->next->previous = cr->previous; - } - - if (cr->previous != NULL) - { - passert(cr->previous->next == cr); - cr->previous->next = cr->next; - } - - pfree(cr); + unshare_id_content(&cr->id); + unshare_id_content(&cr->sgw_id); + + /* unlink from doubly-linked list */ + if (cr->next == NULL) + { + passert(continuations == cr); + continuations = cr->previous; + } + else + { + passert(cr->next->previous == cr); + cr->next->previous = cr->previous; + } + + if (cr->previous != NULL) + { + passert(cr->previous->next == cr); + cr->previous->next = cr->next; + } + + free(cr); } err_t -start_adns_query(const struct id *id /* domain to query */ -, const struct id *sgw_id /* if non-null, any accepted gw_info must match */ -, int type /* T_TXT or T_KEY, selecting rr type of interest */ +start_adns_query(const struct id *id /* domain to query */ +, const struct id *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); - char gwidb[BUF_LEN]; - - 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) - { - passert(continuations->next == NULL); - continuations->next = cr; - } - continuations = cr; - - cr->qtid = qtid++; - cr->type = type; - cr->cont_fn = cont_fn; - cr->id = *id; - unshare_id_content(&cr->id); - cr->sgw_specified = sgw_id != NULL; - cr->sgw_id = cr->sgw_specified? *sgw_id : empty_id; - unshare_id_content(&cr->sgw_id); - cr->gateways_from_dns = NULL; + static unsigned long qtid = 1; /* query transaction id; NOTE: static */ + const char *typename = rr_typename(type); + char gwidb[BUF_LEN]; + + 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) + { + passert(continuations->next == NULL); + continuations->next = cr; + } + continuations = cr; + + cr->qtid = qtid++; + cr->type = type; + cr->cont_fn = cont_fn; + cr->id = *id; + unshare_id_content(&cr->id); + cr->sgw_specified = sgw_id != NULL; + cr->sgw_id = cr->sgw_specified? *sgw_id : empty_id; + unshare_id_content(&cr->sgw_id); + cr->gateways_from_dns = NULL; #ifdef USE_KEYRR - cr->keys_from_dns = NULL; + cr->keys_from_dns = NULL; #endif /* USE_KEYRR */ #ifdef DEBUG - cr->debugging = cur_debugging; + cr->debugging = cur_debugging; #else - cr->debugging = LEMPTY; + cr->debugging = LEMPTY; #endif - idtoa(&cr->sgw_id, gwidb, sizeof(gwidb)); + idtoa(&cr->sgw_id, gwidb, sizeof(gwidb)); - zero(&cr->query); + zero(&cr->query); - { - err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid - , id, typename, gwidb); - - if (ugh != NULL) { - release_adns_continuation(cr); - return ugh; + err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid + , id, typename, gwidb); + + if (ugh != NULL) + { + release_adns_continuation(cr); + return ugh; + } } - } - if (next_query == NULL) - next_query = cr; + if (next_query == NULL) + next_query = cr; - unsent_ADNS_queries = TRUE; + unsent_ADNS_queries = TRUE; - return NULL; + return NULL; } /* send remaining ADNS queries (until pipe full or none left) @@ -1501,79 +1540,79 @@ 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 */ + 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 */ + if (adns_qfd == NULL_FD) + return; /* nothing useful to do */ - for (;;) - { - if (buf_cur != buf_end) + for (;;) { - 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) + if (buf_cur != buf_end) { - 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 */ + 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; + } } - 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! */ - } + else + { + if (next_query == NULL) + { + unsent_ADNS_queries = FALSE; + break; /* done! */ + } #ifdef USE_LWRES - next_query->used = FALSE; - { - /* NOTE STATIC: */ - static unsigned char qbuf[LWDNSQ_CMDBUF_LEN + 1]; /* room for NUL */ - - snprintf(qbuf, sizeof(qbuf), "%s %lu %s\n" - , rr_typename(next_query->type) - , next_query->qtid - , next_query->query.name_buf); - DBG(DBG_DNS, DBG_log("lwdnsq query: %.*s", (int)(strlen(qbuf) - 1), qbuf)); - buf_cur = qbuf; - buf_end = qbuf + strlen(qbuf); - } + next_query->used = FALSE; + { + /* NOTE STATIC: */ + static unsigned char qbuf[LWDNSQ_CMDBUF_LEN + 1]; /* room for NUL */ + + snprintf(qbuf, sizeof(qbuf), "%s %lu %s\n" + , rr_typename(next_query->type) + , next_query->qtid + , next_query->query.name_buf); + DBG(DBG_DNS, DBG_log("lwdnsq query: %.*s", (int)(strlen(qbuf) - 1), qbuf)); + buf_cur = qbuf; + buf_end = qbuf + strlen(qbuf); + } #else /* !USE_LWRES */ - 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->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); #endif /* !USE_LWRES */ - next_query = next_query->next; - adns_in_flight++; + next_query = next_query->next; + adns_in_flight++; + } } - } } #ifdef USE_LWRES @@ -1584,379 +1623,379 @@ send_unsent_ADNS_queries(void) static err_t process_lwdnsq_answer(char *ts) { - err_t ugh = NULL; - char *rest; - char *p; - char *endofnumber; - struct adns_continuation *cr = NULL; - unsigned long qtid; - time_t anstime; /* time of answer */ - char *atype; /* type of answer */ - long ttl; /* ttl of answer; int, but long for conversion */ - bool AuthenticatedData = FALSE; - static char scratch_null_str[] = ""; /* cannot be const, but isn't written */ - - /* query transaction id */ - rest = ts; - p = strsep(&rest, " \t"); - if (p == NULL) - return "lwdnsq: answer missing query transaction ID"; - - qtid = strtoul(p, &endofnumber, 10); - if (*endofnumber != '\0') - return "lwdnsq: malformed query transaction ID"; - - cr = continuation_for_qtid(qtid); - if (qtid != 0 && cr == NULL) - return "lwdnsq: unrecognized qtid"; /* can't happen! */ - - /* time */ - p = strsep(&rest, " \t"); - if (p == NULL) - return "lwdnsq: missing time"; - - anstime = strtoul(p, &endofnumber, 10); - if (*endofnumber != '\0') - return "lwdnsq: malformed time"; - - /* TTL */ - p = strsep(&rest, " \t"); - if (p == NULL) - return "lwdnsq: missing TTL"; - - ttl = strtol(p, &endofnumber, 10); - if (*endofnumber != '\0') - return "lwdnsq: malformed TTL"; - - /* type */ - atype = strsep(&rest, " \t"); - if (atype == NULL) - return "lwdnsq: missing type"; - - /* if rest is NULL, make it "", otherwise eat whitespace after type */ - rest = rest == NULL? scratch_null_str : rest + strspn(rest, " \t"); - - if (strncasecmp(atype, "AD-", 3) == 0) - { - AuthenticatedData = TRUE; - atype += 3; - } - - /* deal with each type */ - - if (cr == NULL) - { - /* we don't actually know which this applies to */ - return builddiag("lwdnsq: 0 qtid invalid with %s", atype); - } - else if (strcaseeq(atype, "START")) - { - /* ignore */ - } - else if (strcaseeq(atype, "DONE")) - { - if (!cr->used) + err_t ugh = NULL; + char *rest; + char *p; + char *endofnumber; + struct adns_continuation *cr = NULL; + unsigned long qtid; + time_t anstime; /* time of answer */ + char *atype; /* type of answer */ + long ttl; /* ttl of answer; int, but long for conversion */ + bool AuthenticatedData = FALSE; + static char scratch_null_str[] = ""; /* cannot be const, but isn't written */ + + /* query transaction id */ + rest = ts; + p = strsep(&rest, " \t"); + if (p == NULL) + return "lwdnsq: answer missing query transaction ID"; + + qtid = strtoul(p, &endofnumber, 10); + if (*endofnumber != '\0') + return "lwdnsq: malformed query transaction ID"; + + cr = continuation_for_qtid(qtid); + if (qtid != 0 && cr == NULL) + return "lwdnsq: unrecognized qtid"; /* can't happen! */ + + /* time */ + p = strsep(&rest, " \t"); + if (p == NULL) + return "lwdnsq: missing time"; + + anstime = strtoul(p, &endofnumber, 10); + if (*endofnumber != '\0') + return "lwdnsq: malformed time"; + + /* TTL */ + p = strsep(&rest, " \t"); + if (p == NULL) + return "lwdnsq: missing TTL"; + + ttl = strtol(p, &endofnumber, 10); + if (*endofnumber != '\0') + return "lwdnsq: malformed TTL"; + + /* type */ + atype = strsep(&rest, " \t"); + if (atype == NULL) + return "lwdnsq: missing type"; + + /* if rest is NULL, make it "", otherwise eat whitespace after type */ + rest = rest == NULL? scratch_null_str : rest + strspn(rest, " \t"); + + if (strncasecmp(atype, "AD-", 3) == 0) { - /* "no results returned by lwdnsq" should not happen */ - cr->cont_fn(cr - , cr->gateways_from_dns == NULL + AuthenticatedData = TRUE; + atype += 3; + } + + /* deal with each type */ + + if (cr == NULL) + { + /* we don't actually know which this applies to */ + return builddiag("lwdnsq: 0 qtid invalid with %s", atype); + } + else if (strcaseeq(atype, "START")) + { + /* ignore */ + } + else if (strcaseeq(atype, "DONE")) + { + if (!cr->used) + { + /* "no results returned by lwdnsq" should not happen */ + cr->cont_fn(cr + , cr->gateways_from_dns == NULL #ifdef USE_KEYRR - && cr->keys_from_dns == NULL + && cr->keys_from_dns == NULL #endif /* USE_KEYRR */ - ? "no results returned by lwdnsq" : NULL); - cr->used = TRUE; + ? "no results returned by lwdnsq" : NULL); + cr->used = TRUE; + } + reset_globals(); + release_adns_continuation(cr); + adns_in_flight--; + } + else if (strcaseeq(atype, "RETRY")) + { + if (!cr->used) + { + cr->cont_fn(cr, rest); + cr->used = TRUE; + } } - reset_globals(); - release_adns_continuation(cr); - adns_in_flight--; - } - else if (strcaseeq(atype, "RETRY")) - { - if (!cr->used) + else if (strcaseeq(atype, "FATAL")) { - cr->cont_fn(cr, rest); - cr->used = TRUE; + if (!cr->used) + { + cr->cont_fn(cr, rest); + cr->used = TRUE; + } } - } - else if (strcaseeq(atype, "FATAL")) - { - if (!cr->used) + else if (strcaseeq(atype, "DNSSEC")) { - cr->cont_fn(cr, rest); - cr->used = TRUE; + /* ignore */ } - } - else if (strcaseeq(atype, "DNSSEC")) - { - /* ignore */ - } - else if (strcaseeq(atype, "NAME")) - { - /* ignore */ - } - else if (strcaseeq(atype, "TXT")) - { - char *end = rest + strlen(rest); - err_t txt_ugh; - - if (*rest == '"' && end[-1] == '"') + else if (strcaseeq(atype, "NAME")) { - /* strip those pesky quotes */ - rest++; - *--end = '\0'; + /* ignore */ } + else if (strcaseeq(atype, "TXT")) + { + char *end = rest + strlen(rest); + err_t txt_ugh; + + if (*rest == '"' && end[-1] == '"') + { + /* strip those pesky quotes */ + rest++; + *--end = '\0'; + } - txt_ugh = process_txt_rr_body(rest - , TRUE - , AuthenticatedData? DAL_SIGNED : DAL_NOTSEC - , cr); + txt_ugh = process_txt_rr_body(rest + , TRUE + , AuthenticatedData? DAL_SIGNED : DAL_NOTSEC + , cr); - if (txt_ugh != NULL) + if (txt_ugh != NULL) + { + DBG(DBG_DNS, + DBG_log("error processing TXT resource record (%s) while processing: %s" + , txt_ugh, rest)); + cr->cont_fn(cr, txt_ugh); + cr->used = TRUE; + } + } + else if (strcaseeq(atype, "SIG")) + { + /* record the SIG records for posterity */ + if (cr->last_info != NULL) + { + free(cr->last_info->dns_sig); + cr->last_info->dns_sig = clone_str(rest); + } + } + else if (strcaseeq(atype, "A")) + { + /* ignore */ + } + else if (strcaseeq(atype, "AAAA")) { - DBG(DBG_DNS, - DBG_log("error processing TXT resource record (%s) while processing: %s" - , txt_ugh, rest)); - cr->cont_fn(cr, txt_ugh); - cr->used = TRUE; + /* ignore */ } - } - else if (strcaseeq(atype, "SIG")) - { - /* record the SIG records for posterity */ - if (cr->last_info != NULL) + else if (strcaseeq(atype, "CNAME")) { - pfreeany(cr->last_info->dns_sig); - cr->last_info->dns_sig = clone_str(rest, "sigrecord"); + /* ignore */ + } + else if (strcaseeq(atype, "CNAMEFROM")) + { + /* ignore */ + } + else if (strcaseeq(atype, "PTR")) + { + /* ignore */ } - } - else if (strcaseeq(atype, "A")) - { - /* ignore */ - } - else if (strcaseeq(atype, "AAAA")) - { - /* ignore */ - } - else if (strcaseeq(atype, "CNAME")) - { - /* ignore */ - } - else if (strcaseeq(atype, "CNAMEFROM")) - { - /* ignore */ - } - else if (strcaseeq(atype, "PTR")) - { - /* ignore */ - } #ifdef USE_KEYRR - else if (strcaseeq(atype, "KEY")) - { - err_t key_ugh = process_lwdnsq_key(rest - , AuthenticatedData? DAL_SIGNED : DAL_NOTSEC - , cr); - - if (key_ugh != NULL) + else if (strcaseeq(atype, "KEY")) { - DBG(DBG_DNS, - DBG_log("error processing KEY resource record (%s) while processing: %s" - , key_ugh, rest)); - cr->cont_fn(cr, key_ugh); - cr->used = TRUE; + err_t key_ugh = process_lwdnsq_key(rest + , AuthenticatedData? DAL_SIGNED : DAL_NOTSEC + , cr); + + if (key_ugh != NULL) + { + DBG(DBG_DNS, + DBG_log("error processing KEY resource record (%s) while processing: %s" + , key_ugh, rest)); + cr->cont_fn(cr, key_ugh); + cr->used = TRUE; + } } - } #endif /* USE_KEYRR */ - else - { - ugh = "lwdnsq: unrecognized type"; - } - return ugh; + else + { + ugh = "lwdnsq: unrecognized type"; + } + return ugh; } #endif /* USE_LWRES */ static void recover_adns_die(void) { - struct adns_continuation *cr = NULL; - - adns_pid = 0; - if(adns_restart_count < ADNS_RESTART_MAX) { - adns_restart_count++; + struct adns_continuation *cr = NULL; + + adns_pid = 0; + if(adns_restart_count < ADNS_RESTART_MAX) { + adns_restart_count++; - /* next DNS query will restart it */ + /* next DNS query will restart it */ - /* we have to walk the list of the outstanding requests, - * and redo them! - */ + /* we have to walk the list of the outstanding requests, + * and redo them! + */ - cr = continuations; + cr = continuations; - /* find the head of the list */ - if(continuations != NULL) { - for (; cr->previous != NULL; cr = cr->previous); - } - - next_query = cr; + /* 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; + if(next_query != NULL) { + unsent_ADNS_queries = TRUE; + } } - } } void reset_adns_restart_count(void) { - adns_restart_count=0; + 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 size_t buflen = 0; /* bytes in answer buffer */ #ifndef USE_LWRES - static struct adns_answer buf; + static struct adns_answer buf; #else /* USE_LWRES */ - static char buf[LWDNSQ_RESULT_LEN_MAX]; - static char buf_copy[LWDNSQ_RESULT_LEN_MAX]; + static char buf[LWDNSQ_RESULT_LEN_MAX]; + static char buf_copy[LWDNSQ_RESULT_LEN_MAX]; #endif /* USE_LWRES */ - ssize_t n; + ssize_t n; - passert(buflen < sizeof(buf)); - n = read(adns_afd, (unsigned char *)&buf + buflen, sizeof(buf) - buflen); + passert(buflen < sizeof(buf)); + n = read(adns_afd, (unsigned char *)&buf + buflen, sizeof(buf) - buflen); - if (n < 0) - { - if (errno != EINTR) + if (n < 0) { - log_errno((e, "error reading answer from adns")); - /* ??? how can we recover? */ + if (errno != EINTR) + { + log_errno((e, "error reading answer from adns")); + /* ??? how can we recover? */ + } + n = 0; /* now n reflects amount read */ } - n = 0; /* now n reflects amount read */ - } - else if (n == 0) - { - /* EOF */ - if (adns_in_flight != 0) + else if (n == 0) { - plog("EOF from ADNS with %d queries outstanding (restarts %d)" - , adns_in_flight, adns_restart_count); - recover_adns_die(); + /* 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; } - if (buflen != 0) + else { - plog("EOF from ADNS with %lu bytes of a partial answer outstanding" - "(restarts %d)" - , (unsigned long)buflen - , adns_restart_count); - recover_adns_die(); + passert(adns_in_flight > 0); } - stop_adns(); - return; - } - else - { - passert(adns_in_flight > 0); - } - - buflen += n; + + buflen += n; #ifndef USE_LWRES - 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; + 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); + 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); + 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); } - 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); - } #else /* USE_LWRES */ - for (;;) - { - err_t ugh; - char *nlp = memchr(buf, '\n', buflen); + for (;;) + { + err_t ugh; + char *nlp = memchr(buf, '\n', buflen); - if (nlp == NULL) - break; + if (nlp == NULL) + break; - /* we've got a line */ - *nlp++ = '\0'; + /* we've got a line */ + *nlp++ = '\0'; - DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL | DBG_DNS - , DBG_log("lwdns: %s", buf)); + DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL | DBG_DNS + , DBG_log("lwdns: %s", buf)); - /* process lwdnsq_answer may modify buf, so make a copy. */ - buf_copy[0]='\0'; - strncat(buf_copy, buf, sizeof(buf_copy)); + /* process lwdnsq_answer may modify buf, so make a copy. */ + buf_copy[0]='\0'; + strncat(buf_copy, buf, sizeof(buf_copy)); - ugh = process_lwdnsq_answer(buf_copy); - if (ugh != NULL) - plog("failure processing lwdnsq output: %s; record: %s" - , ugh, buf); + ugh = process_lwdnsq_answer(buf_copy); + if (ugh != NULL) + plog("failure processing lwdnsq output: %s; record: %s" + , ugh, buf); - passert(GLOBALS_ARE_RESET()); - reset_globals(); + passert(GLOBALS_ARE_RESET()); + reset_globals(); - /* shift out answer that we've consumed */ - buflen -= nlp - buf; - memmove(buf, nlp, buflen); - } + /* shift out answer that we've consumed */ + buflen -= nlp - buf; + memmove(buf, nlp, buflen); + } #endif /* USE_LWRES */ } diff --git a/src/pluto/dnskey.h b/src/pluto/dnskey.h index f69c226c8..976c715bf 100644 --- a/src/pluto/dnskey.h +++ b/src/pluto/dnskey.h @@ -10,14 +10,12 @@ * 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. - * - * RCSID $Id: dnskey.h 3252 2007-10-06 21:24:50Z andreas $ */ extern int - adns_qfd, /* file descriptor for sending queries to adns */ - adns_afd; /* file descriptor for receiving answers from adns */ -extern const char *pluto_adns_option; /* path from --pluto_adns */ + adns_qfd, /* file descriptor for sending queries to adns */ + 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); @@ -30,55 +28,55 @@ extern void send_unsent_ADNS_queries(void); * Freed by call to release_adns_continuation. */ -struct adns_continuation; /* forward declaration (not far!) */ +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 */ - struct id id; /* subject of query */ - bool sgw_specified; - struct id 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 */ + 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 */ + struct id id; /* subject of query */ + bool sgw_specified; + struct id 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 */ + 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_continuation *previous, *next; + struct pubkey *last_info; /* the last structure we accumulated */ #ifdef USE_LWRES - bool used; /* have we called the cont_fn yet? */ - struct { - u_char name_buf[NS_MAXDNAME + 2]; - } query; + bool used; /* have we called the cont_fn yet? */ + struct { + u_char name_buf[NS_MAXDNAME + 2]; + } query; #else /* ! USE_LWRES */ - struct adns_query query; + struct adns_query query; #endif /* ! USE_LWRES */ }; -extern err_t start_adns_query(const struct id *id /* domain to query */ - , const struct id *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); +extern err_t start_adns_query(const struct id *id /* domain to query */ + , const struct id *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" */ - struct id client_id; /* id of client of peer */ - struct id gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */ - bool gw_key_present; - struct pubkey *key; - struct gw_info *next; + unsigned refcnt; /* reference counted! */ + unsigned pref; /* preference: lower is better */ +#define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */ + struct id client_id; /* id of client of peer */ + struct id 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) - , gw_delref(struct gw_info **gwp); + , gw_delref(struct gw_info **gwp); extern void reset_adns_restart_count(void); diff --git a/src/pluto/dsa.c b/src/pluto/dsa.c deleted file mode 100644 index c5982fbf4..000000000 --- a/src/pluto/dsa.c +++ /dev/null @@ -1,476 +0,0 @@ -/* dsa.c - DSA signature scheme - * Copyright (C) 1998 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG 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. - * - * GnuPG 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifdef PLUTO -#include <gmp.h> -#include <freeswan.h> -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "rnd.h" -#include "gcryptfix.h" -#else /*! PLUTO */ -/* #include <config.h> */ -#endif /* !PLUTO */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifndef PLUTO -/* #include <assert.h> */ -/* #include "util.h" */ -/* #include "mpi.h" */ -/* #include "cipher.h" */ -#endif - -#include "dsa.h" - -typedef struct { - MPI p; /* prime */ - MPI q; /* group order */ - MPI g; /* group generator */ - MPI y; /* g^x mod p */ -} DSA_public_key; - - -typedef struct { - MPI p; /* prime */ - MPI q; /* group order */ - MPI g; /* group generator */ - MPI y; /* g^x mod p */ - MPI x; /* secret exponent */ -} DSA_secret_key; - - -static MPI gen_k( MPI q ); -static void test_keys( DSA_secret_key *sk, unsigned qbits ); -static int check_secret_key( DSA_secret_key *sk ); -static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors ); -static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey); -static int verify(MPI r, MPI s, MPI input, DSA_public_key *pkey); - -static void -progress( int c ) -{ - fputc( c, stderr ); -} - - -/**************** - * Generate a random secret exponent k less than q - */ -static MPI -gen_k( MPI q ) -{ - MPI k = mpi_alloc_secure( mpi_get_nlimbs(q) ); - unsigned int nbits = mpi_get_nbits(q); - unsigned int nbytes = (nbits+7)/8; - char *rndbuf = NULL; - - if( DBG_CIPHER ) - log_debug("choosing a random k "); - for(;;) { - if( DBG_CIPHER ) - progress('.'); - - if( !rndbuf || nbits < 32 ) { - m_free(rndbuf); - rndbuf = get_random_bits( nbits, 1, 1 ); - } - else { /* change only some of the higher bits */ - /* we could imporove this by directly requesting more memory - * at the first call to get_random_bits() and use this the here - * maybe it is easier to do this directly in random.c */ - char *pp = get_random_bits( 32, 1, 1 ); - memcpy( rndbuf,pp, 4 ); - m_free(pp); - } - mpi_set_buffer( k, rndbuf, nbytes, 0 ); - if( mpi_test_bit( k, nbits-1 ) ) - mpi_set_highbit( k, nbits-1 ); - else { - mpi_set_highbit( k, nbits-1 ); - mpi_clear_bit( k, nbits-1 ); - } - - if( !(mpi_cmp( k, q ) < 0) ) { /* check: k < q */ - if( DBG_CIPHER ) - progress('+'); - continue; /* no */ - } - if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */ - if( DBG_CIPHER ) - progress('-'); - continue; /* no */ - } - break; /* okay */ - } - m_free(rndbuf); - if( DBG_CIPHER ) - progress('\n'); - - return k; -} - - -static void -test_keys( DSA_secret_key *sk, unsigned qbits ) -{ - DSA_public_key pk; - MPI test = mpi_alloc( qbits / BITS_PER_MPI_LIMB ); - MPI out1_a = mpi_alloc( qbits / BITS_PER_MPI_LIMB ); - MPI out1_b = mpi_alloc( qbits / BITS_PER_MPI_LIMB ); - - pk.p = sk->p; - pk.q = sk->q; - pk.g = sk->g; - pk.y = sk->y; - /*mpi_set_bytes( test, qbits, get_random_byte, 0 );*/ - { char *p = get_random_bits( qbits, 0, 0 ); - mpi_set_buffer( test, p, (qbits+7)/8, 0 ); - m_free(p); - } - - sign( out1_a, out1_b, test, sk ); - if( !verify( out1_a, out1_b, test, &pk ) ) - log_fatal("DSA:: sign, verify failed\n"); - - mpi_free( test ); - mpi_free( out1_a ); - mpi_free( out1_b ); -} - - - -/**************** - * Generate a DSA key pair with a key of size NBITS - * Returns: 2 structures filled with all needed values - * and an array with the n-1 factors of (p-1) - */ -static void -generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors ) -{ - MPI p; /* the prime */ - MPI q; /* the 160 bit prime factor */ - MPI g; /* the generator */ - MPI y; /* g^x mod p */ - MPI x; /* the secret exponent */ - MPI h, e; /* helper */ - unsigned qbits; - byte *rndbuf; - - assert( nbits >= 512 && nbits <= 1024 ); - - qbits = 160; - p = generate_elg_prime( 1, nbits, qbits, NULL, ret_factors ); - /* get q out of factors */ - q = mpi_copy((*ret_factors)[0]); - if( mpi_get_nbits(q) != qbits ) - BUG(); - - /* find a generator g (h and e are helpers)*/ - /* e = (p-1)/q */ - e = mpi_alloc( mpi_get_nlimbs(p) ); - mpi_sub_ui( e, p, 1 ); - mpi_fdiv_q( e, e, q ); - g = mpi_alloc( mpi_get_nlimbs(p) ); - h = mpi_alloc_set_ui( 1 ); /* we start with 2 */ - do { - mpi_add_ui( h, h, 1 ); - /* g = h^e mod p */ - mpi_powm( g, h, e, p ); - } while( !mpi_cmp_ui( g, 1 ) ); /* continue until g != 1 */ - - /* select a random number which has these properties: - * 0 < x < q-1 - * This must be a very good random number because this - * is the secret part. */ - if( DBG_CIPHER ) - log_debug("choosing a random x "); - assert( qbits >= 160 ); - x = mpi_alloc_secure( mpi_get_nlimbs(q) ); - mpi_sub_ui( h, q, 1 ); /* put q-1 into h */ - rndbuf = NULL; - do { - if( DBG_CIPHER ) - progress('.'); - if( !rndbuf ) - rndbuf = get_random_bits( qbits, 2, 1 ); - else { /* change only some of the higher bits (= 2 bytes)*/ - char *r = get_random_bits( 16, 2, 1 ); - memcpy(rndbuf, r, 16/8 ); - m_free(r); - } - mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 ); - mpi_clear_highbit( x, qbits+1 ); - } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) ); - m_free(rndbuf); - mpi_free( e ); - mpi_free( h ); - - /* y = g^x mod p */ - y = mpi_alloc( mpi_get_nlimbs(p) ); - mpi_powm( y, g, x, p ); - - if( DBG_CIPHER ) { - progress('\n'); - log_mpidump("dsa p= ", p ); - log_mpidump("dsa q= ", q ); - log_mpidump("dsa g= ", g ); - log_mpidump("dsa y= ", y ); - log_mpidump("dsa x= ", x ); - } - - /* copy the stuff to the key structures */ - sk->p = p; - sk->q = q; - sk->g = g; - sk->y = y; - sk->x = x; - - /* now we can test our keys (this should never fail!) */ - test_keys( sk, qbits ); -} - - - -/**************** - * Test whether the secret key is valid. - * Returns: if this is a valid key. - */ -static int -check_secret_key( DSA_secret_key *sk ) -{ - int rc; - MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) ); - - mpi_powm( y, sk->g, sk->x, sk->p ); - rc = !mpi_cmp( y, sk->y ); - mpi_free( y ); - return rc; -} - - - -/**************** - * Make a DSA signature from HASH and put it into r and s. - */ - -static void -sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey ) -{ - MPI k; - MPI kinv; - MPI tmp; - - /* select a random k with 0 < k < q */ - k = gen_k( skey->q ); - - /* r = (a^k mod p) mod q */ - mpi_powm( r, skey->g, k, skey->p ); - mpi_fdiv_r( r, r, skey->q ); - - /* kinv = k^(-1) mod q */ - kinv = mpi_alloc( mpi_get_nlimbs(k) ); - mpi_invm(kinv, k, skey->q ); - - /* s = (kinv * ( hash + x * r)) mod q */ - tmp = mpi_alloc( mpi_get_nlimbs(skey->p) ); - mpi_mul( tmp, skey->x, r ); - mpi_add( tmp, tmp, hash ); - mpi_mulm( s , kinv, tmp, skey->q ); - - mpi_free(k); - mpi_free(kinv); - mpi_free(tmp); -} - - -/**************** - * Returns true if the signature composed from R and S is valid. - */ -static int -verify(MPI r, MPI s, MPI hash, DSA_public_key *pkey ) -{ - int rc; - MPI w, u1, u2, v; - MPI base[3]; - MPI exp[3]; - - - if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) ) - return 0; /* assertion 0 < r < q failed */ - if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) ) - return 0; /* assertion 0 < s < q failed */ - - w = mpi_alloc( mpi_get_nlimbs(pkey->q) ); - u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) ); - u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) ); - v = mpi_alloc( mpi_get_nlimbs(pkey->p) ); - - /* w = s^(-1) mod q */ - mpi_invm( w, s, pkey->q ); - - /* u1 = (hash * w) mod q */ - mpi_mulm( u1, hash, w, pkey->q ); - - /* u2 = r * w mod q */ - mpi_mulm( u2, r, w, pkey->q ); - - /* v = g^u1 * y^u2 mod p mod q */ - base[0] = pkey->g; exp[0] = u1; - base[1] = pkey->y; exp[1] = u2; - base[2] = NULL; exp[2] = NULL; - mpi_mulpowm( v, base, exp, pkey->p ); - mpi_fdiv_r( v, v, pkey->q ); - - rc = !mpi_cmp( v, r ); - - mpi_free(w); - mpi_free(u1); - mpi_free(u2); - mpi_free(v); - return rc; -} - - -/********************************************* - ************** interface ****************** - *********************************************/ - -int -dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ) -{ - DSA_secret_key sk; - - if( algo != PUBKEY_ALGO_DSA ) - return G10ERR_PUBKEY_ALGO; - - generate( &sk, nbits, retfactors ); - skey[0] = sk.p; - skey[1] = sk.q; - skey[2] = sk.g; - skey[3] = sk.y; - skey[4] = sk.x; - return 0; -} - - -int -dsa_check_secret_key( int algo, MPI *skey ) -{ - DSA_secret_key sk; - - if( algo != PUBKEY_ALGO_DSA ) - return G10ERR_PUBKEY_ALGO; - if( !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] ) - return G10ERR_BAD_MPI; - - sk.p = skey[0]; - sk.q = skey[1]; - sk.g = skey[2]; - sk.y = skey[3]; - sk.x = skey[4]; - if( !check_secret_key( &sk ) ) - return G10ERR_BAD_SECKEY; - - return 0; -} - - - -int -dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey ) -{ - DSA_secret_key sk; - - if( algo != PUBKEY_ALGO_DSA ) - return G10ERR_PUBKEY_ALGO; - if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] ) - return G10ERR_BAD_MPI; - - sk.p = skey[0]; - sk.q = skey[1]; - sk.g = skey[2]; - sk.y = skey[3]; - sk.x = skey[4]; - resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); - resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); - sign( resarr[0], resarr[1], data, &sk ); - return 0; -} - -int -dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey, - int (*cmp)(void *, MPI) UNUSED, void *opaquev UNUSED) -{ - DSA_public_key pk; - - if( algo != PUBKEY_ALGO_DSA ) - return G10ERR_PUBKEY_ALGO; - if( !data[0] || !data[1] || !hash - || !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] ) - return G10ERR_BAD_MPI; - - pk.p = pkey[0]; - pk.q = pkey[1]; - pk.g = pkey[2]; - pk.y = pkey[3]; - if( !verify( data[0], data[1], hash, &pk ) ) - return G10ERR_BAD_SIGN; - return 0; -} - - - -unsigned -dsa_get_nbits( int algo, MPI *pkey ) -{ - if( algo != PUBKEY_ALGO_DSA ) - return 0; - return mpi_get_nbits( pkey[0] ); -} - - -/**************** - * Return some information about the algorithm. We need algo here to - * distinguish different flavors of the algorithm. - * Returns: A pointer to string describing the algorithm or NULL if - * the ALGO is invalid. - * Usage: Bit 0 set : allows signing - * 1 set : allows encryption - */ -const char * -dsa_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig, - int *use ) -{ - *npkey = 4; - *nskey = 5; - *nenc = 0; - *nsig = 2; - - switch( algo ) { - case PUBKEY_ALGO_DSA: *use = PUBKEY_USAGE_SIG; return "DSA"; - default: *use = 0; return NULL; - } -} - - diff --git a/src/pluto/dsa.h b/src/pluto/dsa.h deleted file mode 100644 index 1456d65b6..000000000 --- a/src/pluto/dsa.h +++ /dev/null @@ -1,32 +0,0 @@ -/* dsa.h - DSA signature scheme - * Copyright (C) 1998 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG 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. - * - * GnuPG 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ -#ifndef G10_DSA_H -#define G10_DSA_H - -int dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ); -int dsa_check_secret_key( int algo, MPI *skey ); -int dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey ); -int dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey, - int (*cmp)(void *, MPI), void *opaquev ); -unsigned dsa_get_nbits( int algo, MPI *pkey ); -const char *dsa_get_info( int algo, int *npkey, int *nskey, - int *nenc, int *nsig, int *use ); - -#endif /*G10_DSA_H*/ diff --git a/src/pluto/elgamal.c b/src/pluto/elgamal.c deleted file mode 100644 index 0c099bb90..000000000 --- a/src/pluto/elgamal.c +++ /dev/null @@ -1,613 +0,0 @@ -/* elgamal.c - ElGamal Public Key encryption - * Copyright (C) 1998 Free Software Foundation, Inc. - * - * For a description of the algorithm, see: - * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. - * ISBN 0-471-11709-9. Pages 476 ff. - * - * This file is part of GnuPG. - * - * GnuPG 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. - * - * GnuPG 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifdef PLUTO -#include <gmp.h> -#include <freeswan.h> -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "rnd.h" -#include "gcryptfix.h" -#else /*! PLUTO */ -/* #include <config.h> */ -#endif /* !PLUTO */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifndef PLUTO -/* #include "util.h" */ -/* #include "mpi.h" */ -/* #include "cipher.h" */ -#endif - -#include "elgamal.h" - -typedef struct { - MPI p; /* prime */ - MPI g; /* group generator */ - MPI y; /* g^x mod p */ -} ELG_public_key; - - -typedef struct { - MPI p; /* prime */ - MPI g; /* group generator */ - MPI y; /* g^x mod p */ - MPI x; /* secret exponent */ -} ELG_secret_key; - - -static void test_keys( ELG_secret_key *sk, unsigned nbits ); -static MPI gen_k( MPI p ); -static void generate( ELG_secret_key *sk, unsigned nbits, MPI **factors ); -static int check_secret_key( ELG_secret_key *sk ); -static void encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey ); -static void decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey ); -static void sign(MPI a, MPI b, MPI input, ELG_secret_key *skey); -static int verify(MPI a, MPI b, MPI input, ELG_public_key *pkey); - - -static void -progress( int c ) -{ - fputc( c, stderr ); -} - - -static void -test_keys( ELG_secret_key *sk, unsigned nbits ) -{ - ELG_public_key pk; - MPI test = mpi_alloc( 0 ); - MPI out1_a = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); - MPI out1_b = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); - MPI out2 = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); - - pk.p = sk->p; - pk.g = sk->g; - pk.y = sk->y; - - /*mpi_set_bytes( test, nbits, get_random_byte, 0 );*/ - { char *p = get_random_bits( nbits, 0, 0 ); - mpi_set_buffer( test, p, (nbits+7)/8, 0 ); - m_free(p); - } - - encrypt( out1_a, out1_b, test, &pk ); - decrypt( out2, out1_a, out1_b, sk ); - if( mpi_cmp( test, out2 ) ) - log_fatal("ElGamal operation: encrypt, decrypt failed\n"); - - sign( out1_a, out1_b, test, sk ); - if( !verify( out1_a, out1_b, test, &pk ) ) - log_fatal("ElGamal operation: sign, verify failed\n"); - - mpi_free( test ); - mpi_free( out1_a ); - mpi_free( out1_b ); - mpi_free( out2 ); -} - - -/**************** - * generate a random secret exponent k from prime p, so - * that k is relatively prime to p-1 - */ -static MPI -gen_k( MPI p ) -{ - MPI k = mpi_alloc_secure( 0 ); - MPI temp = mpi_alloc( mpi_get_nlimbs(p) ); - MPI p_1 = mpi_copy(p); - unsigned int nbits = mpi_get_nbits(p); - unsigned int nbytes = (nbits+7)/8; - char *rndbuf = NULL; - - if( DBG_CIPHER ) - log_debug("choosing a random k "); - mpi_sub_ui( p_1, p, 1); - for(;;) { - if( DBG_CIPHER ) - progress('.'); - if( !rndbuf || nbits < 32 ) { - m_free(rndbuf); - rndbuf = get_random_bits( nbits, 1, 1 ); - } - else { /* change only some of the higher bits */ - /* we could imporove this by directly requesting more memory - * at the first call to get_random_bits() and use this the here - * maybe it is easier to do this directly in random.c */ - char *pp = get_random_bits( 32, 1, 1 ); - memcpy( rndbuf,pp, 4 ); - m_free(pp); - } - mpi_set_buffer( k, rndbuf, nbytes, 0 ); - - for(;;) { - /* make sure that the number is of the exact lenght */ - if( mpi_test_bit( k, nbits-1 ) ) - mpi_set_highbit( k, nbits-1 ); - else { - mpi_set_highbit( k, nbits-1 ); - mpi_clear_bit( k, nbits-1 ); - } - if( !(mpi_cmp( k, p_1 ) < 0) ) { /* check: k < (p-1) */ - if( DBG_CIPHER ) - progress('+'); - break; /* no */ - } - if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */ - if( DBG_CIPHER ) - progress('-'); - break; /* no */ - } - if( mpi_gcd( temp, k, p_1 ) ) - goto found; /* okay, k is relatively prime to (p-1) */ - mpi_add_ui( k, k, 1 ); - } - } - found: - m_free(rndbuf); - if( DBG_CIPHER ) - progress('\n'); - mpi_free(p_1); - mpi_free(temp); - - return k; -} - -/**************** - * Generate a key pair with a key of size NBITS - * Returns: 2 structures filles with all needed values - * and an array with n-1 factors of (p-1) - */ -static void -generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors ) -{ - MPI p; /* the prime */ - MPI p_min1; - MPI g; - MPI x; /* the secret exponent */ - MPI y; - MPI temp; - unsigned qbits; - byte *rndbuf; - - p_min1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); - temp = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); - if( nbits < 512 ) - qbits = 120; - else if( nbits <= 1024 ) - qbits = 160; - else if( nbits <= 2048 ) - qbits = 200; - else - qbits = 240; - g = mpi_alloc(1); - p = generate_elg_prime( 0, nbits, qbits, g, ret_factors ); - mpi_sub_ui(p_min1, p, 1); - - - /* select a random number which has these properties: - * 0 < x < p-1 - * This must be a very good random number because this is the - * secret part. The prime is public and may be shared anyway, - * so a random generator level of 1 is used for the prime. - */ - x = mpi_alloc_secure( nbits/BITS_PER_MPI_LIMB ); - if( DBG_CIPHER ) - log_debug("choosing a random x "); - rndbuf = NULL; - do { - if( DBG_CIPHER ) - progress('.'); - if( rndbuf ) { /* change only some of the higher bits */ - if( nbits < 16 ) {/* should never happen ... */ - m_free(rndbuf); - rndbuf = get_random_bits( nbits, 2, 1 ); - } - else { - char *r = get_random_bits( 16, 2, 1 ); - memcpy(rndbuf, r, 16/8 ); - m_free(r); - } - } - else - rndbuf = get_random_bits( nbits, 2, 1 ); - mpi_set_buffer( x, rndbuf, (nbits+7)/8, 0 ); - mpi_clear_highbit( x, nbits+1 ); - } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) ); - m_free(rndbuf); - - y = mpi_alloc(nbits/BITS_PER_MPI_LIMB); - mpi_powm( y, g, x, p ); - - if( DBG_CIPHER ) { - progress('\n'); - log_mpidump("elg p= ", p ); - log_mpidump("elg g= ", g ); - log_mpidump("elg y= ", y ); - log_mpidump("elg x= ", x ); - } - - /* copy the stuff to the key structures */ - sk->p = p; - sk->g = g; - sk->y = y; - sk->x = x; - - /* now we can test our keys (this should never fail!) */ - test_keys( sk, nbits - 64 ); - - mpi_free( p_min1 ); - mpi_free( temp ); -} - - -/**************** - * Test whether the secret key is valid. - * Returns: if this is a valid key. - */ -static int -check_secret_key( ELG_secret_key *sk ) -{ - int rc; - MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) ); - - mpi_powm( y, sk->g, sk->x, sk->p ); - rc = !mpi_cmp( y, sk->y ); - mpi_free( y ); - return rc; -} - - -static void -encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey ) -{ - MPI k; - - /* Note: maybe we should change the interface, so that it - * is possible to check that input is < p and return an - * error code. - */ - - k = gen_k( pkey->p ); - mpi_powm( a, pkey->g, k, pkey->p ); - /* b = (y^k * input) mod p - * = ((y^k mod p) * (input mod p)) mod p - * and because input is < p - * = ((y^k mod p) * input) mod p - */ - mpi_powm( b, pkey->y, k, pkey->p ); - mpi_mulm( b, b, input, pkey->p ); - #if 0 - if( DBG_CIPHER ) { - log_mpidump("elg encrypted y= ", pkey->y); - log_mpidump("elg encrypted p= ", pkey->p); - log_mpidump("elg encrypted k= ", k); - log_mpidump("elg encrypted M= ", input); - log_mpidump("elg encrypted a= ", a); - log_mpidump("elg encrypted b= ", b); - } - #endif - mpi_free(k); -} - - - - -static void -decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey ) -{ - MPI t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) ); - - /* output = b/(a^x) mod p */ - - mpi_powm( t1, a, skey->x, skey->p ); - mpi_invm( t1, t1, skey->p ); - mpi_mulm( output, b, t1, skey->p ); - #if 0 - if( DBG_CIPHER ) { - log_mpidump("elg decrypted x= ", skey->x); - log_mpidump("elg decrypted p= ", skey->p); - log_mpidump("elg decrypted a= ", a); - log_mpidump("elg decrypted b= ", b); - log_mpidump("elg decrypted M= ", output); - } - #endif - mpi_free(t1); -} - - -/**************** - * Make an Elgamal signature out of INPUT - */ - -static void -sign(MPI a, MPI b, MPI input, ELG_secret_key *skey ) -{ - MPI k; - MPI t = mpi_alloc( mpi_get_nlimbs(a) ); - MPI inv = mpi_alloc( mpi_get_nlimbs(a) ); - MPI p_1 = mpi_copy(skey->p); - - /* - * b = (t * inv) mod (p-1) - * b = (t * inv(k,(p-1),(p-1)) mod (p-1) - * b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1) - * - */ - mpi_sub_ui(p_1, p_1, 1); - k = gen_k( skey->p ); - mpi_powm( a, skey->g, k, skey->p ); - mpi_mul(t, skey->x, a ); - mpi_subm(t, input, t, p_1 ); - while( mpi_is_neg(t) ) - mpi_add(t, t, p_1); - mpi_invm(inv, k, p_1 ); - mpi_mulm(b, t, inv, p_1 ); - - #if 0 - if( DBG_CIPHER ) { - log_mpidump("elg sign p= ", skey->p); - log_mpidump("elg sign g= ", skey->g); - log_mpidump("elg sign y= ", skey->y); - log_mpidump("elg sign x= ", skey->x); - log_mpidump("elg sign k= ", k); - log_mpidump("elg sign M= ", input); - log_mpidump("elg sign a= ", a); - log_mpidump("elg sign b= ", b); - } - #endif - mpi_free(k); - mpi_free(t); - mpi_free(inv); - mpi_free(p_1); -} - - -/**************** - * Returns true if the signature composed of A and B is valid. - */ -static int -verify(MPI a, MPI b, MPI input, ELG_public_key *pkey ) -{ - int rc; - MPI t1; - MPI t2; - MPI base[4]; - MPI exp[4]; - - if( !(mpi_cmp_ui( a, 0 ) > 0 && mpi_cmp( a, pkey->p ) < 0) ) - return 0; /* assertion 0 < a < p failed */ - - t1 = mpi_alloc( mpi_get_nlimbs(a) ); - t2 = mpi_alloc( mpi_get_nlimbs(a) ); - - #if 0 - /* t1 = (y^a mod p) * (a^b mod p) mod p */ - mpi_powm( t1, pkey->y, a, pkey->p ); - mpi_powm( t2, a, b, pkey->p ); - mpi_mulm( t1, t1, t2, pkey->p ); - - /* t2 = g ^ input mod p */ - mpi_powm( t2, pkey->g, input, pkey->p ); - - rc = !mpi_cmp( t1, t2 ); - #elif 0 - /* t1 = (y^a mod p) * (a^b mod p) mod p */ - base[0] = pkey->y; exp[0] = a; - base[1] = a; exp[1] = b; - base[2] = NULL; exp[2] = NULL; - mpi_mulpowm( t1, base, exp, pkey->p ); - - /* t2 = g ^ input mod p */ - mpi_powm( t2, pkey->g, input, pkey->p ); - - rc = !mpi_cmp( t1, t2 ); - #else - /* t1 = g ^ - input * y ^ a * a ^ b mod p */ - mpi_invm(t2, pkey->g, pkey->p ); - base[0] = t2 ; exp[0] = input; - base[1] = pkey->y; exp[1] = a; - base[2] = a; exp[2] = b; - base[3] = NULL; exp[3] = NULL; - mpi_mulpowm( t1, base, exp, pkey->p ); - rc = !mpi_cmp_ui( t1, 1 ); - - #endif - - mpi_free(t1); - mpi_free(t2); - return rc; -} - -/********************************************* - ************** interface ****************** - *********************************************/ - -int -elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ) -{ - ELG_secret_key sk; - - if( !is_ELGAMAL(algo) ) - return G10ERR_PUBKEY_ALGO; - - generate( &sk, nbits, retfactors ); - skey[0] = sk.p; - skey[1] = sk.g; - skey[2] = sk.y; - skey[3] = sk.x; - return 0; -} - - -int -elg_check_secret_key( int algo, MPI *skey ) -{ - ELG_secret_key sk; - - if( !is_ELGAMAL(algo) ) - return G10ERR_PUBKEY_ALGO; - if( !skey[0] || !skey[1] || !skey[2] || !skey[3] ) - return G10ERR_BAD_MPI; - - sk.p = skey[0]; - sk.g = skey[1]; - sk.y = skey[2]; - sk.x = skey[3]; - if( !check_secret_key( &sk ) ) - return G10ERR_BAD_SECKEY; - - return 0; -} - - - -int -elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ) -{ - ELG_public_key pk; - - if( !is_ELGAMAL(algo) ) - return G10ERR_PUBKEY_ALGO; - if( !data || !pkey[0] || !pkey[1] || !pkey[2] ) - return G10ERR_BAD_MPI; - - pk.p = pkey[0]; - pk.g = pkey[1]; - pk.y = pkey[2]; - resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); - resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); - encrypt( resarr[0], resarr[1], data, &pk ); - return 0; -} - -int -elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey ) -{ - ELG_secret_key sk; - - if( !is_ELGAMAL(algo) ) - return G10ERR_PUBKEY_ALGO; - if( !data[0] || !data[1] - || !skey[0] || !skey[1] || !skey[2] || !skey[3] ) - return G10ERR_BAD_MPI; - - sk.p = skey[0]; - sk.g = skey[1]; - sk.y = skey[2]; - sk.x = skey[3]; - *result = mpi_alloc_secure( mpi_get_nlimbs( sk.p ) ); - decrypt( *result, data[0], data[1], &sk ); - return 0; -} - -int -elg_sign( int algo, MPI *resarr, MPI data, MPI *skey ) -{ - ELG_secret_key sk; - - if( !is_ELGAMAL(algo) ) - return G10ERR_PUBKEY_ALGO; - if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] ) - return G10ERR_BAD_MPI; - - sk.p = skey[0]; - sk.g = skey[1]; - sk.y = skey[2]; - sk.x = skey[3]; - resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); - resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); - sign( resarr[0], resarr[1], data, &sk ); - return 0; -} - -int -elg_verify( int algo, MPI hash, MPI *data, MPI *pkey, - int (*cmp)(void *, MPI) UNUSED, void *opaquev UNUSED) -{ - ELG_public_key pk; - - if( !is_ELGAMAL(algo) ) - return G10ERR_PUBKEY_ALGO; - if( !data[0] || !data[1] || !hash - || !pkey[0] || !pkey[1] || !pkey[2] ) - return G10ERR_BAD_MPI; - - pk.p = pkey[0]; - pk.g = pkey[1]; - pk.y = pkey[2]; - if( !verify( data[0], data[1], hash, &pk ) ) - return G10ERR_BAD_SIGN; - return 0; -} - - - -unsigned -elg_get_nbits( int algo, MPI *pkey ) -{ - if( !is_ELGAMAL(algo) ) - return 0; - return mpi_get_nbits( pkey[0] ); -} - - -/**************** - * Return some information about the algorithm. We need algo here to - * distinguish different flavors of the algorithm. - * Returns: A pointer to string describing the algorithm or NULL if - * the ALGO is invalid. - * Usage: Bit 0 set : allows signing - * 1 set : allows encryption - * NOTE: This function allows signing also for ELG-E, which is not - * okay but a bad hack to allow to work with old gpg keys. The real check - * is done in the gnupg ocde depending on the packet version. - */ -const char * -elg_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig, - int *use ) -{ - *npkey = 3; - *nskey = 4; - *nenc = 2; - *nsig = 2; - - switch( algo ) { - case PUBKEY_ALGO_ELGAMAL: - *use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC; - return "ELG"; - case PUBKEY_ALGO_ELGAMAL_E: - *use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC; - return "ELG-E"; - default: *use = 0; return NULL; - } -} - - diff --git a/src/pluto/elgamal.h b/src/pluto/elgamal.h deleted file mode 100644 index f104c2a52..000000000 --- a/src/pluto/elgamal.h +++ /dev/null @@ -1,35 +0,0 @@ -/* elgamal.h - * Copyright (C) 1998 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG 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. - * - * GnuPG 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ -#ifndef G10_ELGAMAL_H -#define G10_ELGAMAL_H - -int elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ); -int elg_check_secret_key( int algo, MPI *skey ); -int elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ); -int elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey ); -int elg_sign( int algo, MPI *resarr, MPI data, MPI *skey ); -int elg_verify( int algo, MPI hash, MPI *data, MPI *pkey, - int (*cmp)(void *, MPI), void *opaquev ); -unsigned elg_get_nbits( int algo, MPI *pkey ); -const char *elg_get_info( int algo, int *npkey, int *nskey, - int *nenc, int *nsig, int *use ); - - -#endif /*G10_ELGAMAL_H*/ diff --git a/src/pluto/fetch.c b/src/pluto/fetch.c index c8a98cd9b..6f7f1215f 100644 --- a/src/pluto/fetch.c +++ b/src/pluto/fetch.c @@ -1,6 +1,6 @@ /* Dynamic fetching of X.509 CRLs * Copyright (C) 2002 Stephane Laroche <stephane.laroche@colubris.com> - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * 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 @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: fetch.c 4632 2008-11-11 18:37:19Z martin $ */ #include <stdlib.h> @@ -25,24 +23,17 @@ #include <pthread.h> #endif -#ifdef LIBCURL -#include <curl/curl.h> -#endif - #include <freeswan.h> -#ifdef LIBLDAP -#ifndef LDAP_DEPRECATED -#define LDAP_DEPRECATED 1 -#endif -#include <ldap.h> -#endif +#include <library.h> +#include <debug.h> +#include <asn1/asn1.h> +#include <asn1/pem.h> #include "constants.h" #include "defs.h" #include "log.h" #include "id.h" -#include "asn1.h" #include "pem.h" #include "x509.h" #include "ca.h" @@ -52,13 +43,13 @@ #include "fetch.h" fetch_req_t empty_fetch_req = { - NULL , /* next */ - 0 , /* installed */ - 0 , /* trials */ + NULL , /* next */ + 0 , /* installed */ + 0 , /* trials */ { NULL, 0}, /* issuer */ { NULL, 0}, /* authKeyID */ { NULL, 0}, /* authKeySerialNumber */ - NULL /* distributionPoints */ + NULL /* distributionPoints */ }; /* chained list of crl fetch requests */ @@ -79,189 +70,174 @@ 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) +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) - ) + 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 +/** + * Unlock access to my certs and keys */ -void -unlock_certs_and_keys(const char *who) +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); + 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 +/** + * Lock access to the chained authcert list */ -void -lock_authcert_list(const char *who) +void lock_authcert_list(const char *who) { - pthread_mutex_lock(&authcert_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("authcert list locked by '%s'", 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 +/** + * Unlock access to the chained authcert list */ -void -unlock_authcert_list(const char *who) +void unlock_authcert_list(const char *who) { - DBG(DBG_CONTROLMORE, - DBG_log("authcert list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&authcert_list_mutex); + DBG(DBG_CONTROLMORE, + DBG_log("authcert list unlocked by '%s'", who) + ) + pthread_mutex_unlock(&authcert_list_mutex); } -/* - * lock access to the chained crl list +/** + * Lock access to the chained crl list */ -void -lock_crl_list(const char *who) +void lock_crl_list(const char *who) { - pthread_mutex_lock(&crl_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("crl list locked by '%s'", 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 +/** + * Unlock access to the chained crl list */ -void -unlock_crl_list(const char *who) +void unlock_crl_list(const char *who) { - DBG(DBG_CONTROLMORE, - DBG_log("crl list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&crl_list_mutex); + DBG(DBG_CONTROLMORE, + DBG_log("crl list unlocked by '%s'", who) + ) + pthread_mutex_unlock(&crl_list_mutex); } -/* - * lock access to the ocsp cache +/** + * Lock access to the ocsp cache */ -extern void -lock_ocsp_cache(const char *who) +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) - ) + pthread_mutex_lock(&ocsp_cache_mutex); + DBG(DBG_CONTROLMORE, + DBG_log("ocsp cache locked by '%s'", who) + ) } -/* - * unlock access to the ocsp cache +/** + * Unlock access to the ocsp cache */ -extern void -unlock_ocsp_cache(const char *who) +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); + DBG(DBG_CONTROLMORE, + DBG_log("ocsp cache unlocked by '%s'", who) + ) + pthread_mutex_unlock(&ocsp_cache_mutex); } -/* - * lock access to the ca info list +/** + * Lock access to the ca info list */ -extern void -lock_ca_info_list(const char *who) +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) - ) + 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 +/** + * Unlock access to the ca info list */ -extern void -unlock_ca_info_list(const char *who) +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); + 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 +/** + * Lock access to the chained crl fetch request list */ -static void -lock_crl_fetch_list(const char *who) +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) - ) + 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 +/** + * Unlock access to the chained crl fetch request list */ -static void -unlock_crl_fetch_list(const char *who) +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); + 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 +/** + * Lock access to the chained ocsp fetch request list */ -static void -lock_ocsp_fetch_list(const char *who) +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) - ) + 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 +/** + * Unlock access to the chained ocsp fetch request list */ -static void -unlock_ocsp_fetch_list(const char *who) +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); + 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 +/** + * Wakes up the sleeping fetch thread */ -void -wake_fetch_thread(const char *who) +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); - } + 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 */ @@ -270,817 +246,506 @@ wake_fetch_thread(const char *who) #define unlock_ocsp_fetch_list(who) /* do nothing */ #endif /* !THREADS */ -/* - * free the dynamic memory used to store fetch requests +/** + * Free the dynamic memory used to store fetch requests */ -static void -free_fetch_request(fetch_req_t *req) +static void free_fetch_request(fetch_req_t *req) { - pfree(req->issuer.ptr); - pfreeany(req->authKeySerialNumber.ptr); - pfreeany(req->authKeyID.ptr); - free_generalNames(req->distributionPoints, TRUE); - pfree(req); -} - -/* writes data into a dynamically resizeable chunk_t - * needed for libcurl responses - */ -size_t -write_buffer(void *ptr, size_t size, size_t nmemb, void *data) -{ - size_t realsize = size * nmemb; - chunk_t *mem = (chunk_t*)data; - - mem->ptr = (u_char *)realloc(mem->ptr, mem->len + realsize); - if (mem->ptr) { - memcpy(&(mem->ptr[mem->len]), ptr, realsize); - mem->len += realsize; - } - return realsize; + free(req->issuer.ptr); + free(req->authKeySerialNumber.ptr); + free(req->authKeyID.ptr); + free_generalNames(req->distributionPoints, TRUE); + free(req); } #ifdef THREADS -/* - * fetches a binary blob from a url with libcurl +/** + * Fetch an ASN.1 blob coded in PEM or DER format from a URL */ -static err_t -fetch_curl(char *url, chunk_t *blob) +bool fetch_asn1_blob(char *url, chunk_t *blob) { -#ifdef LIBCURL - char errorbuffer[CURL_ERROR_SIZE] = ""; - chunk_t response = empty_chunk; - CURLcode res; - - /* get it with libcurl */ - CURL *curl = curl_easy_init(); - - if (curl != NULL) - { - DBG(DBG_CONTROL, - DBG_log("Trying cURL '%s'", url) - ) - - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); - curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer); - curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT); - - res = curl_easy_perform(curl); - - if (res == CURLE_OK) - { - blob->len = response.len; - blob->ptr = alloc_bytes(response.len, "curl blob"); - memcpy(blob->ptr, response.ptr, response.len); - } - else + DBG1(" fetching crl from '%s' ...", url); + if (lib->fetcher->fetch(lib->fetcher, url, blob, FETCH_END) != SUCCESS) { - plog("fetching uri (%s) with libcurl failed: %s", url, errorbuffer); + DBG1("crl fetching failed"); + return FALSE; } - curl_easy_cleanup(curl); - /* not using freeanychunk because of realloc (no leak detective) */ - curl_free(response.ptr); - } - return strlen(errorbuffer) > 0 ? "libcurl error" : NULL; -#else /* !LIBCURL */ - return "warning: not compiled with libcurl support"; -#endif /* !LIBCURL */ -} - -#ifdef LIBLDAP -/* - * parses the result returned by an ldap query - */ -static err_t -parse_ldap_result(LDAP * ldap, LDAPMessage *result, chunk_t *blob) -{ - err_t ugh = NULL; - - LDAPMessage * entry = ldap_first_entry(ldap, result); - if (entry != NULL) - { - BerElement *ber = NULL; - char *attr; - - attr = ldap_first_attribute(ldap, entry, &ber); - - if (attr != NULL) + if (is_asn1(*blob)) { - struct berval **values = ldap_get_values_len(ldap, entry, attr); - - if (values != NULL) - { - if (values[0] != NULL) - { - blob->len = values[0]->bv_len; - blob->ptr = alloc_bytes(blob->len, "ldap blob"); - memcpy(blob->ptr, values[0]->bv_val, blob->len); - if (values[1] != NULL) - { - plog("warning: more than one value was fetched from LDAP URL"); - } - } - else - { - ugh = "no values in attribute"; - } - ldap_value_free_len(values); - } - else - { - ugh = ldap_err2string(ldap_result2error(ldap, entry, 0)); - } - ldap_memfree(attr); + DBG2(" fetched blob coded in DER format"); } else { - ugh = ldap_err2string(ldap_result2error(ldap, entry, 0)); - } - ber_free(ber, 0); - } - else - { - ugh = ldap_err2string(ldap_result2error(ldap, result, 0)); - } - return ugh; -} - -/* - * fetches a binary blob from an ldap url - */ -static err_t -fetch_ldap_url(char *url, chunk_t *blob) -{ - LDAPURLDesc *lurl; - err_t ugh = NULL; - int rc; - - DBG(DBG_CONTROL, - DBG_log("Trying LDAP URL '%s'", url) - ) - - rc = ldap_url_parse(url, &lurl); - - if (rc == LDAP_SUCCESS) - { - LDAP *ldap = ldap_init(lurl->lud_host, lurl->lud_port); - - if (ldap != NULL) - { - int ldap_version = LDAP_VERSION3; - struct timeval timeout; + bool pgp = FALSE; - timeout.tv_sec = FETCH_CMD_TIMEOUT; - timeout.tv_usec = 0; - ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version); - ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout); - - rc = ldap_simple_bind_s(ldap, NULL, NULL); - - if (rc == LDAP_SUCCESS) - { - LDAPMessage *result; - - timeout.tv_sec = FETCH_CMD_TIMEOUT; - timeout.tv_usec = 0; - - rc = ldap_search_st(ldap, lurl->lud_dn - , lurl->lud_scope - , lurl->lud_filter - , lurl->lud_attrs - , 0, &timeout, &result); - - if (rc == LDAP_SUCCESS) + if (pem_to_bin(blob, chunk_empty, &pgp) != SUCCESS) { - ugh = parse_ldap_result(ldap, result, blob); - ldap_msgfree(result); + free(blob->ptr); + return FALSE; + } + if (is_asn1(*blob)) + { + DBG2(" fetched blob coded in PEM format"); } else { - ugh = ldap_err2string(rc); + DBG1("crl fetched successfully but data coded in unknown format"); + free(blob->ptr); + return FALSE; } - } - else - { - ugh = ldap_err2string(rc); - } - ldap_unbind_s(ldap); - } - else - { - ugh = "ldap init"; - } - ldap_free_urldesc(lurl); - } - else - { - ugh = ldap_err2string(rc); - } - return ugh; -} -#else /* !LIBLDAP */ -static err_t -fetch_ldap_url(char *url, chunk_t *blob) -{ - return "LDAP URL fetching not activated in pluto source code"; -} -#endif /* !LIBLDAP */ - -/* - * fetch an ASN.1 blob coded in PEM or DER format from a URL - */ -static err_t -fetch_asn1_blob(char *url, chunk_t *blob) -{ - err_t ugh = NULL; - - if (strlen(url) >= 4 && strncasecmp(url, "ldap", 4) == 0) - { - ugh = fetch_ldap_url(url, blob); - } - else - { - ugh = fetch_curl(url, blob); - } - if (ugh != NULL) - return ugh; - - if (is_asn1(*blob)) - { - DBG(DBG_PARSING, - DBG_log(" fetched blob coded in DER format") - ) - } - else - { - bool pgp = FALSE; - - ugh = pemtobin(blob, NULL, "", &pgp); - if (ugh == NULL) - { - if (is_asn1(*blob)) - { - DBG(DBG_PARSING, - DBG_log(" fetched blob coded in PEM format") - ) - } - else - { - ugh = "blob coded in unknown format"; - pfree(blob->ptr); - } - } - else - { - pfree(blob->ptr); } - } - return ugh; + return TRUE; } -/* - * complete a distributionPoint URI with ca information +/** + * Complete a distributionPoint URI with ca information */ -static char* -complete_uri(chunk_t distPoint, const char *ldaphost) +static char* complete_uri(chunk_t distPoint, const char *ldaphost) { - char *uri; - char *ptr = distPoint.ptr; - size_t len = distPoint.len; + char *uri; + char *ptr = distPoint.ptr; + size_t len = distPoint.len; - char *symbol = memchr(ptr, ':', len); + char *symbol = memchr(ptr, ':', len); - if (symbol != NULL) - { - size_t type_len = symbol - ptr; - - if (type_len >= 4 && strncasecmp(ptr, "ldap", 4) == 0) + if (symbol != NULL) { - ptr = symbol + 1; - len -= (type_len + 1); - - if (len > 2 && *ptr++ == '/' && *ptr++ == '/') - { - len -= 2; - symbol = memchr(ptr, '/', len); + size_t type_len = symbol - ptr; - if (symbol != NULL && symbol - ptr == 0 && ldaphost != NULL) + if (type_len >= 4 && strncasecmp(ptr, "ldap", 4) == 0) { - uri = alloc_bytes(distPoint.len+strlen(ldaphost)+1, "uri"); - - /* insert the ldaphost into the uri */ - sprintf(uri, "%.*s%s%.*s" - , (int)(distPoint.len - len), distPoint.ptr - , ldaphost - , (int)len, symbol); - return uri; + ptr = symbol + 1; + len -= (type_len + 1); + + if (len > 2 && *ptr++ == '/' && *ptr++ == '/') + { + len -= 2; + symbol = memchr(ptr, '/', len); + + if (symbol != NULL && symbol - ptr == 0 && ldaphost != NULL) + { + uri = malloc(distPoint.len + strlen(ldaphost) + 1); + + /* insert the ldaphost into the uri */ + sprintf(uri, "%.*s%s%.*s" + , (int)(distPoint.len - len), distPoint.ptr + , ldaphost + , (int)len, symbol); + return uri; + } + } } - } } - } - - /* default action: copy distributionPoint without change */ - uri = alloc_bytes(distPoint.len+1, "uri"); - sprintf(uri, "%.*s", (int)distPoint.len, distPoint.ptr); - return uri; + + /* default action: copy distributionPoint without change */ + uri = malloc(distPoint.len + 1); + sprintf(uri, "%.*s", (int)distPoint.len, distPoint.ptr); + return uri; } -/* - * try to fetch the crls defined by the fetch requests +/** + * Try to fetch the crls defined by the fetch requests */ -static void -fetch_crls(bool cache_crls) +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) - { - bool valid_crl = FALSE; - chunk_t blob = empty_chunk; - generalName_t *gn = req->distributionPoints; - const char *ldaphost; - ca_info_t *ca; + fetch_req_t *req; + fetch_req_t **reqp; - lock_ca_info_list("fetch_crls"); + lock_crl_fetch_list("fetch_crls"); + req = crl_fetch_reqs; + reqp = &crl_fetch_reqs; - ca = get_ca_info(req->issuer, req->authKeySerialNumber, req->authKeyID); - ldaphost = (ca == NULL)? NULL : ca->ldaphost; - - while (gn != NULL) + while (req != NULL) { - char *uri = complete_uri(gn->name, ldaphost); + bool valid_crl = FALSE; + chunk_t blob = chunk_empty; + generalName_t *gn = req->distributionPoints; + const char *ldaphost; + ca_info_t *ca; - err_t ugh = fetch_asn1_blob(uri, &blob); - pfree(uri); + lock_ca_info_list("fetch_crls"); - if (ugh != NULL) - { - plog("fetch failed: %s", ugh); - } - else - { - chunk_t crl_uri; + ca = get_ca_info(req->issuer, req->authKeySerialNumber, req->authKeyID); + ldaphost = (ca == NULL)? NULL : ca->ldaphost; - clonetochunk(crl_uri, gn->name.ptr, gn->name.len, "crl uri"); - if (insert_crl(blob, crl_uri, cache_crls)) + while (gn != NULL) { - DBG(DBG_CONTROL, - DBG_log("we have a valid crl") - ) - valid_crl = TRUE; - break; + char *uri = complete_uri(gn->name, ldaphost); + + if (fetch_asn1_blob(uri, &blob)) + { + chunk_t crl_uri = chunk_clone(gn->name); + + if (insert_crl(blob, crl_uri, cache_crls)) + { + DBG(DBG_CONTROL, + DBG_log("we have a valid crl") + ) + valid_crl = TRUE; + free(uri); + break; + } + } + free(uri); + gn = gn->next; } - } - gn = gn->next; - } - unlock_ca_info_list("fetch_crls"); + unlock_ca_info_list("fetch_crls"); - if (valid_crl) - { - /* delete fetch request */ - fetch_req_t *req_free = req; + 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; + 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"); + unlock_crl_fetch_list("fetch_crls"); } -static void -fetch_ocsp_status(ocsp_location_t* location) +static void fetch_ocsp_status(ocsp_location_t* location) { -#ifdef LIBCURL - chunk_t request; - chunk_t response = empty_chunk; - - CURL* curl; - CURLcode res; - - request = build_ocsp_request(location); + chunk_t request, response; + char *uri; - DBG(DBG_CONTROL, - DBG_log("sending ocsp request to location '%.*s'" - , (int)location->uri.len, location->uri.ptr) - ) - DBG(DBG_RAW, - DBG_dump_chunk("OCSP request", request) - ) - - /* send via http post using libcurl */ - curl = curl_easy_init(); - - if (curl != NULL) - { - char errorbuffer[CURL_ERROR_SIZE]; - struct curl_slist *headers = NULL; - char* uri = alloc_bytes(location->uri.len+1, "ocsp uri"); + request = build_ocsp_request(location); + response = chunk_empty; /* we need a null terminated string for curl */ + uri = malloc(location->uri.len + 1); memcpy(uri, location->uri.ptr, location->uri.len); *(uri + location->uri.len) = '\0'; - /* set content type header */ - headers = curl_slist_append(headers, "Content-Type: application/ocsp-request"); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - - curl_easy_setopt(curl, CURLOPT_URL, uri); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_buffer); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (void*)request.ptr); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request.len); - curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer); - curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, FETCH_CMD_TIMEOUT); - - res = curl_easy_perform(curl); - - if (res == CURLE_OK) + DBG1(" requesting ocsp status from '%s' ...", uri); + if (lib->fetcher->fetch(lib->fetcher, uri, &response, + FETCH_REQUEST_DATA, request, + FETCH_REQUEST_TYPE, "application/ocsp-request", + FETCH_END) == SUCCESS) { - DBG(DBG_CONTROL, - DBG_log("received ocsp response") - ) - DBG(DBG_RAW, - DBG_dump_chunk("OCSP response:\n", response) - ) - parse_ocsp(location, response); + parse_ocsp(location, response); } else { - plog("failed to fetch ocsp status from '%s': %s", uri, errorbuffer); + DBG1("ocsp request to %s failed", uri); } - curl_slist_free_all(headers); - curl_easy_cleanup(curl); - pfree(uri); - /* not using freeanychunk because of realloc (no leak detective) */ - curl_free(response.ptr); - } - freeanychunk(location->nonce); - freeanychunk(request); - - /* increment the trial counter of the unresolved fetch requests */ - { - ocsp_certinfo_t *certinfo = location->certinfo; - - while (certinfo != NULL) + + free(uri); + free(request.ptr); + chunk_free(&location->nonce); + + /* increment the trial counter of the unresolved fetch requests */ { - certinfo->trials++; - certinfo = certinfo->next; + ocsp_certinfo_t *certinfo = location->certinfo; + + while (certinfo != NULL) + { + certinfo->trials++; + certinfo = certinfo->next; + } } - } - return; -#else /* !LIBCURL */ - plog("ocsp error: pluto wasn't compiled with libcurl support"); -#endif /* !LIBCURL */ } -/* - * try to fetch the necessary ocsp information +/** + * Try to fetch the necessary ocsp information */ -static void -fetch_ocsp(void) +static void fetch_ocsp(void) { - ocsp_location_t *location; + ocsp_location_t *location; - lock_ocsp_fetch_list("fetch_ocsp"); - location = ocsp_fetch_reqs; + 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; - } + /* 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"); + unlock_ocsp_fetch_list("fetch_ocsp"); } -static void* -fetch_thread(void *arg) +static void* fetch_thread(void *arg) { - struct timespec wait_interval; + struct timespec wait_interval; - DBG(DBG_CONTROL, - DBG_log("fetch thread started") - ) + DBG(DBG_CONTROL, + DBG_log("fetch thread started") + ) - pthread_mutex_lock(&fetch_wake_mutex); + pthread_mutex_lock(&fetch_wake_mutex); - while(1) - { - int status; + while(1) + { + int status; - wait_interval.tv_nsec = 0; - wait_interval.tv_sec = time(NULL) + crl_check_interval; + 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) - ) - status = pthread_cond_timedwait(&fetch_wake_cond, &fetch_wake_mutex - , &wait_interval); + DBG(DBG_CONTROL, + DBG_log("next regular crl check in %ld seconds", crl_check_interval) + ) + status = pthread_cond_timedwait(&fetch_wake_cond, &fetch_wake_mutex + , &wait_interval); - 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") - ) + 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); } - fetch_ocsp(); - fetch_crls(cache_crls); - } } #endif /* THREADS*/ -/* - * initializes curl and starts the fetching thread +/** + * Initializes curl and starts the fetching thread */ -void -init_fetch(void) +void init_fetch(void) { -#if defined(LIBCURL) || defined (THREADS) - int status; -#endif - -#ifdef LIBCURL - /* init curl */ - status = curl_global_init(CURL_GLOBAL_NOTHING); - if (status != CURLE_OK) - { - plog("libcurl could not be initialized, status = %d", status); - } -#endif /* LIBCURL */ - - if (crl_check_interval > 0) - { -#ifdef THREADS - status = pthread_create( &thread, NULL, fetch_thread, NULL); - if (status != 0) + if (crl_check_interval > 0) { - plog("fetching thread could not be started, status = %d", status); - } +#ifdef THREADS + int status = pthread_create( &thread, NULL, fetch_thread, NULL); + + if (status != 0) + { + plog("fetching thread could not be started, status = %d", status); + } #else /* !THREADS */ - plog("warning: not compiled with pthread support"); + plog("warning: not compiled with pthread support"); #endif /* !THREADS */ - } + } } -void -free_crl_fetch(void) +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"); - -#ifdef LIBCURL - if (crl_check_interval > 0) - { - /* cleanup curl */ - curl_global_cleanup(); - } -#endif /* LIBCURL */ + 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 +/** + * Free the chained list of ocsp requests */ -void -free_ocsp_fetch(void) +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"); + lock_ocsp_fetch_list("free_ocsp_fetch"); + free_ocsp_locations(&ocsp_fetch_reqs); + unlock_ocsp_fetch_list("free_ocsp_fetch"); } -/* - * add additional distribution points +/** + * Add additional distribution points */ -void -add_distribution_points(const generalName_t *newPoints ,generalName_t **distributionPoints) +void add_distribution_points(const generalName_t *newPoints ,generalName_t **distributionPoints) { - while (newPoints != NULL) - { - /* skip empty distribution point */ - if (newPoints->name.len > 0) - { - bool add = TRUE; - generalName_t *gn = *distributionPoints; - - while (gn != NULL) - { - if (gn->kind == newPoints->kind - && gn->name.len == newPoints->name.len - && memcmp(gn->name.ptr, newPoints->name.ptr, gn->name.len) == 0) - { - /* skip if the distribution point is already present */ - add = FALSE; - break; - } - gn = gn->next; - } - - if (add) - { - /* clone additional distribution point */ - gn = clone_thing(*newPoints, "generalName"); - clonetochunk(gn->name, newPoints->name.ptr, newPoints->name.len - , "crl uri"); - - /* insert additional CRL distribution point */ - gn->next = *distributionPoints; - *distributionPoints = gn; - } + while (newPoints != NULL) + { + /* skip empty distribution point */ + if (newPoints->name.len > 0) + { + bool add = TRUE; + generalName_t *gn = *distributionPoints; + + while (gn != NULL) + { + if (gn->kind == newPoints->kind + && gn->name.len == newPoints->name.len + && memeq(gn->name.ptr, newPoints->name.ptr, gn->name.len)) + { + /* skip if the distribution point is already present */ + add = FALSE; + break; + } + gn = gn->next; + } + + if (add) + { + /* clone additional distribution point */ + gn = clone_thing(*newPoints); + gn->name = chunk_clone(newPoints->name); + + /* insert additional CRL distribution point */ + gn->next = *distributionPoints; + *distributionPoints = gn; + } + } + newPoints = newPoints->next; } - newPoints = newPoints->next; - } } -fetch_req_t* -build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber -, chunk_t authKeyID, const generalName_t *gn) +fetch_req_t* build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber, + chunk_t authKeyID, const generalName_t *gn) { - fetch_req_t *req = alloc_thing(fetch_req_t, "fetch request"); - *req = empty_fetch_req; - - /* note current time */ - req->installed = time(NULL); - - /* clone fields */ - clonetochunk(req->issuer, issuer.ptr, issuer.len, "issuer"); - if (authKeySerialNumber.ptr != NULL) - { - clonetochunk(req->authKeySerialNumber, authKeySerialNumber.ptr - , authKeySerialNumber.len, "authKeySerialNumber"); - } - if (authKeyID.ptr != NULL) - { - clonetochunk(req->authKeyID, authKeyID.ptr, authKeyID.len, "authKeyID"); - } - - /* copy distribution points */ - add_distribution_points(gn, &req->distributionPoints); - - return req; + fetch_req_t *req = malloc_thing(fetch_req_t); + *req = empty_fetch_req; + + /* note current time */ + req->installed = time(NULL); + + /* clone fields */ + req->issuer = chunk_clone(issuer); + req->authKeySerialNumber = chunk_clone(authKeySerialNumber); + req->authKeyID = chunk_clone(authKeyID); + + /* copy distribution points */ + add_distribution_points(gn, &req->distributionPoints); + + return req; } -/* - * add a crl fetch request to the chained list +/** + * Add a crl fetch request to the chained list */ -void -add_crl_fetch_request(fetch_req_t *req) +void add_crl_fetch_request(fetch_req_t *req) { - fetch_req_t *r; + fetch_req_t *r; - lock_crl_fetch_list("add_crl_fetch_request"); - r = crl_fetch_reqs; + lock_crl_fetch_list("add_crl_fetch_request"); + r = crl_fetch_reqs; - while (r != NULL) - { - if ((req->authKeyID.ptr != NULL)? same_keyid(req->authKeyID, r->authKeyID) - : (same_dn(req->issuer, r->issuer) - && same_serial(req->authKeySerialNumber, r->authKeySerialNumber))) + while (r != NULL) { - /* there is already a fetch request */ - DBG(DBG_CONTROL, - DBG_log("crl fetch request already exists") - ) + if ((req->authKeyID.ptr != NULL)? same_keyid(req->authKeyID, r->authKeyID) + : (same_dn(req->issuer, r->issuer) + && same_serial(req->authKeySerialNumber, r->authKeySerialNumber))) + { + /* 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(req->distributionPoints, &r->distributionPoints); + /* there might be new distribution points */ + add_distribution_points(req->distributionPoints, &r->distributionPoints); - unlock_crl_fetch_list("add_crl_fetch_request"); - free_fetch_request(req); - return; + unlock_crl_fetch_list("add_crl_fetch_request"); + free_fetch_request(req); + return; + } + r = r->next; } - r = r->next; - } - /* insert new fetch request at the head of the queue */ - req->next = crl_fetch_reqs; - crl_fetch_reqs = req; + /* 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"); + 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 +/** + * Add an ocsp fetch request to the chained list */ -void -add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber) +void add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber) { - ocsp_certinfo_t certinfo; + ocsp_certinfo_t certinfo; - certinfo.serialNumber = serialNumber; + 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"); + 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 +/** + * List all distribution points */ -void -list_distribution_points(const generalName_t *gn) +void list_distribution_points(const generalName_t *gn) { - bool first_gn = TRUE; - - while (gn != NULL) - { - whack_log(RC_COMMENT, " %s '%.*s'", (first_gn)? "distPts: " - :" ", (int)gn->name.len, gn->name.ptr); - first_gn = FALSE; - gn = gn->next; - } + bool first_gn = TRUE; + + while (gn != NULL) + { + whack_log(RC_COMMENT, " %s '%.*s'", (first_gn)? "distPts: " + :" ", (int)gn->name.len, gn->name.ptr); + first_gn = FALSE; + gn = gn->next; + } } -/* - * list all fetch requests in the chained list +/** + * List all fetch requests in the chained list */ -void -list_crl_fetch_requests(bool utc) +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:"); - whack_log(RC_COMMENT, " "); - } - - while (req != NULL) - { - u_char buf[BUF_LEN]; - - whack_log(RC_COMMENT, "%s, trials: %d" - , timetoa(&req->installed, utc), req->trials); - dntoa(buf, BUF_LEN, req->issuer); - whack_log(RC_COMMENT, " issuer: '%s'", buf); - if (req->authKeyID.ptr != NULL) + fetch_req_t *req; + + lock_crl_fetch_list("list_crl_fetch_requests"); + req = crl_fetch_reqs; + + if (req != NULL) { - datatot(req->authKeyID.ptr, req->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of CRL fetch requests:"); + whack_log(RC_COMMENT, " "); } - if (req->authKeySerialNumber.ptr != NULL) + + while (req != NULL) { - datatot(req->authKeySerialNumber.ptr, req->authKeySerialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); + u_char buf[BUF_LEN]; + + whack_log(RC_COMMENT, "%T, trials: %d" + , &req->installed, utc, req->trials); + dntoa(buf, BUF_LEN, req->issuer); + whack_log(RC_COMMENT, " issuer: '%s'", buf); + if (req->authKeyID.ptr != NULL) + { + datatot(req->authKeyID.ptr, req->authKeyID.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " authkey: %s", buf); + } + if (req->authKeySerialNumber.ptr != NULL) + { + datatot(req->authKeySerialNumber.ptr, req->authKeySerialNumber.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " aserial: %s", buf); + } + list_distribution_points(req->distributionPoints); + req = req->next; } - list_distribution_points(req->distributionPoints); - req = req->next; - } - unlock_crl_fetch_list("list_crl_fetch_requests"); + unlock_crl_fetch_list("list_crl_fetch_requests"); } -void -list_ocsp_fetch_requests(bool utc) +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"); + 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 index 67be12d47..f7b4eb074 100644 --- a/src/pluto/fetch.h +++ b/src/pluto/fetch.h @@ -11,31 +11,29 @@ * 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. - * - * RCSID $Id: fetch.h 3252 2007-10-06 21:24:50Z andreas $ */ #include "x509.h" -#define FETCH_CMD_TIMEOUT 10 /* seconds */ +#define FETCH_CMD_TIMEOUT 10 /* seconds */ -struct ocsp_location; /* forward declaration of ocsp_location defined in ocsp.h */ +struct ocsp_location; /* forward declaration of ocsp_location defined in ocsp.h */ typedef enum { - FETCH_GET = 1, - FETCH_POST = 2 + FETCH_GET = 1, + FETCH_POST = 2 } fetch_request_t; typedef struct fetch_req fetch_req_t; struct fetch_req { - fetch_req_t *next; - time_t installed; - int trials; - chunk_t issuer; - chunk_t authKeyID; - chunk_t authKeySerialNumber; - generalName_t *distributionPoints; + fetch_req_t *next; + time_t installed; + int trials; + chunk_t issuer; + chunk_t authKeyID; + chunk_t authKeySerialNumber; + generalName_t *distributionPoints; }; #ifdef THREADS @@ -67,9 +65,9 @@ extern void init_fetch(void); extern void free_crl_fetch(void); extern void free_ocsp_fetch(void); extern void add_distribution_points(const generalName_t *newPoints - , generalName_t **distributionPoints); + , generalName_t **distributionPoints); extern fetch_req_t* build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber - , chunk_t authKeyID, const generalName_t *gn); + , chunk_t authKeyID, const generalName_t *gn); 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(const generalName_t *gn); diff --git a/src/pluto/foodgroups.c b/src/pluto/foodgroups.c index 5b2836bce..ed9853fc4 100644 --- a/src/pluto/foodgroups.c +++ b/src/pluto/foodgroups.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: foodgroups.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <string.h> @@ -49,8 +47,8 @@ static size_t fg_path_space = 0; */ struct fg_groups { - struct fg_groups *next; - struct connection *connection; + struct fg_groups *next; + struct connection *connection; }; static struct fg_groups *groups = NULL; @@ -66,10 +64,10 @@ static struct fg_groups *groups = NULL; */ struct fg_targets { - struct fg_targets *next; - struct fg_groups *group; - ip_subnet subnet; - char *name; /* name of instance of group conn */ + 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; @@ -83,24 +81,24 @@ struct fg_targets *new_targets; 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; - } + 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. @@ -110,353 +108,353 @@ ipcmp(ip_address *a, ip_address *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; + 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) - { - pfreeany(fg_path); - fg_path_space = plen + 10; - fg_path = alloc_bytes(fg_path_space, "policy group path"); - } - 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 (;;) + 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 { - switch (flp->bdry) - { - case B_none: + plog("loading group \"%s\"", fg_path); + for (;;) { - /* !!! 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) + switch (flp->bdry) { - 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); + 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 */ } - else - { - struct fg_targets *f = alloc_thing(struct fg_targets, "fg_target"); - - f->next = *pp; - f->group = g; - f->subnet = sn; - f->name = NULL; - *pp = f; - } - } + break; /* if we reach here, out of loop */ } - (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(); } - lexclose(); - } } static void free_targets(void) { - while (targets != NULL) - { - struct fg_targets *t = targets; - - targets = t->next; - pfreeany(t->name); - pfree(t); - } + while (targets != NULL) + { + struct fg_targets *t = targets; + + targets = t->next; + free(t->name); + free(t); + } } void load_groups(void) { - passert(new_targets == NULL); + passert(new_targets == NULL); - /* for each group, add config file targets into new_targets */ - { - struct fg_groups *g; + /* 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); - } + 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) + /* dump new_targets */ + DBG(DBG_CONTROL, { - remove_group_instance(op->group->connection, op->name); - op = op->next; - } - if (r >= 0) + 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) { - np->name = add_group_instance(np->group->connection, &np->subnet); - np = np->next; + 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; } - 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(struct connection *c) { - struct fg_groups *g = alloc_thing(struct fg_groups, "policy group"); + struct fg_groups *g = malloc_thing(struct fg_groups); - g->next = groups; - groups = g; + g->next = groups; + groups = g; - g->connection = c; + g->connection = c; } static struct fg_groups * find_group(const struct connection *c) { - struct fg_groups *g; + struct fg_groups *g; - for (g = groups; g != NULL && g->connection != c; g = g->next) - ; - return g; + for (g = groups; g != NULL && g->connection != c; g = g->next) + ; + return g; } void route_group(struct connection *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) + /* 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 { - if (t->group == g) - { - struct connection *ci = con_by_name(t->name, FALSE); + struct fg_groups *g = find_group(c); + struct fg_targets *t; - if (ci != NULL) + passert(g != NULL); + g->connection->policy |= POLICY_GROUTED; + for (t = targets; t != NULL; t = t->next) { - set_cur_connection(ci); - if (!trap_connection(ci)) - whack_log(RC_ROUTE, "could not route"); - set_cur_connection(c); + if (t->group == g) + { + struct connection *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(struct connection *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) + 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) { - struct connection *ci = con_by_name(t->name, FALSE); - - if (ci != NULL) - { - set_cur_connection(ci); - unroute_connection(ci); - set_cur_connection(c); - } + if (t->group == g) + { + struct connection *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 struct connection *c) { - struct fg_groups *g; - - /* find and remove from groups */ - { - struct fg_groups **pp; + struct fg_groups *g; - for (pp = &groups; (g = *pp)->connection != c; pp = &(*pp)->next) - ; + /* find and remove from groups */ + { + struct fg_groups **pp; - *pp = g->next; - } + for (pp = &groups; (g = *pp)->connection != c; pp = &(*pp)->next) + ; - /* find and remove from targets */ - { - struct fg_targets **pp; + *pp = g->next; + } - for (pp = &targets; *pp != NULL; ) + /* find and remove from targets */ { - struct fg_targets *t = *pp; - - if (t->group == g) - { - *pp = t->next; - remove_group_instance(t->group->connection, t->name); - pfree(t); - /* pp is ready for next iteration */ - } - else - { - pp = &t->next; - } + 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; + } + } } - } - pfree(g); + free(g); } diff --git a/src/pluto/foodgroups.h b/src/pluto/foodgroups.h index d66f85423..b6d3386ae 100644 --- a/src/pluto/foodgroups.h +++ b/src/pluto/foodgroups.h @@ -10,11 +10,9 @@ * 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. - * - * RCSID $Id: foodgroups.h 3252 2007-10-06 21:24:50Z andreas $ */ -struct connection; /* forward declaration */ +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); diff --git a/src/pluto/gcryptfix.c b/src/pluto/gcryptfix.c deleted file mode 100644 index b8007046d..000000000 --- a/src/pluto/gcryptfix.c +++ /dev/null @@ -1,283 +0,0 @@ -/* Routines to make gcrypt routines feel at home in Pluto. - * Copyright (C) 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. - * - * RCSID $Id: gcryptfix.c 3252 2007-10-06 21:24:50Z andreas $ - */ - -#include <stdlib.h> - -#include <gmp.h> -#include <freeswan.h> -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "rnd.h" -#include "gcryptfix.h" /* includes <gmp.h> "defs.h" "rnd.h" */ - -MPI -mpi_alloc( unsigned nlimbs UNUSED ) -{ - MPI n = alloc_bytes(sizeof *n, "mpi_alloc"); - - mpz_init(n); - return n; -} - -MPI -mpi_alloc_secure( unsigned nlimbs ) -{ - return mpi_alloc(nlimbs); -} - -MPI -mpi_alloc_set_ui( unsigned long u) -{ - MPI n = alloc_bytes(sizeof *n, "mpi_copy"); - - mpz_init_set_ui(n, u); - return n; -} - -MPI -mpi_copy( MPI a ) -{ - MPI n = alloc_bytes(sizeof *n, "mpi_copy"); - - mpz_init_set(n, a); - return n; -} - -void -mpi_free( MPI a ) -{ - mpz_clear(a); - pfree(a); -} - -int -mpi_divisible_ui(MPI dividend, ulong divisor ) -{ - ulong rem; - mpz_t remtoo; - - mpz_init(remtoo); - rem = mpz_mod_ui(remtoo, dividend, divisor); - mpz_clear(remtoo); - return rem == 0; -} - -unsigned -mpi_trailing_zeros( MPI a ) -{ - return mpz_scan1(a, 0); -} - -unsigned -mpi_get_nbits( MPI a ) -{ - return mpz_sizeinbase(a, 2); -} - -int -mpi_test_bit( MPI a, unsigned n ) -{ - /* inspired by gmp/mpz/clrbit.c */ - mp_size_t li = n / mp_bits_per_limb; - - if (li >= a->_mp_size) - return 0; - return (a->_mp_d[li] & ((mp_limb_t) 1 << (n % mp_bits_per_limb))) != 0; -} - -void -mpi_set_bit( MPI a, unsigned n ) -{ - mpz_setbit(a, n); -} - -void -mpi_clear_bit( MPI a, unsigned n ) -{ - mpz_clrbit(a, n); -} - -void -mpi_clear_highbit( MPI a, unsigned n ) -{ - /* This seems whacky, but what do I know. */ - mpz_fdiv_r_2exp(a, a, n); -} - -void -mpi_set_highbit( MPI a, unsigned n ) -{ - /* This seems whacky, but what do I know. */ - mpz_fdiv_r_2exp(a, a, n+1); - mpz_setbit(a, n); -} - -void -mpi_set_buffer( MPI a, const u_char *buffer, unsigned nbytes, int sign ) -{ - /* this is a lot like n_to_mpz */ - size_t i; - - passert(sign == 0); /* we won't hit any negative numbers */ - mpz_init_set_ui(a, 0); - - for (i = 0; i != nbytes; i++) - { - mpz_mul_ui(a, a, 1 << BITS_PER_BYTE); - mpz_add_ui(a, a, buffer[i]); - } -} - -u_char * -get_random_bits(size_t nbits, int level UNUSED, int secure UNUSED) -{ - size_t nbytes = (nbits+7)/8; - u_char *b = alloc_bytes(nbytes, "random bytes"); - - get_rnd_bytes(b, nbytes); - return b; -} -/**************** from gnupg-1.0.0/mpi/mpi-mpow.c - * RES = (BASE[0] ^ EXP[0]) * (BASE[1] ^ EXP[1]) * ... * mod M - */ -#define barrett_mulm( w, u, v, m, y, k, r1, r2 ) mpi_mulm( (w), (u), (v), (m) ) - -static int -build_index( MPI *exparray, int k, int i, int t ) -{ - int j, bitno; - int index = 0; - - bitno = t-i; - for(j=k-1; j >= 0; j-- ) { - index <<= 1; - if( mpi_test_bit( exparray[j], bitno ) ) - index |= 1; - } - /*log_debug("t=%d i=%d index=%d\n", t, i, index );*/ - return index; -} - -void -mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m) -{ - int k; /* number of elements */ - int t; /* bit size of largest exponent */ - int i, j, idx; - MPI *G; /* table with precomputed values of size 2^k */ - MPI tmp; - #ifdef USE_BARRETT - MPI barrett_y, barrett_r1, barrett_r2; - int barrett_k; - #endif - - for(k=0; basearray[k]; k++ ) - ; - passert(k); - for(t=0, i=0; (tmp=exparray[i]); i++ ) { - /*log_mpidump("exp: ", tmp );*/ - j = mpi_get_nbits(tmp); - if( j > t ) - t = j; - } - /*log_mpidump("mod: ", m );*/ - passert(i==k); - passert(t); - passert( k < 10 ); - -#ifdef PLUTO - m_alloc_ptrs_clear(G, 1<<k); -#else - G = m_alloc_clear( (1<<k) * sizeof *G ); -#endif - - #ifdef USE_BARRETT - barrett_y = init_barrett( m, &barrett_k, &barrett_r1, &barrett_r2 ); - #endif - /* and calculate */ - tmp = mpi_alloc( mpi_get_nlimbs(m)+1 ); - mpi_set_ui( res, 1 ); - for(i = 1; i <= t; i++ ) { - barrett_mulm(tmp, res, res, m, barrett_y, barrett_k, - barrett_r1, barrett_r2 ); - idx = build_index( exparray, k, i, t ); - passert( idx >= 0 && idx < (1<<k) ); - if( !G[idx] ) { - if( !idx ) - G[0] = mpi_alloc_set_ui( 1 ); - else { - for(j=0; j < k; j++ ) { - if( (idx & (1<<j) ) ) { - if( !G[idx] ) - G[idx] = mpi_copy( basearray[j] ); - else - barrett_mulm( G[idx], G[idx], basearray[j], - m, barrett_y, barrett_k, barrett_r1, barrett_r2 ); - } - } - if( !G[idx] ) - G[idx] = mpi_alloc(0); - } - } - barrett_mulm(res, tmp, G[idx], m, barrett_y, barrett_k, barrett_r1, barrett_r2 ); - } - - /* cleanup */ - mpi_free(tmp); - #ifdef USE_BARRETT - mpi_free(barrett_y); - mpi_free(barrett_r1); - mpi_free(barrett_r2); - #endif - for(i=0; i < (1<<k); i++ ) - mpi_free(G[i]); - m_free(G); -} - -void -log_mpidump( const char *text UNUSED, MPI a ) -{ - /* Print number in hex -- helpful to see if they match bytes. - * Humans are not going to do arithmetic with the large numbers! - * Much code adapted from mpz_to_n. - */ - u_char buf[8048]; /* this ought to be big enough */ - size_t len = (mpz_sizeinbase(a, 16) + 1) / 2; /* bytes */ - MP_INT temp1, temp2; - int i; - - passert(len <= sizeof(buf)); - - mpz_init(&temp1); - mpz_init(&temp2); - - mpz_set(&temp1, a); - - for (i = len-1; i >= 0; i--) - { - buf[i] = mpz_mdivmod_ui(&temp2, NULL, &temp1, 1 << BITS_PER_BYTE); - mpz_set(&temp1, &temp2); - } - - passert(mpz_sgn(&temp1) == 0); /* we must have done all the bits */ - mpz_clear(&temp1); - mpz_clear(&temp2); - -#ifdef DEBUG - DBG_dump(text, buf, len); -#endif /* DEBUG */ -} diff --git a/src/pluto/gcryptfix.h b/src/pluto/gcryptfix.h deleted file mode 100644 index db2587c59..000000000 --- a/src/pluto/gcryptfix.h +++ /dev/null @@ -1,111 +0,0 @@ -/* Definitions to make gcrypt routines feel at home in Pluto. - * Copyright (C) 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. - * - * RCSID $Id: gcryptfix.h 3252 2007-10-06 21:24:50Z andreas $ - */ - -#define DBG_CIPHER 1 /* some day we'll do this right */ - -/* Simulate MPI routines with gmp routines. - * gmp's MP_INT is a stuct; MPI's MPI is a pointer to an analogous struct. - * gmp's mpz_t is an array of one of these structs to enable magic pointer - * conversions to make the notation convenient (but confusing). - */ -typedef u_char byte; -typedef MP_INT *MPI; - -#define BITS_PER_MPI_LIMB mp_bits_per_limb - -extern MPI mpi_alloc( unsigned nlimbs ); -extern MPI mpi_alloc_secure( unsigned nlimbs ); -#define mpi_alloc_like(n) mpi_alloc(mpi_get_nlimbs(n)) -extern MPI mpi_alloc_set_ui( unsigned long u); -#define mpi_set_ui(w, u) mpz_set_ui(w, u) -#define mpi_set(w, u) mpz_set(w, u) -extern void mpi_free( MPI a ); -extern MPI mpi_copy( MPI a ); -extern unsigned mpi_get_nbits( MPI a ); -#define mpi_get_nlimbs(a) ((a)->_mp_alloc) /* dirty, but useless */ -extern void mpi_set_buffer( MPI a, const u_char *buffer, unsigned nbytes, int sign ); -extern unsigned mpi_trailing_zeros( MPI a ); -extern int mpi_test_bit( MPI a, unsigned n ); -extern void mpi_set_bit( MPI a, unsigned n ); -extern void mpi_clear_bit( MPI a, unsigned n ); -extern void mpi_clear_highbit( MPI a, unsigned n ); -extern void mpi_set_highbit( MPI a, unsigned n ); -#define mpi_cmp_ui(u, v) mpz_cmp_ui((u), (v)) -#define mpi_cmp(u, v) mpz_cmp((u), (v)) -#define mpi_is_neg(n) (mpz_sgn(n) < 0) -#define mpi_add(w, u, v) mpz_add((w), (u), (v)) -#define mpi_add_ui(w, u, v) mpz_add_ui((w), (u), (v)) -#define mpi_sub_ui(w, u, v) mpz_sub_ui((w), (u), (v)) -#define mpi_subm( w, u, v, m) { mpz_sub( (w), (u), (v)) ; mpz_fdiv_r((w), (w), (m)); } -#define mpi_mul( w, u, v) mpz_mul( (w), (u), (v)) -#define mpi_mul_ui( w, u, v) mpz_mul_ui( (w), (u), (v)) -#define mpi_mulm( w, u, v, m) { mpz_mul( (w), (u), (v)) ; mpz_fdiv_r((w), (w), (m)); } -#define mpi_fdiv_q(quot, dividend, divisor) mpz_fdiv_q((quot), (dividend), (divisor)) -#define mpi_fdiv_r( rem, dividend, divisor ) mpz_fdiv_r( (rem), (dividend), (divisor) ) -#define mpi_fdiv_r_ui( rem, dividend, divisor ) mpz_fdiv_r_ui( (rem), (dividend), (divisor) ) -#define mpi_tdiv_q_2exp( w, u, count ) mpz_tdiv_q_2exp( (w), (u), (count) ) -extern int mpi_divisible_ui(MPI dividend, ulong divisor ); -#define mpi_powm( res, base, exp, mod) mpz_powm( res, base, exp, mod) -extern void mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI mod); -#define mpi_gcd( g, a, b ) ( mpz_gcd( (g), (a), (b) ), !mpi_cmp_ui( (g), 1)) -#define mpi_invm( x, a, n ) mpz_invert( (x), (a), (n) ) - -#ifdef DEBUG -# define log_debug(f...) DBG_log(f) -#else -# define log_debug(f...) do ; while (0) /* do nothing, carefully */ -#endif -#define log_fatal(f...) exit_log(f) /* overreaction? */ -extern void log_mpidump( const char *text, MPI a ); - -#define assert(p) passert(p) -#define BUG() passert(FALSE) - -#define m_alloc_ptrs_clear(pp, n) { \ - int c = (n); \ - (pp) = alloc_bytes((n) * sizeof(*(pp)), "m_alloc_ptrs_clear"); \ - while (c > 0) (pp)[--c] = NULL; \ - } - -extern u_char *get_random_bits(size_t nbits, int level, int secure); -#define m_alloc(sz) alloc_bytes((sz), "m_alloc") /* not initialized */ -#define m_free(n) pfree(n) /* always freeing something from get_random_bits */ - -/* declarations from gnupg-1.0.0/include/cipher.h */ -/*-- primegen.c --*/ -MPI generate_secret_prime( unsigned nbits ); -MPI generate_public_prime( unsigned nbits ); -MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits, - MPI g, MPI **factors ); - -#define PUBKEY_ALGO_ELGAMAL_E 16 /* encrypt only ElGamal (but not for v3)*/ -#define PUBKEY_ALGO_DSA 17 -#define PUBKEY_ALGO_ELGAMAL 20 /* sign and encrypt elgamal */ - -#define is_ELGAMAL(a) ((a)==PUBKEY_ALGO_ELGAMAL || (a)==PUBKEY_ALGO_ELGAMAL_E) - -#define PUBKEY_USAGE_SIG 1 /* key is good for signatures */ -#define PUBKEY_USAGE_ENC 2 /* key is good for encryption */ - -/* from gnupg-1.0.0/include/errors.h */ - -#define G10ERR_PUBKEY_ALGO 4 /* Unknown pubkey algorithm */ -#define G10ERR_BAD_SECKEY 7 /* Bad secret key */ -#define G10ERR_BAD_SIGN 8 /* Bad signature */ -#define G10ERR_BAD_MPI 30 - -/*-- smallprime.c --*/ -extern ushort small_prime_numbers[]; diff --git a/src/pluto/id.c b/src/pluto/id.c index 8db322a5e..f34775e68 100644 --- a/src/pluto/id.c +++ b/src/pluto/id.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: id.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdlib.h> @@ -22,13 +20,12 @@ #include <netinet/in.h> #include <arpa/inet.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 */ +#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 <sys/queue.h> #include <freeswan.h> -#include <ipsec_policy.h> #include "constants.h" #include "defs.h" @@ -38,10 +35,10 @@ #include "packet.h" #include "whack.h" -const struct id empty_id; /* ID_NONE */ +const struct id empty_id; /* ID_ANY */ enum myid_state myid_state = MYID_UNKNOWN; -struct id myids[MYID_SPECIFIED+1]; /* %myid */ +struct id myids[MYID_SPECIFIED+1]; /* %myid */ char *myid_str[MYID_SPECIFIED+1]; /* string form of IDs */ /* initialize id module @@ -50,100 +47,117 @@ char *myid_str[MYID_SPECIFIED+1]; /* string form of IDs */ void init_id(void) { - passert(empty_id.kind == ID_NONE); - myid_state = MYID_UNKNOWN; - { + passert(empty_id.kind == ID_ANY); + myid_state = MYID_UNKNOWN; + { + enum myid_state s; + + for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++) + { + myids[s] = empty_id; + myid_str[s] = NULL; + } + } + set_myid(MYID_SPECIFIED, getenv("IPSECmyid")); + set_myid(MYID_IP, getenv("defaultrouteaddr")); + set_myFQDN(); +} + +/* + * free id module + */ +void +free_id(void) +{ enum myid_state s; for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++) { - myids[s] = empty_id; - myid_str[s] = NULL; + free_id_content(&myids[s]); + free(myid_str[s]); } - } - set_myid(MYID_SPECIFIED, getenv("IPSECmyid")); - set_myid(MYID_IP, getenv("defaultrouteaddr")); - set_myFQDN(); } static void calc_myid_str(enum myid_state s) { - /* preformat the ID name */ - char buf[BUF_LEN]; + /* preformat the ID name */ + char buf[BUF_LEN]; - idtoa(&myids[s], buf, BUF_LEN); - replace(myid_str[s], clone_str(buf, "myid string")); + idtoa(&myids[s], buf, BUF_LEN); + replace(myid_str[s], clone_str(buf)); } void set_myid(enum myid_state s, char *idstr) { - if (idstr != NULL) - { - struct id id; - err_t ugh = atoid(idstr, &id, FALSE); - - if (ugh != NULL) - { - loglog(RC_BADID, "myid malformed: %s \"%s\"", ugh, idstr); - } - else + if (idstr != NULL) { - free_id_content(&myids[s]); - unshare_id_content(&id); - myids[s] = id; - if (s == MYID_SPECIFIED) - myid_state = MYID_SPECIFIED; - - calc_myid_str(s); + struct id id; + err_t ugh = atoid(idstr, &id, FALSE); + + if (ugh != NULL) + { + loglog(RC_BADID, "myid malformed: %s \"%s\"", ugh, idstr); + } + else + { + free_id_content(&myids[s]); + unshare_id_content(&id); + myids[s] = id; + if (s == MYID_SPECIFIED) + myid_state = MYID_SPECIFIED; + + calc_myid_str(s); + } } - } } void set_myFQDN(void) { - char FQDN[HOST_NAME_MAX + 1]; - int r = gethostname(FQDN, sizeof(FQDN)); - - free_id_content(&myids[MYID_HOSTNAME]); - myids[MYID_HOSTNAME] = empty_id; - if (r != 0) - { - log_errno((e, "gethostname() failed in set_myFQDN")); - } - else - { - FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */ + char FQDN[HOST_NAME_MAX + 1]; + int r = gethostname(FQDN, sizeof(FQDN)); + free_id_content(&myids[MYID_HOSTNAME]); + myids[MYID_HOSTNAME] = empty_id; + if (r != 0) { - size_t len = strlen(FQDN); - - if (len > 0 && FQDN[len-1] == '.') - { - /* nuke trailing . */ - FQDN[len-1]='\0'; - } + log_errno((e, "gethostname() failed in set_myFQDN")); } - - if (!strcaseeq(FQDN, "localhost.localdomain")) + else { - clonetochunk(myids[MYID_HOSTNAME].name, FQDN, strlen(FQDN), "my FQDN"); - myids[MYID_HOSTNAME].kind = ID_FQDN; - calc_myid_str(MYID_HOSTNAME); + FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */ + + { + size_t len = strlen(FQDN); + + if (len > 0 && FQDN[len-1] == '.') + { + /* nuke trailing . */ + FQDN[len-1]='\0'; + } + } + + if (!strcaseeq(FQDN, "localhost.localdomain")) + { + chunk_t myid_name = { FQDN, strlen(FQDN) }; + + myids[MYID_HOSTNAME].name = chunk_clone(myid_name); + myids[MYID_HOSTNAME].kind = ID_FQDN; + calc_myid_str(MYID_HOSTNAME); + } } - } } void show_myid_status(void) { - char idstr[BUF_LEN]; + char idstr[BUF_LEN]; - (void)idtoa(&myids[myid_state], idstr, sizeof(idstr)); - whack_log(RC_COMMENT, "%%myid = %s", idstr); + (void)idtoa(&myids[myid_state], idstr, sizeof(idstr)); + whack_log(RC_COMMENT, "%%myid = %s", idstr); } /* Convert textual form of id into a (temporary) struct id. @@ -152,86 +166,86 @@ show_myid_status(void) err_t atoid(char *src, struct id *id, bool myid_ok) { - err_t ugh = NULL; - - *id = empty_id; - - if (myid_ok && streq("%myid", src)) - { - id->kind = ID_MYID; - } - else if (strchr(src, '=') != NULL) - { - /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN */ - id->kind = ID_DER_ASN1_DN; - id->name.ptr = temporary_cyclic_buffer(); /* assign temporary buffer */ - id->name.len = 0; - /* convert from LDAP style or openssl x509 -subject style to ASN.1 DN - * discard optional @ character in front of DN - */ - ugh = atodn((*src == '@')?src+1:src, &id->name); - } - else if (strchr(src, '@') == NULL) - { - if (streq(src, "%any") || streq(src, "0.0.0.0")) + err_t ugh = NULL; + + *id = empty_id; + + if (myid_ok && streq("%myid", src)) { - /* any ID will be accepted */ - id->kind = ID_NONE; + id->kind = ID_MYID; } - else + else if (strchr(src, '=') != NULL) { - /* !!! 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(src, ':') == NULL - ? &af_inet4_info: &af_inet6_info; - - id->kind = afi->id_addr; - ugh = ttoaddr(src, 0, afi->af, &id->ip_addr); + /* we interpret this as an ASCII X.501 ID_DER_ASN1_DN */ + id->kind = ID_DER_ASN1_DN; + id->name.ptr = temporary_cyclic_buffer(); /* assign temporary buffer */ + id->name.len = 0; + /* convert from LDAP style or openssl x509 -subject style to ASN.1 DN + * discard optional @ character in front of DN + */ + ugh = atodn((*src == '@')?src+1:src, &id->name); } - } - else - { - if (*src == '@') + else if (strchr(src, '@') == NULL) { - if (*(src+1) == '#') - { - /* if there is a second specifier (#) on the line - * we interprete this as ID_KEY_ID - */ - id->kind = ID_KEY_ID; - id->name.ptr = src; - /* discard @~, convert from hex to bin */ - ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len); - } - else if (*(src+1) == '~') - { - /* if there is a second specifier (~) on the line - * we interprete this as a binary ID_DER_ASN1_DN - */ - id->kind = ID_DER_ASN1_DN; - id->name.ptr = src; - /* discard @~, convert from hex to bin */ - ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len); - } - else - { - id->kind = ID_FQDN; - id->name.ptr = src+1; /* discard @ */ - id->name.len = strlen(src)-1; - } + if (streq(src, "%any") || streq(src, "0.0.0.0")) + { + /* any ID will be accepted */ + id->kind = ID_ANY; + } + else + { + /* !!! 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(src, ':') == NULL + ? &af_inet4_info: &af_inet6_info; + + id->kind = afi->id_addr; + ugh = ttoaddr(src, 0, afi->af, &id->ip_addr); + } } else { - /* We leave in @, as per DOI 4.6.2.4 - * (but DNS wants . instead). - */ - id->kind = ID_USER_FQDN; - id->name.ptr = src; - id->name.len = strlen(src); + if (*src == '@') + { + if (*(src+1) == '#') + { + /* if there is a second specifier (#) on the line + * we interprete this as ID_KEY_ID + */ + id->kind = ID_KEY_ID; + id->name.ptr = src; + /* discard @~, convert from hex to bin */ + ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len); + } + else if (*(src+1) == '~') + { + /* if there is a second specifier (~) on the line + * we interprete this as a binary ID_DER_ASN1_DN + */ + id->kind = ID_DER_ASN1_DN; + id->name.ptr = src; + /* discard @~, convert from hex to bin */ + ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len); + } + else + { + id->kind = ID_FQDN; + id->name.ptr = src+1; /* discard @ */ + id->name.len = strlen(src)-1; + } + } + else + { + /* We leave in @, as per DOI 4.6.2.4 + * (but DNS wants . instead). + */ + id->kind = ID_USER_FQDN; + id->name.ptr = src; + id->name.len = strlen(src); + } } - } - return ugh; + return ugh; } @@ -241,72 +255,72 @@ atoid(char *src, struct id *id, bool myid_ok) int keyidtoa(char *dst, size_t dstlen, chunk_t keyid) { - int n = datatot(keyid.ptr, keyid.len, 'x', dst, dstlen); - return (((size_t)n < dstlen)? n : dstlen) - 1; + int n = datatot(keyid.ptr, keyid.len, 'x', dst, dstlen); + return (((size_t)n < dstlen)? n : dstlen) - 1; } void iptoid(const ip_address *ip, struct id *id) { - *id = empty_id; - - switch (addrtypeof(ip)) - { - case AF_INET: - id->kind = ID_IPV4_ADDR; - break; - case AF_INET6: - id->kind = ID_IPV6_ADDR; - break; - default: - bad_case(addrtypeof(ip)); - } - id->ip_addr = *ip; + *id = empty_id; + + switch (addrtypeof(ip)) + { + case AF_INET: + id->kind = ID_IPV4_ADDR; + break; + case AF_INET6: + id->kind = ID_IPV6_ADDR; + break; + default: + bad_case(addrtypeof(ip)); + } + id->ip_addr = *ip; } int idtoa(const struct id *id, char *dst, size_t dstlen) { - int n; - - id = resolve_myid(id); - switch (id->kind) - { - case ID_NONE: - n = snprintf(dst, dstlen, "(none)"); - break; - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - n = (int)addrtot(&id->ip_addr, 0, dst, dstlen) - 1; - break; - case ID_FQDN: - n = snprintf(dst, dstlen, "@%.*s", (int)id->name.len, id->name.ptr); - break; - case ID_USER_FQDN: - n = snprintf(dst, dstlen, "%.*s", (int)id->name.len, id->name.ptr); - break; - case ID_DER_ASN1_DN: - n = dntoa(dst, dstlen, id->name); - break; - case ID_KEY_ID: - n = keyidtoa(dst, dstlen, id->name); - break; - default: - n = snprintf(dst, dstlen, "unknown id kind %d", id->kind); - break; - } - - /* "Sanitize" string so that log isn't endangered: - * replace unprintable characters with '?'. - */ - if (n > 0) - { - for ( ; *dst != '\0'; dst++) - if (!isprint(*dst)) - *dst = '?'; - } - - return n; + int n; + + id = resolve_myid(id); + switch (id->kind) + { + case ID_ANY: + n = snprintf(dst, dstlen, "(none)"); + break; + case ID_IPV4_ADDR: + case ID_IPV6_ADDR: + n = (int)addrtot(&id->ip_addr, 0, dst, dstlen) - 1; + break; + case ID_FQDN: + n = snprintf(dst, dstlen, "@%.*s", (int)id->name.len, id->name.ptr); + break; + case ID_USER_FQDN: + n = snprintf(dst, dstlen, "%.*s", (int)id->name.len, id->name.ptr); + break; + case ID_DER_ASN1_DN: + n = dntoa(dst, dstlen, id->name); + break; + case ID_KEY_ID: + n = keyidtoa(dst, dstlen, id->name); + break; + default: + n = snprintf(dst, dstlen, "unknown id kind %d", id->kind); + break; + } + + /* "Sanitize" string so that log isn't endangered: + * replace unprintable characters with '?'. + */ + if (n > 0) + { + for ( ; *dst != '\0'; dst++) + if (!isprint(*dst)) + *dst = '?'; + } + + return n; } /* Replace the shell metacharacters ', \, ", `, and $ in a character string @@ -315,26 +329,26 @@ idtoa(const struct id *id, char *dst, size_t dstlen) void escape_metachar(const char *src, char *dst, size_t dstlen) { - while (*src != '\0' && dstlen > 4) - { - switch (*src) + while (*src != '\0' && dstlen > 4) { - case '\'': - case '\\': - case '"': - case '`': - case '$': - sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src); - dst += 4; - dstlen -= 4; - break; - default: - *dst++ = *src; - dstlen--; + 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++; } - src++; - } - *dst = '\0'; + *dst = '\0'; } @@ -344,126 +358,126 @@ escape_metachar(const char *src, char *dst, size_t dstlen) void unshare_id_content(struct id *id) { - switch (id->kind) - { - case ID_FQDN: - case ID_USER_FQDN: - case ID_DER_ASN1_DN: - case ID_KEY_ID: - id->name.ptr = clone_bytes(id->name.ptr, id->name.len, "keep id name"); - break; - case ID_MYID: - case ID_NONE: - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - break; - default: - bad_case(id->kind); - } + switch (id->kind) + { + case ID_FQDN: + case ID_USER_FQDN: + case ID_DER_ASN1_DN: + case ID_KEY_ID: + id->name = chunk_clone(id->name); + break; + case ID_MYID: + case ID_ANY: + case ID_IPV4_ADDR: + case ID_IPV6_ADDR: + break; + default: + bad_case(id->kind); + } } void free_id_content(struct id *id) { - switch (id->kind) - { - case ID_FQDN: - case ID_USER_FQDN: - case ID_DER_ASN1_DN: - case ID_KEY_ID: - freeanychunk(id->name); - break; - case ID_MYID: - case ID_NONE: - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - break; - default: - bad_case(id->kind); - } + switch (id->kind) + { + case ID_FQDN: + case ID_USER_FQDN: + case ID_DER_ASN1_DN: + case ID_KEY_ID: + free(id->name.ptr); + break; + case ID_MYID: + case ID_ANY: + case ID_IPV4_ADDR: + case ID_IPV6_ADDR: + break; + default: + bad_case(id->kind); + } } /* compare two struct id values */ bool same_id(const struct id *a, const struct id *b) { - a = resolve_myid(a); - b = resolve_myid(b); - if (a->kind != b->kind) - return FALSE; - switch (a->kind) - { - case ID_NONE: - return TRUE; /* kind of vacuous */ - - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - return sameaddr(&a->ip_addr, &b->ip_addr); - - case ID_FQDN: - case ID_USER_FQDN: - /* assumptions: - * - case should be ignored - * - trailing "." should be ignored (even if the only character?) - */ + a = resolve_myid(a); + b = resolve_myid(b); + if (a->kind != b->kind) + return FALSE; + switch (a->kind) { - size_t al = a->name.len - , bl = b->name.len; - - while (al > 0 && a->name.ptr[al - 1] == '.') - al--; - while (bl > 0 && b->name.ptr[bl - 1] == '.') - bl--; - return al == bl - && strncasecmp(a->name.ptr, b->name.ptr, al) == 0; - } + case ID_ANY: + return TRUE; /* kind of vacuous */ + + case ID_IPV4_ADDR: + case ID_IPV6_ADDR: + return sameaddr(&a->ip_addr, &b->ip_addr); + + case ID_FQDN: + case ID_USER_FQDN: + /* assumptions: + * - case should be ignored + * - trailing "." should be ignored (even if the only character?) + */ + { + size_t al = a->name.len + , bl = b->name.len; + + while (al > 0 && a->name.ptr[al - 1] == '.') + al--; + while (bl > 0 && b->name.ptr[bl - 1] == '.') + bl--; + return al == bl + && strncasecmp(a->name.ptr, b->name.ptr, al) == 0; + } - case ID_DER_ASN1_DN: - return same_dn(a->name, b->name); + case ID_DER_ASN1_DN: + return same_dn(a->name, b->name); - case ID_KEY_ID: - return a->name.len == b->name.len - && memcmp(a->name.ptr, b->name.ptr, a->name.len) == 0; + case ID_KEY_ID: + return a->name.len == b->name.len + && memeq(a->name.ptr, b->name.ptr, a->name.len); - default: - bad_case(a->kind); - } - return FALSE; + default: + bad_case(a->kind); + } + return FALSE; } /* compare two struct id values, DNs can contain wildcards */ bool match_id(const struct id *a, const struct id *b, int *wildcards) { - if (b->kind == ID_NONE) - { - *wildcards = MAX_WILDCARDS; - return TRUE; - } - if (a->kind != b->kind) - return FALSE; - if (a->kind == ID_DER_ASN1_DN) - return match_dn(a->name, b->name, wildcards); - else - { - *wildcards = 0; - return same_id(a, b); - } + if (b->kind == ID_ANY) + { + *wildcards = MAX_WILDCARDS; + return TRUE; + } + if (a->kind != b->kind) + return FALSE; + if (a->kind == ID_DER_ASN1_DN) + return match_dn(a->name, b->name, wildcards); + else + { + *wildcards = 0; + return same_id(a, b); + } } /* count the numer of wildcards in an id */ int id_count_wildcards(const struct id *id) { - switch (id->kind) - { - case ID_NONE: - return MAX_WILDCARDS; - case ID_DER_ASN1_DN: - return dn_count_wildcards(id->name); - default: - return 0; - } + switch (id->kind) + { + case ID_ANY: + return MAX_WILDCARDS; + case ID_DER_ASN1_DN: + return dn_count_wildcards(id->name); + default: + return 0; + } } /* build an ID payload @@ -474,31 +488,31 @@ id_count_wildcards(const struct id *id) void build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end) { - const struct id *id = resolve_myid(&end->id); - - zero(hd); - hd->isaiid_idtype = id->kind; - switch (id->kind) - { - case ID_NONE: - 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_FQDN: - case ID_USER_FQDN: - case ID_DER_ASN1_DN: - case ID_KEY_ID: - *tl = id->name; - break; - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - tl->len = addrbytesptr(&id->ip_addr - , (const unsigned char **)&tl->ptr); /* sets tl->ptr too */ - break; - default: - bad_case(id->kind); - } + const struct id *id = resolve_myid(&end->id); + + zero(hd); + hd->isaiid_idtype = id->kind; + switch (id->kind) + { + 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_FQDN: + case ID_USER_FQDN: + case ID_DER_ASN1_DN: + case ID_KEY_ID: + *tl = id->name; + break; + case ID_IPV4_ADDR: + case ID_IPV6_ADDR: + tl->len = addrbytesptr(&id->ip_addr + , (const unsigned char **)&tl->ptr); /* sets tl->ptr too */ + break; + default: + bad_case(id->kind); + } } /* diff --git a/src/pluto/id.h b/src/pluto/id.h index 185c17f20..dc2dcdfa6 100644 --- a/src/pluto/id.h +++ b/src/pluto/id.h @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: id.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _ID_H @@ -20,25 +18,25 @@ #include "defs.h" struct id { - int kind; /* ID_* value */ - ip_address ip_addr; /* ID_IPV4_ADDR, ID_IPV6_ADDR */ - chunk_t name; /* ID_FQDN, ID_USER_FQDN (with @) */ - /* ID_KEY_ID, ID_DER_ASN_DN */ + int kind; /* ID_* value */ + ip_address ip_addr; /* ID_IPV4_ADDR, ID_IPV6_ADDR */ + chunk_t name; /* ID_FQDN, ID_USER_FQDN (with @) */ + /* ID_KEY_ID, ID_DER_ASN_DN */ }; extern void init_id(void); - -extern const struct id empty_id; /* ID_NONE */ +extern void free_id(void); +extern const struct id empty_id; /* ID_NONE */ 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 */ + 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 struct id myids[MYID_SPECIFIED+1]; /* %myid */ +extern struct id myids[MYID_SPECIFIED+1]; /* %myid */ extern char *myid_str[MYID_SPECIFIED+1]; /* strings */ extern void set_myid(enum myid_state s, char *); extern void show_myid_status(void); @@ -49,19 +47,19 @@ extern err_t atoid(char *src, struct id *id, bool myid_ok); extern int keyidtoa(char *dst, size_t dstlen, chunk_t keyid); extern void iptoid(const ip_address *ip, struct id *id); extern int idtoa(const struct id *id, char *dst, size_t dstlen); -#define IDTOA_BUF 512 +#define IDTOA_BUF 512 extern void escape_metachar(const char *src, char *dst, size_t dstlen); -struct end; /* forward declaration of tag (defined in connections.h) */ +struct end; /* forward declaration of tag (defined in connections.h) */ extern void unshare_id_content(struct id *id); extern void free_id_content(struct id *id); extern bool same_id(const struct id *a, const struct id *b); -#define MAX_WILDCARDS 15 +#define MAX_WILDCARDS 15 extern bool match_id(const struct id *a, const struct id *b, int *wildcards); extern int id_count_wildcards(const struct id *id); #define id_is_ipaddr(id) ((id)->kind == ID_IPV4_ADDR || (id)->kind == ID_IPV6_ADDR) -struct isakmp_ipsec_id; /* forward declaration of tag (defined in packet.h) */ +struct isakmp_ipsec_id; /* forward declaration of tag (defined in packet.h) */ extern void - build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end); + build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end); #endif /* _ID_H */ diff --git a/src/pluto/ike_alg.c b/src/pluto/ike_alg.c index 6759059fa..f833f85b5 100644 --- a/src/pluto/ike_alg.c +++ b/src/pluto/ike_alg.c @@ -1,5 +1,6 @@ /* IKE modular algorithm handling interface - * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> + * 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 @@ -10,8 +11,6 @@ * 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. - * - * RCSID $Id: ike_alg.c 3686 2008-03-28 11:48:14Z martin $ */ #include <stdio.h> @@ -21,16 +20,19 @@ #include <sys/queue.h> #include <freeswan.h> -#include <ipsec_policy.h> + +#include <library.h> +#include <debug.h> +#include <crypto/hashers/hasher.h> +#include <crypto/crypters/crypter.h> +#include <crypto/prfs/prf.h> #include "constants.h" #include "defs.h" -#include "sha1.h" -#include "md5.h" #include "crypto.h" - #include "state.h" #include "packet.h" +#include "keys.h" #include "log.h" #include "whack.h" #include "spdb.h" @@ -42,7 +44,7 @@ #define return_on(var, val) do { var=val;goto return_out; } while(0); -/* +/** * IKE algorithm list handling - registration and lookup */ @@ -50,540 +52,371 @@ static struct ike_alg *ike_alg_base[IKE_ALG_MAX+1] = {NULL, NULL}; -/* - * return ike_algo object by {type, id} +/** + * 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))) +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]; + 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; + 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) +int ike_alg_add(struct ike_alg* a) { - 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) + if (a->algo_type > IKE_ALG_MAX) { - ep = &e->algo_next; - e = *ep; + plog("ike_alg: Not added, invalid algorithm type"); + return -EINVAL; } - *ep = a; - 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); -} + if (ike_alg_find(a->algo_type, a->algo_id, 0) != NULL) + { + plog("ike_alg: Not added, algorithm already exists"); + return -EEXIST; + } -/* - * get IKE encryption algorithm - */ -struct encrypt_desc *ike_alg_get_encrypter(u_int alg) -{ - return (struct encrypt_desc *) ike_alg_find(IKE_ALG_ENCRYPT, alg, 0); -} + { + struct ike_alg **ep = &ike_alg_base[a->algo_type]; + struct ike_alg *e = *ep; -/* - * check if IKE hash algorithm is present - */ -bool -ike_alg_hash_present(u_int halg) -{ - return ike_alg_get_hasher(halg) != NULL; + while (e != NULL && a->algo_id > e->algo_id) + { + ep = &e->algo_next; + e = *ep; + } + *ep = a; + a->algo_next = e; + return 0; + } } -/* - * check if IKE encryption algorithm is present +/** + * Get IKE hash algorithm */ -bool -ike_alg_enc_present(u_int ealg) +struct hash_desc *ike_alg_get_hasher(u_int alg) { - return ike_alg_get_encrypter(ealg) != NULL; + return (struct hash_desc *) ike_alg_find(IKE_ALG_HASH, alg, 0); } -/* - * Validate and register IKE hash algorithm object +/** + * Get IKE encryption algorithm */ -int -ike_alg_register_hash(struct hash_desc *hash_desc) +struct encrypt_desc *ike_alg_get_crypter(u_int alg) { - const char *alg_name = NULL; - int ret = 0; - - if (hash_desc->algo_id > OAKLEY_HASH_MAX) - { - plog ("ike_alg: hash alg=%d > max=%d" - , hash_desc->algo_id, OAKLEY_HASH_MAX); - return_on(ret,-EINVAL); - } - - if (hash_desc->hash_ctx_size > sizeof (union hash_ctx)) - { - plog ("ike_alg: hash alg=%d has ctx_size=%d > hash_ctx=%d" - , hash_desc->algo_id - , (int)hash_desc->hash_ctx_size - , (int)sizeof (union hash_ctx)); - return_on(ret,-EOVERFLOW); - } - - if (!(hash_desc->hash_init && hash_desc->hash_update && hash_desc->hash_final)) - { - plog ("ike_alg: hash alg=%d needs hash_init(), hash_update() and hash_final()" - , hash_desc->algo_id); - return_on(ret,-EINVAL); - } - - alg_name = enum_name(&oakley_hash_names, hash_desc->algo_id); - if (!alg_name) - { - plog ("ike_alg: hash alg=%d not found in constants.c:oakley_hash_names" - , hash_desc->algo_id); - alg_name = "<NULL>"; - } - -return_out: - if (ret == 0) - ret = ike_alg_add((struct ike_alg *)hash_desc); - - plog("ike_alg: Activating %s hash: %s" - ,alg_name, ret == 0 ? "Ok" : "FAILED"); - - return ret; + return (struct encrypt_desc *) ike_alg_find(IKE_ALG_ENCRYPT, alg, 0); } -/* - * Validate and register IKE encryption algorithm object +/** + * Get IKE dh group */ -int -ike_alg_register_enc(struct encrypt_desc *enc_desc) +struct dh_desc *ike_alg_get_dh_group(u_int alg) { - int ret = ike_alg_add((struct ike_alg *)enc_desc); - - const char *alg_name = enum_name(&oakley_enc_names, enc_desc->algo_id); - - char alg_number[20]; - - /* algorithm is not listed in oakley_enc_names */ - if (alg_name == NULL) - { - snprintf(alg_number, sizeof(alg_number), "OAKLEY_ID_%d" - , enc_desc->algo_id); - alg_name = alg_number; - } - - plog("ike_alg: Activating %s encryption: %s" - , alg_name, ret == 0 ? "Ok" : "FAILED"); - - return ret; + return (struct dh_desc *) ike_alg_find(IKE_ALG_DH_GROUP, alg, 0); } -/* +/** * Get pfsgroup for this connection */ -const struct oakley_group_desc * -ike_alg_pfsgroup(struct connection *c, lset_t policy) +const struct dh_desc *ike_alg_pfsgroup(struct connection *c, lset_t policy) { - const struct oakley_group_desc * ret = NULL; + const struct dh_desc *ret = NULL; - if ((policy & POLICY_PFS) - && c->alg_info_esp - && c->alg_info_esp->esp_pfsgroup) - ret = lookup_group(c->alg_info_esp->esp_pfsgroup); - return ret; + 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(struct alg_info_ike *ai , lset_t policy) +struct db_context *ike_alg_db_new(struct connection *c, lset_t policy) { - struct db_context *db_ctx = NULL; - struct ike_info *ike_info; - struct encrypt_desc *enc_desc; - 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_enc_present(ealg)) - { - DBG_log("ike_alg: ike enc ealg=%d not present" - , ealg); - continue; - } - - if (!ike_alg_hash_present(halg)) - { - DBG_log("ike_alg: ike hash halg=%d not present" - , halg); - continue; - } + struct alg_info_ike *ai = c->alg_info_ike; + struct db_context *db_ctx = NULL; + struct ike_info *ike_info; + struct encrypt_desc *enc_desc; + u_int ealg, halg, modp, eklen = 0; + int i; - enc_desc = ike_alg_get_encrypter(ealg); - passert(enc_desc != NULL); + bool is_xauth_server = (policy & POLICY_XAUTH_SERVER) != LEMPTY; - if (eklen - && (eklen < enc_desc->keyminlen || eklen > enc_desc->keymaxlen)) + if (!ai) { - DBG_log("ike_alg: ealg=%d (specified) keylen:%d, not valid min=%d, max=%d" - , ealg - , eklen - , enc_desc->keyminlen - , enc_desc->keymaxlen - ); - continue; + 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); - if (policy & POLICY_RSASIG) + /* for each group */ + ALG_INFO_IKE_FOREACH(ai, ike_info, i) { - 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_RSA_SIG); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } + ealg = ike_info->ike_ealg; + halg = ike_info->ike_halg; + modp = ike_info->ike_modp; + eklen= ike_info->ike_eklen; - 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 (!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; + } + enc_desc = ike_alg_get_crypter(ealg); - 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_PUBKEY) + { + int auth_method = 0; + private_key_t *key = get_private_key(c); + + if (key == NULL) + { + plog("ike alg: unable to locate my private key"); + continue; + } + switch (key->get_type(key)) + { + case KEY_RSA: + auth_method = OAKLEY_RSA_SIG; + break; + case KEY_ECDSA: + switch (key->get_keysize(key)) + { + case 32: + auth_method = OAKLEY_ECDSA_256; + break; + case 48: + auth_method = OAKLEY_ECDSA_384; + break; + case 66: + 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_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); + 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; + return db_ctx; } -/* +/** * Show registered IKE algorithms */ -void -ike_alg_list(void) +void ike_alg_list(void) { - u_int i; - struct ike_alg *a; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of registered IKE Encryption Algorithms:"); - whack_log(RC_COMMENT, " "); - - for (a = ike_alg_base[IKE_ALG_ENCRYPT]; a != NULL; a = a->algo_next) - { - struct encrypt_desc *desc = (struct encrypt_desc*)a; - - whack_log(RC_COMMENT, "#%-5d %s, blocksize: %d, keylen: %d-%d-%d" - , a->algo_id - , enum_name(&oakley_enc_names, a->algo_id) - , (int)desc->enc_blocksize*BITS_PER_BYTE - , desc->keyminlen - , desc->keydeflen - , desc->keymaxlen - ); - } - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of registered IKE Hash Algorithms:"); - whack_log(RC_COMMENT, " "); - - for (a = ike_alg_base[IKE_ALG_HASH]; a != NULL; a = a->algo_next) - { - whack_log(RC_COMMENT, "#%-5d %s, hashsize: %d" - , a->algo_id - , enum_name(&oakley_hash_names, a->algo_id) - , (int)((struct hash_desc *)a)->hash_digest_size*BITS_PER_BYTE - ); - } - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of registered IKE DH Groups:"); - whack_log(RC_COMMENT, " "); - - for (i = 0; i < elemsof(oakley_group); i++) - { - const struct oakley_group_desc *gdesc=oakley_group + i; - - whack_log(RC_COMMENT, "#%-5d %s, groupsize: %d" - , gdesc->group - , enum_name(&oakley_group_names, gdesc->group) - , (int)gdesc->bytes*BITS_PER_BYTE - ); - } -} - -/* Show IKE algorithms for - * - this connection (result from ike= string) - * - newest SA - */ -void -ike_alg_show_connection(struct connection *c, const char *instance) -{ - char buf[256]; - struct state *st; - - if (c->alg_info_ike) - { - alg_info_snprint(buf, sizeof(buf)-1, (struct alg_info *)c->alg_info_ike); - whack_log(RC_COMMENT - , "\"%s\"%s: IKE algorithms wanted: %s" - , c->name - , instance - , buf - ); - - alg_info_snprint_ike(buf, sizeof(buf)-1, c->alg_info_ike); - whack_log(RC_COMMENT - , "\"%s\"%s: IKE algorithms found: %s" - , c->name - , instance - , buf - ); - } - - st = state_with_serialno(c->newest_isakmp_sa); - if (st) - whack_log(RC_COMMENT - , "\"%s\"%s: IKE algorithm newest: %s_%d-%s-%s" - , c->name - , instance - , enum_show(&oakley_enc_names, st->st_oakley.encrypt) - +7 /* strlen("OAKLEY_") */ - /* , st->st_oakley.encrypter->keydeflen */ - , st->st_oakley.enckeylen - , enum_show(&oakley_hash_names, st->st_oakley.hash) - +7 /* strlen("OAKLEY_") */ - , enum_show(&oakley_group_names, st->st_oakley.group->group) - +13 /* strlen("OAKLEY_GROUP_") */ - ); -} - -/* - * Apply a suite of testvectors to a hash algorithm - */ -static bool -ike_hash_test(const struct hash_desc *desc) -{ - bool hash_results = TRUE; - bool hmac_results = TRUE; - - if (desc->hash_testvectors == NULL) - { - plog(" %s hash self-test not available", enum_name(&oakley_hash_names, desc->algo_id)); - } - else - { - int i; + char buf[BUF_LEN]; + char *pos; + int n, len; + struct ike_alg *a; + + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of registered IKEv1 Algorithms:"); + whack_log(RC_COMMENT, " "); + + pos = buf; + *pos = '\0'; + len = BUF_LEN; + for (a = ike_alg_base[IKE_ALG_ENCRYPT]; a != NULL; a = a->algo_next) + { + n = snprintf(pos, len, " %s", enum_name(&oakley_enc_names, a->algo_id)); + pos += n; + len -= n; + if (len <= 0) + { + break; + } + } + whack_log(RC_COMMENT, " encryption:%s", buf); - for (i = 0; desc->hash_testvectors[i].msg_digest != NULL; i++) + pos = buf; + *pos = '\0'; + len = BUF_LEN; + for (a = ike_alg_base[IKE_ALG_HASH]; a != NULL; a = a->algo_next) { - u_char digest[MAX_DIGEST_LEN]; - bool result; - - union hash_ctx ctx; - - desc->hash_init(&ctx); - desc->hash_update(&ctx, desc->hash_testvectors[i].msg - ,desc->hash_testvectors[i].msg_size); - desc->hash_final(digest, &ctx); - result = memcmp(digest, desc->hash_testvectors[i].msg_digest - , desc->hash_digest_size) == 0; - DBG(DBG_CRYPT, - DBG_log(" hash testvector %d: %s", i, result ? "ok":"failed") - ) - hash_results &= result; + n = snprintf(pos, len, " %s", enum_name(&oakley_hash_names, a->algo_id)); + pos += n; + len -= n; + if (len <= 0) + { + break; + } } - plog(" %s hash self-test %s", enum_name(&oakley_hash_names, desc->algo_id) - , hash_results ? "passed":"failed"); - } - - if (desc->hmac_testvectors == NULL) - { - plog(" %s hmac self-test not available", enum_name(&oakley_hash_names, desc->algo_id)); - } - else - { - int i; + whack_log(RC_COMMENT, " integrity: %s", buf); - for (i = 0; desc->hmac_testvectors[i].hmac != NULL; i++) + pos = buf; + *pos = '\0'; + len = BUF_LEN; + for (a = ike_alg_base[IKE_ALG_DH_GROUP]; a != NULL; a = a->algo_next) { - u_char digest[MAX_DIGEST_LEN]; - bool result; - - struct hmac_ctx ctx; - - hmac_init(&ctx, desc, desc->hmac_testvectors[i].key - , desc->hmac_testvectors[i].key_size); - hmac_update(&ctx, desc->hmac_testvectors[i].msg - ,desc->hmac_testvectors[i].msg_size); - hmac_final(digest, &ctx); - result = memcmp(digest, desc->hmac_testvectors[i].hmac - , desc->hash_digest_size) == 0; - DBG(DBG_CRYPT, - DBG_log(" hmac testvector %d: %s", i, result ? "ok":"failed") - ) - hmac_results &= result; + n = snprintf(pos, len, " %s", enum_name(&oakley_group_names, a->algo_id)); + pos += n; + len -= n; + if (len <= 0) + { + break; + } } - plog(" %s hmac self-test %s", enum_name(&oakley_hash_names, desc->algo_id) - , hmac_results ? "passed":"failed"); - } - return hash_results && hmac_results; + whack_log(RC_COMMENT, " dh-group: %s", buf); } -/* - * Apply test vectors to registered encryption and hash algorithms +/** + * Show IKE algorithms for this connection (result from ike= string) + * and newest SA */ -bool -ike_alg_test(void) +void ike_alg_show_connection(struct connection *c, const char *instance) { - bool all_results = TRUE; - struct ike_alg *a; - - plog("Testing registered IKE encryption algorithms:"); - - for (a = ike_alg_base[IKE_ALG_ENCRYPT]; a != NULL; a = a->algo_next) - { - plog(" %s self-test not available", enum_name(&oakley_enc_names, a->algo_id)); - } - - plog("Testing registered IKE hash algorithms:"); - - for (a = ike_alg_base[IKE_ALG_HASH]; a != NULL; a = a->algo_next) - { - struct hash_desc *desc = (struct hash_desc*)a; + struct state *st = state_with_serialno(c->newest_isakmp_sa); - all_results &= ike_hash_test(desc); - } - - if (all_results) - plog("All crypto self-tests passed"); - else - plog("Some crypto self-tests failed"); - return all_results; + 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) +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) + /* + * 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)) { - 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) + int i; + struct ike_info *ike_info; + + if (alg_info_ike) { - if (ealg_insecure) - loglog(RC_LOG_SERIOUS, "You should NOT use insecure IKE algorithms (%s)!" - , enum_name(&oakley_enc_names, ealg)); - return TRUE; + 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; } - 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; + return TRUE; } diff --git a/src/pluto/ike_alg.h b/src/pluto/ike_alg.h index dbf4076c5..458d14c3a 100644 --- a/src/pluto/ike_alg.h +++ b/src/pluto/ike_alg.h @@ -10,85 +10,63 @@ * 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. - * - * RCSID $Id: ike_alg.h 3252 2007-10-06 21:24:50Z andreas $ */ - + #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; - struct ike_alg *algo_next; + u_int16_t algo_type; + u_int16_t algo_id; + struct ike_alg *algo_next; }; struct encrypt_desc { - u_int16_t algo_type; - u_int16_t algo_id; - struct ike_alg *algo_next; + u_int16_t algo_type; + u_int16_t algo_id; + struct ike_alg *algo_next; - size_t enc_ctxsize; - size_t enc_blocksize; - u_int keydeflen; - u_int keymaxlen; - u_int keyminlen; - void (*do_crypt)(u_int8_t *dat, size_t datasize, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc); + size_t enc_blocksize; + u_int keydeflen; + u_int keymaxlen; + u_int keyminlen; }; -typedef struct hash_testvector hash_testvector_t; +struct hash_desc { + u_int16_t algo_type; + u_int16_t algo_id; + struct ike_alg *algo_next; -struct hash_testvector { - const size_t msg_size; - const u_char *msg; - const u_char *msg_digest; + size_t hash_digest_size; }; -typedef struct hmac_testvector hmac_testvector_t; - -struct hmac_testvector { - const size_t key_size; - const u_char *key; - const size_t msg_size; - const u_char *msg; - const u_char *hmac; -}; -struct hash_desc { - u_int16_t algo_type; - u_int16_t algo_id; - struct ike_alg *algo_next; +struct dh_desc { + u_int16_t algo_type; + u_int16_t algo_id; + struct ike_alg *algo_next; - size_t hash_ctx_size; - size_t hash_block_size; - size_t hash_digest_size; - const hash_testvector_t *hash_testvectors; - const hmac_testvector_t *hmac_testvectors; - void (*hash_init)(void *ctx); - void (*hash_update)(void *ctx, const u_int8_t *in, size_t datasize); - void (*hash_final)(u_int8_t *out, void *ctx); + size_t ke_size; }; -#define IKE_ALG_ENCRYPT 0 -#define IKE_ALG_HASH 1 -#define IKE_ALG_MAX IKE_ALG_HASH +#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); extern struct hash_desc *ike_alg_get_hasher(u_int alg); -extern struct encrypt_desc *ike_alg_get_encrypter(u_int alg); -extern bool ike_alg_enc_present(u_int ealg); -extern bool ike_alg_hash_present(u_int halg); -extern int ike_alg_register_hash(struct hash_desc *a); -extern int ike_alg_register_enc(struct encrypt_desc *e); -extern const struct oakley_group_desc* ike_alg_pfsgroup(struct connection *c - , lset_t policy); -extern struct db_context * ike_alg_db_new(struct alg_info_ike *ai, lset_t policy); +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_test(void); 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); + , 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 index 9721ac583..929768ee9 100644 --- a/src/pluto/ipsec_doi.c +++ b/src/pluto/ipsec_doi.c @@ -1,6 +1,7 @@ /* 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 @@ -11,8 +12,6 @@ * 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. - * - * RCSID $Id: ipsec_doi.c 5052 2009-03-30 03:47:14Z andreas $ */ #include <stdio.h> @@ -24,16 +23,22 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ +#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ #include <sys/queue.h> -#include <sys/time.h> /* for gettimeofday */ +#include <sys/time.h> /* for gettimeofday */ #include <freeswan.h> -#include <ipsec_policy.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 "constants.h" #include "defs.h" -#include "mp_defs.h" #include "state.h" #include "id.h" #include "x509.h" @@ -44,25 +49,20 @@ #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 "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 "rnd.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ +#include "ipsec_doi.h" /* needs demux.h and state.h */ #include "whack.h" #include "fetch.h" #include "pkcs7.h" -#include "asn1.h" - -#include "sha1.h" -#include "md5.h" -#include "crypto.h" /* requires sha1.h and md5.h */ +#include "crypto.h" #include "vendor.h" #include "alg_info.h" #include "ike_alg.h" @@ -74,115 +74,84 @@ * are we sending Pluto's Vendor ID? */ #ifdef VENDORID -#define SEND_PLUTO_VID 1 +#define SEND_PLUTO_VID 1 #else /* !VENDORID */ -#define SEND_PLUTO_VID 0 +#define SEND_PLUTO_VID 0 #endif /* !VENDORID */ /* * are we sending an XAUTH VID? */ #ifdef XAUTH_VID -#define SEND_XAUTH_VID 1 +#define SEND_XAUTH_VID 1 #else /* !XAUTH_VID */ -#define SEND_XAUTH_VID 0 +#define SEND_XAUTH_VID 0 #endif /* !XAUTH_VID */ /* * are we sending a Cisco Unity VID? */ #ifdef CISCO_QUIRKS -#define SEND_CISCO_UNITY_VID 1 +#define SEND_CISCO_UNITY_VID 1 #else /* !CISCO_QUIRKS */ -#define SEND_CISCO_UNITY_VID 0 +#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 != NOTHING_WRONG) return STF_FAIL + r; } + { int r = (f); if (r != NOTHING_WRONG) return STF_FAIL + r; } /* 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 */ + 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 -, const struct oakley_group_desc *group) +static void compute_dh_shared(struct state *st, const chunk_t g) { - MP_INT mp_g, mp_shared; - struct timeval tv0, tv1; - unsigned long tv_diff; - - gettimeofday(&tv0, NULL); - passert(st->st_sec_in_use); - n_to_mpz(&mp_g, g.ptr, g.len); - mpz_init(&mp_shared); - mpz_powm(&mp_shared, &mp_g, &st->st_sec, group->modulus); - mpz_clear(&mp_g); - freeanychunk(st->st_shared); /* happens in odd error cases */ - st->st_shared = mpz_to_n(&mp_shared, group->bytes); - mpz_clear(&mp_shared); - gettimeofday(&tv1, NULL); - tv_diff=(tv1.tv_sec - tv0.tv_sec) * 1000000 + (tv1.tv_usec - tv0.tv_usec); - DBG(DBG_CRYPT, - DBG_log("compute_dh_shared(): time elapsed (%s): %ld usec" - , enum_show(&oakley_group_names, st->st_oakley.group->group) - , tv_diff); - ); - /* if took more than 200 msec ... */ - if (tv_diff > 200000) { - loglog(RC_LOG_SERIOUS, "WARNING: compute_dh_shared(): for %s took " - "%ld usec" - , enum_show(&oakley_group_names, st->st_oakley.group->group) - , tv_diff); - } - - DBG_cond_dump_chunk(DBG_CRYPT, "DH shared secret:\n", st->st_shared); + 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 oakley_group_desc *group, pb_stream *outs, u_int8_t np) +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_sec_in_use) - { - u_char tmp[LOCALSECRETSIZE]; - MP_INT mp_g; - - get_rnd_bytes(tmp, LOCALSECRETSIZE); - st->st_sec_in_use = TRUE; - n_to_mpz(&st->st_sec, tmp, LOCALSECRETSIZE); - - mpz_init(&mp_g); - mpz_powm(&mp_g, &groupgenerator, &st->st_sec, group->modulus); - freeanychunk(*g); /* happens in odd error cases */ - *g = mpz_to_n(&mp_g, group->bytes); - mpz_clear(&mp_g); + 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("Local DH secret:\n", tmp, LOCALSECRETSIZE); - DBG_dump_chunk("Public DH value sent:\n", *g)); - } - return out_generic_chunk(np, &isakmp_keyex_desc, outs, *g, "keyex value"); + DBG_dump_chunk("Public DH value sent:\n", *g) + ) + return out_generic_chunk(np, &isakmp_keyex_desc, outs, *g, "keyex value"); } /* accept_ke @@ -194,21 +163,22 @@ build_and_ship_KE(struct state *st, chunk_t *g * 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 oakley_group_desc *gr -, pb_stream *pbs) +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->bytes) - { - loglog(RC_LOG_SERIOUS, "KE has %u byte DH public value; %u required" - , (unsigned) pbs_left(pbs), (unsigned) gr->bytes); - /* XXX Could send notification back */ - return INVALID_KEY_INFORMATION; - } - clonereplacechunk(*dest, pbs->cur, pbs_left(pbs), val_name); - DBG_cond_dump_chunk(DBG_CRYPT, "DH public value received:\n", *dest); - return NOTHING_WRONG; + 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 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 NOTHING_WRONG; } /* accept_PFS_KE @@ -216,652 +186,663 @@ accept_KE(chunk_t *dest, const char *val_name * 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) +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]; + 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 INVALID_KEY_INFORMATION; - } - } - else - { - if (st->st_pfs_group == NULL) + if (ke_pd == NULL) { - loglog(RC_LOG_SERIOUS, "%s message KE payload requires a GROUP_DESCRIPTION attribute in SA" - , msg_name); - return INVALID_KEY_INFORMATION; + if (st->st_pfs_group != NULL) + { + loglog(RC_LOG_SERIOUS, "missing KE payload in %s message", msg_name); + return INVALID_KEY_INFORMATION; + } } - if (ke_pd->next != NULL) + else { - loglog(RC_LOG_SERIOUS, "%s message contains several KE payloads; we accept at most one", msg_name); - return INVALID_KEY_INFORMATION; /* ??? */ + if (st->st_pfs_group == NULL) + { + loglog(RC_LOG_SERIOUS, "%s message KE payload requires a GROUP_DESCRIPTION attribute in SA" + , msg_name); + return 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 INVALID_KEY_INFORMATION; /* ??? */ + } + return accept_KE(dest, val_name, st->st_pfs_group, &ke_pd->pbs); } - return accept_KE(dest, val_name, st->st_pfs_group, &ke_pd->pbs); - } - return NOTHING_WRONG; + return NOTHING_WRONG; } -static bool -build_and_ship_nonce(chunk_t *n, pb_stream *outs, u_int8_t np -, const char *name) +static bool build_and_ship_nonce(chunk_t *n, pb_stream *outs, u_int8_t np, + const char *name) { - freeanychunk(*n); - setchunk(*n, alloc_bytes(DEFAULT_NONCE_SIZE, name), DEFAULT_NONCE_SIZE); - get_rnd_bytes(n->ptr, DEFAULT_NONCE_SIZE); - return out_generic_chunk(np, &isakmp_nonce_desc, outs, *n, 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 bool -collect_rw_ca_candidates(struct msg_digest *md, generalName_t **top) +static bool collect_rw_ca_candidates(struct msg_digest *md, generalName_t **top) { - struct connection *d = find_host_connection(&md->iface->addr - , pluto_port, (ip_address*)NULL, md->sender_port, LEMPTY); + struct connection *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.ptr != NULL) + for (; d != NULL; d = d->hp_next) { - generalName_t *gn; - bool new_entry = TRUE; - - for (gn = *top; gn != NULL; gn = gn->next) - { - if (same_dn(gn->name, d->spd.that.ca)) + /* must be a road warrior connection */ + if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO) + && d->spd.that.ca.ptr != NULL) { - new_entry = FALSE; - break; + generalName_t *gn; + bool new_entry = TRUE; + + for (gn = *top; gn != NULL; gn = gn->next) + { + if (same_dn(gn->name, d->spd.that.ca)) + { + new_entry = FALSE; + break; + } + } + if (new_entry) + { + gn = malloc_thing(generalName_t); + gn->kind = GN_DIRECTORY_NAME; + gn->name = d->spd.that.ca; + gn->next = *top; + *top = gn; + } } - } - if (new_entry) - { - gn = alloc_thing(generalName_t, "generalName"); - gn->kind = GN_DIRECTORY_NAME; - gn->name = d->spd.that.ca; - gn->next = *top; - *top = gn; - } - } - } - return *top != NULL; + } + return *top != NULL; } -static bool -build_and_ship_CR(u_int8_t type, chunk_t ca, pb_stream *outs, u_int8_t np) +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; + 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; + /* 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; + 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) +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) - { - struct hmac_ctx ctx; - hmac_init_chunk(&ctx, encst->st_oakley.hasher, encst->st_skeyid_a); - hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t)); - hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start); - hmac_final(r_hashval, &ctx); + 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 */ - DBG(DBG_CRYPT, - DBG_log("HASH computed:"); - DBG_dump("", r_hashval, ctx.hmac_digest_size); - ) - } + passert((sndst) && (sndst->st_connection)); - /* 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]; + 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(); + } - 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; - - setchunk(sndst->st_tpacket, pbs.start, pbs_offset(&pbs)); - send_packet(sndst, "ISAKMP notify"); - sndst->st_tpacket = saved_tpacket; - } + /* 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) +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); - } + 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) +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; - struct connection 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); + /** + * 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; + struct connection 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) +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) + 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 { - DBG(DBG_CONTROL, DBG_log("no Phase 1 state for Delete")); - return; + return; /* nothing to do */ } - if (st->st_ah.present) + msgid = generate_msgid(p1st); + + zero(buffer); + init_pbs(&reply_pbs, buffer, sizeof(buffer), "delete msg"); + + /* HDR* */ { - ns->spi = st->st_ah.our_spi; - ns->dst = st->st_connection->spd.this.host_addr; - ns->proto = PROTO_IPSEC_AH; - ns++; + 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(); } - if (st->st_esp.present) + + /* HASH -- value to be filled later */ { - 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 */ - { - struct hmac_ctx ctx; - hmac_init_chunk(&ctx, p1st->st_oakley.hasher, p1st->st_skeyid_a); - hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t)); - hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start); - hmac_final(r_hashval, &ctx); + 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) */ + } - DBG(DBG_CRYPT, - DBG_log("HASH(1) computed:"); - DBG_dump("", r_hashval, ctx.hmac_digest_size); - ) - } - - /* 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(); - - setchunk(p1st->st_tpacket, 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); - } + /* 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) +void accept_delete(struct state *st, struct msg_digest *md, + struct payload_digest *p) { - struct isakmp_delete *d = &(p->payload.delete); - 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; - } - - 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*/ - , &st->st_connection->spd.that.host_addr - , MAINMODE_MSGID); - - if (dst == NULL) - { - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " - "ISAKMP SA not found (maybe expired)"); - } - else if (!same_peer_ids(st->st_connection, dst->st_connection, NULL)) - { - /* we've not authenticated the relevant identities */ + struct isakmp_delete *d = &(p->payload.delete); + 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 used to convey Delete has different IDs from ISAKMP SA it deletes"); - } - else - { - struct connection *oldc; - - oldc = cur_connection; - set_cur_connection(dst->st_connection); + "ISAKMP SA not established"); + return; + } - if (nat_traversal_enabled) - nat_traversal_change_port_lookup(md, dst); + if (d->isad_nospi == 0) + { + loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: no SPI"); + return; + } - loglog(RC_LOG_SERIOUS, "received Delete SA payload: " - "deleting ISAKMP State #%lu", dst->st_serialno); - delete_state(dst); - set_cur_connection(oldc); - } + 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; } - else + + if (d->isad_spisize != sizespi) { - /** - * 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 - { - struct connection *rc = dst->st_connection; - struct connection *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. + , "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; + } + + for (i = 0; i < d->isad_nospi; i++) + { + u_char *spi = p->pbs.cur + (i * sizespi); + + if (d->isad_protoid == PROTO_ISAKMP) + { + /** + * ISAKMP */ - 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); - } + struct state *dst = find_state(spi /*iCookie*/ + , spi+COOKIE_SIZE /*rCookie*/ + , &st->st_connection->spd.that.host_addr + , MAINMODE_MSGID); + + if (dst == NULL) + { + loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " + "ISAKMP SA not found (maybe expired)"); + } + else if (!same_peer_ids(st->st_connection, dst->st_connection, NULL)) + { + /* 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 + { + struct connection *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 { - 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); - } + /** + * IPSEC (ESP/AH) + */ + bool bogus; + struct state *dst = find_phase2_state_to_delete(st + , d->isad_protoid + , *(ipsec_spi_t *)spi /* network order */ + , &bogus); - /* reset connection */ - set_cur_connection(oldc); - } + 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 + { + struct connection *rc = dst->st_connection; + struct connection *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); + } + } } - } } /* The whole message must be a multiple of 4 octets. @@ -869,14 +850,13 @@ accept_delete(struct state *st, struct msg_digest *md, struct payload_digest *p) * rfc2408 3.6 Transform Payload. * Note: it talks about 4 BYTE boundaries! */ -void -close_message(pb_stream *pbs) +void close_message(pb_stream *pbs) { - size_t padding = pad_up(pbs_offset(pbs), 4); + size_t padding = pad_up(pbs_offset(pbs), 4); - if (padding != 0) - (void) out_zero(padding, pbs, "message padding"); - close_output_pbs(pbs); + if (padding != 0) + (void) out_zero(padding, pbs, "message padding"); + close_output_pbs(pbs); } /* Initiate an Oakley Main Mode exchange. @@ -885,225 +865,220 @@ close_message(pb_stream *pbs) */ static stf_status main_outI1(int whack_sock, struct connection *c, struct state *predecessor - , lset_t policy, unsigned long try) + , 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.type == CERT_PGP) - 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++; + 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.type == CERT_PGP) + 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) */ + 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 (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); + 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"); + /* set up reply */ + init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet"); - /* HDR out */ - { - struct isakmp_hdr hdr; + /* 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 */ + 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; + 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)) + /* SA out */ { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } + u_char *sa_start = rbody.cur; - /* save initiator SA for later HASH */ - passert(st->st_p1isa.ptr == NULL); /* no leak! (MUST be first time) */ - clonetochunk(st->st_p1isa, sa_start, rbody.cur - sa_start - , "sa in main_outI1"); - } + if (!out_sa(&rbody, &oakley_sadb, st, TRUE + , vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE)) + { + reset_cur_state(); + return STF_INTERNAL_ERROR; + } - /* 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)) + /* 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) { - reset_cur_state(); - return STF_INTERNAL_ERROR; + 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)) + /* if enabled send Cisco Unity Vendor ID */ + if (SEND_CISCO_UNITY_VID) { - reset_cur_state(); - return STF_INTERNAL_ERROR; + 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.type == CERT_PGP) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_OPENPGP)) + /* if we have an OpenPGP certificate we assume an + * OpenPGP peer and have to send the Vendor ID + */ + if (c->spd.this.cert.type == CERT_PGP) { - reset_cur_state(); - return STF_INTERNAL_ERROR; + 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)) + /* Announce our ability to do eXtended AUTHentication to the peer */ + if (SEND_XAUTH_VID) { - reset_cur_state(); - return STF_INTERNAL_ERROR; + 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)) + /* Announce our ability to do Dead Peer Detection to the peer */ { - reset_cur_state(); - return STF_INTERNAL_ERROR; + 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)) + if (nat_traversal_enabled) { - reset_cur_state(); - return STF_INTERNAL_ERROR; + /* 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); - clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply) - , "reply packet for main_outI1"); + 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 */ + /* Transmit */ - send_packet(st, "main_outI1"); + 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); + /* 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; + 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 -, struct connection *c -, lset_t policy -, unsigned long try -, so_serial_t replacing) +void ipsecdoi_initiate(int whack_sock, struct connection *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)) + /* 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)) { - /* leave our Phase 2 negotiation pending */ - add_pending(whack_sock, st, c, policy, try, replacing); + 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 { - /* ??? 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); - } + close_any(whack_sock); + } } /* Replace SA with a fresh one that is similar @@ -1115,221 +1090,264 @@ ipsecdoi_initiate(int whack_sock * - 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) +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) + int whack_sock = dup_any(st->st_whack_sock); + lset_t policy = st->st_policy; + + if (IS_PHASE1(st->st_state)) { - policy |= POLICY_ENCRYPT; - if (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; + passert(!HAS_IPSEC_POLICY(policy)); + (void) main_outI1(whack_sock, st->st_connection, st, policy, try); } - if (st->st_ipcomp.present) + else { - policy |= POLICY_COMPRESS; - if (st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; + /* 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); } - 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) +static bool skeyid_preshared(struct state *st) { - const chunk_t *pss = get_preshared_secret(st->st_connection); + const chunk_t *pss = get_preshared_secret(st->st_connection); - if (pss == NULL) - { - loglog(RC_LOG_SERIOUS, "preshared secret disappeared!"); - return FALSE; - } - else - { - struct hmac_ctx ctx; - - hmac_init_chunk(&ctx, st->st_oakley.hasher, *pss); - hmac_update_chunk(&ctx, st->st_ni); - hmac_update_chunk(&ctx, st->st_nr); - hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_preshared()", &ctx); - return TRUE; - } + 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) { - struct hmac_ctx ctx; - chunk_t nir; - - /* We need to hmac_init with the concatenation of Ni_b and Nr_b, - * so we have to build a temporary concatentation. - */ - nir.len = st->st_ni.len + st->st_nr.len; - nir.ptr = alloc_bytes(nir.len, "Ni + Nr in skeyid_digisig"); - memcpy(nir.ptr, st->st_ni.ptr, st->st_ni.len); - memcpy(nir.ptr+st->st_ni.len, st->st_nr.ptr, st->st_nr.len); - hmac_init_chunk(&ctx, st->st_oakley.hasher, nir); - pfree(nir.ptr); - - hmac_update_chunk(&ctx, st->st_shared); - hmac_final_chunk(st->st_skeyid, "st_skeyid in skeyid_digisig()", &ctx); - return TRUE; + 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) +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; + /* 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 XAUTHInitRSA: - case XAUTHRespRSA: - if (!skeyid_digisig(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_DSS_SIG: + /* XXX */ - case OAKLEY_RSA_ENC: - case OAKLEY_RSA_ENC_REV: - case OAKLEY_ELGAMAL_ENC: - case OAKLEY_ELGAMAL_ENC_REV: - /* 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 */ - { - struct hmac_ctx ctx; - - hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid); - - /* SKEYID_D */ - hmac_update_chunk(&ctx, st->st_shared); - hmac_update(&ctx, st->st_icookie, COOKIE_SIZE); - hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE); - hmac_update(&ctx, "\0", 1); - hmac_final_chunk(st->st_skeyid_d, "st_skeyid_d in generate_skeyids_iv()", &ctx); - - /* SKEYID_A */ - hmac_reinit(&ctx); - hmac_update_chunk(&ctx, st->st_skeyid_d); - hmac_update_chunk(&ctx, st->st_shared); - hmac_update(&ctx, st->st_icookie, COOKIE_SIZE); - hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE); - hmac_update(&ctx, "\1", 1); - hmac_final_chunk(st->st_skeyid_a, "st_skeyid_a in generate_skeyids_iv()", &ctx); - - /* SKEYID_E */ - hmac_reinit(&ctx); - hmac_update_chunk(&ctx, st->st_skeyid_a); - hmac_update_chunk(&ctx, st->st_shared); - hmac_update(&ctx, st->st_icookie, COOKIE_SIZE); - hmac_update(&ctx, st->st_rcookie, COOKIE_SIZE); - hmac_update(&ctx, "\2", 1); - hmac_final_chunk(st->st_skeyid_e, "st_skeyid_e in generate_skeyids_iv()", &ctx); - } - - /* generate IV */ - { - union hash_ctx hash_ctx; - const struct hash_desc *h = st->st_oakley.hasher; - - st->st_new_iv_len = h->hash_digest_size; - passert(st->st_new_iv_len <= sizeof(st->st_new_iv)); + default: + bad_case(st->st_oakley.auth); + } + + /* generate SKEYID_* from SKEYID */ + { + char buf_skeyid_d[] = { 0x00 }; + char buf_skeyid_a[] = { 0x01 }; + char buf_skeyid_e[] = { 0x02 }; + chunk_t seed_skeyid_d = chunk_from_buf(buf_skeyid_d); + chunk_t seed_skeyid_a = chunk_from_buf(buf_skeyid_a); + chunk_t seed_skeyid_e = chunk_from_buf(buf_skeyid_e); + 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]; + char seed_buf[] = { 0x00 }; + chunk_t seed = chunk_from_buf(seed_buf); + 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("DH_i:", st->st_gi); - DBG_dump_chunk("DH_r:", st->st_gr); - ); - h->hash_init(&hash_ctx); - h->hash_update(&hash_ctx, st->st_gi.ptr, st->st_gi.len); - h->hash_update(&hash_ctx, st->st_gr.ptr, st->st_gr.len); - h->hash_final(st->st_new_iv, &hash_ctx); - } - - /* Oakley Keying Material - * Derived from Skeyid_e: if it is not big enough, generate more - * using the PRF. - * See RFC 2409 "IKE" Appendix B - */ - { - /* const size_t keysize = st->st_oakley.encrypter->keydeflen/BITS_PER_BYTE; */ - const size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE; - u_char keytemp[MAX_OAKLEY_KEY_LEN + MAX_DIGEST_LEN]; - u_char *k = st->st_skeyid_e.ptr; - - if (keysize > st->st_skeyid_e.len) - { - struct hmac_ctx ctx; - size_t i = 0; - - hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_e); - hmac_update(&ctx, "\0", 1); - for (;;) - { - hmac_final(&keytemp[i], &ctx); - i += ctx.hmac_digest_size; - if (i >= keysize) - break; - hmac_reinit(&ctx); - hmac_update(&ctx, &keytemp[i - ctx.hmac_digest_size], ctx.hmac_digest_size); - } - k = keytemp; - } - clonereplacechunk(st->st_enc_key, k, keysize, "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; + 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. @@ -1338,288 +1356,126 @@ generate_skeyids_iv(struct state *st) * 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. - * - * Generating the SIG_I and SIG_R for DSS is an odd perversion of this: - * Most of the logic is the same, but SHA-1 is used in place of HMAC-whatever. - * The extensive common logic is embodied in main_mode_hash_body(). - * See draft-ietf-ipsec-ike-01.txt 4.1 and 6.1.1.2 */ - -typedef void (*hash_update_t)(union hash_ctx *, const u_char *, size_t) ; -static void -main_mode_hash_body(struct state *st -, bool hashi /* Initiator? */ -, const pb_stream *idpl /* ID payload, as PBS */ -, union hash_ctx *ctx -, void (*hash_update_void)(void *, const u_char *input, size_t)) + static void main_mode_hash(struct state *st, chunk_t *hash, bool hashi, + const pb_stream *idpl) { -#define HASH_UPDATE_T (union hash_ctx *, const u_char *input, unsigned int len) - hash_update_t hash_update=(hash_update_t) hash_update_void; -#if 0 /* if desperate to debug hashing */ -# define hash_update(ctx, input, len) { \ - DBG_dump("hash input", input, len); \ - (hash_update)(ctx, input, len); \ + 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); } -#endif + prf = lib->crypto->create_prf(lib->crypto, prf_alg); + prf->set_key(prf, st->st_skeyid); -# define hash_update_chunk(ctx, ch) hash_update((ctx), (ch).ptr, (ch).len) - - if (hashi) - { - hash_update_chunk(ctx, st->st_gi); - hash_update_chunk(ctx, st->st_gr); - hash_update(ctx, st->st_icookie, COOKIE_SIZE); - hash_update(ctx, st->st_rcookie, COOKIE_SIZE); - } - else - { - hash_update_chunk(ctx, st->st_gr); - hash_update_chunk(ctx, st->st_gi); - hash_update(ctx, st->st_rcookie, COOKIE_SIZE); - hash_update(ctx, st->st_icookie, COOKIE_SIZE); - } - - DBG(DBG_CRYPT, DBG_log("hashing %lu bytes of SA" - , (unsigned long) (st->st_p1isa.len - sizeof(struct isakmp_generic)))); - - /* SA_b */ - hash_update(ctx, st->st_p1isa.ptr + sizeof(struct isakmp_generic) - , st->st_p1isa.len - sizeof(struct isakmp_generic)); - - /* 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". - */ - hash_update(ctx - , idpl->start + sizeof(struct isakmp_generic) - , pbs_offset(idpl) - sizeof(struct isakmp_generic)); - -# undef hash_update_chunk -# undef hash_update -} - -static size_t /* length of hash */ -main_mode_hash(struct state *st -, u_char *hash_val /* resulting bytes */ -, bool hashi /* Initiator? */ -, const pb_stream *idpl) /* ID payload, as PBS; cur must be at end */ -{ - struct hmac_ctx ctx; - - hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid); - main_mode_hash_body(st, hashi, idpl, &ctx.hash_ctx, ctx.h->hash_update); - hmac_final(hash_val, &ctx); - return ctx.hmac_digest_size; -} - -#if 0 /* only needed for DSS */ -static void -main_mode_sha1(struct state *st -, u_char *hash_val /* resulting bytes */ -, size_t *hash_len /* length of hash */ -, bool hashi /* Initiator? */ -, const pb_stream *idpl) /* ID payload, as PBS */ -{ - union hash_ctx ctx; - - SHA1Init(&ctx.ctx_sha1); - SHA1Update(&ctx.ctx_sha1, st->st_skeyid.ptr, st->st_skeyid.len); - *hash_len = SHA1_DIGEST_SIZE; - main_mode_hash_body(st, hashi, idpl, &ctx - , (void (*)(union hash_ctx *, const u_char *, unsigned int))&SHA1Update); - SHA1Final(hash_val, &ctx.ctx_sha1); -} -#endif - -/* Create an RSA 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 -RSA_sign_hash(struct connection *c -, u_char sig_val[RSA_MAX_OCTETS] -, const u_char *hash_val, size_t hash_len) -{ - size_t sz = 0; - smartcard_t *sc = c->spd.this.sc; - - if (sc == NULL) /* no smartcard */ - { - const struct RSA_private_key *k = get_RSA_private_key(c); - - if (k == NULL) - return 0; /* failure: no key to use */ - - sz = k->pub.k; - passert(RSA_MIN_OCTETS <= sz && 4 + hash_len < sz && sz <= RSA_MAX_OCTETS); - sign_hash(k, hash_val, hash_len, sig_val, sz); - } - else if (sc->valid) /* if valid pin then sign hash on the smartcard */ - { - lock_certs_and_keys("RSA_sign_hash"); - if (!scx_establish_context(sc) || !scx_login(sc)) + if (hashi) { - scx_release_context(sc); - unlock_certs_and_keys("RSA_sign_hash"); - return 0; + 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); } - - sz = scx_get_keylength(sc); - if (sz == 0) + else { - plog("failed to get keylength from smartcard"); - scx_release_context(sc); - unlock_certs_and_keys("RSA_sign_hash"); - return 0; + 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_CONTROL | DBG_CRYPT, - DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)" - , (int)sc->slot, sc->id) + DBG(DBG_CRYPT, + DBG_log("hashing %u bytes of SA", sa_body.len) ) - sz = scx_sign_hash(sc, hash_val, hash_len, sig_val, sz) ? sz : 0; - if (!pkcs11_keep_state) - scx_release_context(sc); - unlock_certs_and_keys("RSA_sign_hash"); - } - return sz; + 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); } -/* Check a Main Mode RSA Signature against computed hash using RSA public key k. - * - * As a side effect, on success, the public key is copied into the - * state object to record the authenticator. - * - * Can fail because wrong public key is used or because hash disagrees. - * We distinguish because diagnostics should also. - * - * The result is NULL if the Signature checked out. - * Otherwise, the first character of the result indicates - * how far along failure occurred. A greater character signifies - * greater progress. - * - * Classes: - * 0 reserved for caller - * 1 SIG length doesn't match key length -- wrong key - * 2-8 malformed ECB after decryption -- probably wrong key - * 9 decrypted hash != computed hash -- probably correct key - * - * Although the math should be the same for generating and checking signatures, - * it is not: the knowledge of the private key allows more efficient (i.e. - * different) computation for encryption. +/* 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 err_t -try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN], size_t hash_len -, const pb_stream *sig_pbs, pubkey_t *kr -, struct state *st) +static size_t sign_hash(signature_scheme_t scheme, struct connection *c, + u_char sig_val[RSA_MAX_OCTETS], chunk_t hash) { - const u_char *sig_val = sig_pbs->cur; - size_t sig_len = pbs_left(sig_pbs); - u_char s[RSA_MAX_OCTETS]; /* for decrypted sig_val */ - u_char *hash_in_s = &s[sig_len - hash_len]; - const struct RSA_public_key *k = &kr->u.rsa; - - /* decrypt the signature -- reversing RSA_sign_hash */ - if (sig_len != k->k) - { - /* XXX notification: INVALID_KEY_INFORMATION */ - return "1" "SIG length does not match public key length"; - } - - /* actual exponentiation; see PKCS#1 v2.0 5.1 */ - { - chunk_t temp_s; - mpz_t c; - - n_to_mpz(c, sig_val, sig_len); - mpz_powm(c, c, &k->e, &k->n); - - temp_s = mpz_to_n(c, sig_len); /* back to octets */ - memcpy(s, temp_s.ptr, sig_len); - pfree(temp_s.ptr); - mpz_clear(c); - } - - /* sanity check on signature: see if it matches - * PKCS#1 v1.5 8.1 encryption-block formatting - */ - { - err_t ugh = NULL; + size_t sz = 0; + smartcard_t *sc = c->spd.this.sc; - if (s[0] != 0x00) - ugh = "2" "no leading 00"; - else if (hash_in_s[-1] != 0x00) - ugh = "3" "00 separator not present"; - else if (s[1] == 0x01) + if (sc == NULL) /* no smartcard */ { - const u_char *p; + chunk_t sig; + private_key_t *private = get_private_key(c); - for (p = &s[2]; p != hash_in_s - 1; p++) - { - if (*p != 0xFF) + if (private == NULL) { - ugh = "4" "invalid Padding String"; - break; + 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 (s[1] == 0x02) + else if (sc->valid) /* if valid pin then sign hash on the smartcard */ { - const u_char *p; + 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; + } - for (p = &s[2]; p != hash_in_s - 1; p++) - { - if (*p == 0x00) + sz = scx_get_keylength(sc); + if (sz == 0) { - ugh = "5" "invalid Padding String"; - break; + plog("failed to get keylength from smartcard"); + scx_release_context(sc); + unlock_certs_and_keys("sign_hash"); + return 0; } - } - } - else - ugh = "6" "Block Type not 01 or 02"; - if (ugh != NULL) - { - /* note: it might be a good idea to make sure that - * an observer cannot tell what kind of failure happened. - * I don't know what this means in practice. - */ - /* We probably selected the wrong public key for peer: - * SIG Payload decrypted into malformed ECB - */ - /* XXX notification: INVALID_KEY_INFORMATION */ - return ugh; - } - } - - /* We have the decoded hash: see if it matches. */ - if (memcmp(hash_val, hash_in_s, hash_len) != 0) - { - /* good: header, hash, signature, and other payloads well-formed - * good: we could find an RSA Sig key for the peer. - * bad: hash doesn't match - * Guess: sides disagree about key to be used. - */ - DBG_cond_dump(DBG_CRYPT, "decrypted SIG", s, sig_len); - DBG_cond_dump(DBG_CRYPT, "computed HASH", hash_val, hash_len); - /* XXX notification: INVALID_HASH_INFORMATION */ - return "9" "authentication failure: received SIG does not match computed HASH, but message is well-formed"; - } - - /* Success: copy successful key into state. - * There might be an old one if we previously aborted this - * state transition. - */ - unreference_key(&st->st_peer_pubkey); - st->st_peer_pubkey = reference_key(kr); - - return NULL; /* happy happy */ + 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 RSA public keys we can find. +/* 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. * @@ -1630,227 +1486,195 @@ try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN], size_t hash_len * If only we had coroutines. */ struct tac_state { - /* RSA_check_signature's args that take_a_crack needs */ - struct state *st; - const u_char *hash_val; - size_t hash_len; - const pb_stream *sig_pbs; - - /* state carried between calls */ - err_t best_ugh; /* most successful failure */ - int tried_cnt; /* number of keys tried */ - char tried[50]; /* keyids of tried public keys */ - char *tn; /* roof of tried[] */ + 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 -, const char *story USED_BY_DEBUG) +static bool take_a_crack(struct tac_state *s, pubkey_t *kr) { - err_t ugh = try_RSA_signature(s->hash_val, s->hash_len, s->sig_pbs - , kr, s->st); - const struct RSA_public_key *k = &kr->u.rsa; - - s->tried_cnt++; - if (ugh == NULL) - { - DBG(DBG_CRYPT | DBG_CONTROL - , DBG_log("an RSA Sig check passed with *%s [%s]" - , k->keyid, story)); - return TRUE; - } - else - { - DBG(DBG_CRYPT - , DBG_log("an RSA Sig check failure %s with *%s [%s]" - , ugh + 1, k->keyid, story)); - if (s->best_ugh == NULL || s->best_ugh[0] < ugh[0]) - s->best_ugh = ugh; - if (ugh[0] > '0' - && s->tn - s->tried + KEYID_BUF + 2 < (ptrdiff_t)sizeof(s->tried)) - { - strcpy(s->tn, " *"); - strcpy(s->tn + 2, k->keyid); - s->tn += strlen(s->tn); + public_key_t *pub_key = kr->public_key; + identification_t *keyid = pub_key->get_id(pub_key, ID_PUBKEY_INFO_SHA1); + signature_scheme_t scheme; + + s->tried_cnt++; + scheme = oakley_to_signature_scheme(s->st->st_oakley.auth); + + if (pub_key->verify(pub_key, scheme, s->hash, s->sig)) + { + DBG(DBG_CRYPT | DBG_CONTROL, + DBG_log("%s check passed with keyid %Y", + 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 %Y", + enum_show(&oakley_auth_names, s->st->st_oakley.auth), keyid) + ) + return FALSE; } - return FALSE; - } } -static stf_status -RSA_check_signature(const struct id* peer -, struct state *st -, const u_char hash_val[MAX_DIGEST_LEN] -, size_t hash_len -, const pb_stream *sig_pbs +static stf_status check_signature(key_type_t key_type, const struct id* peer, + struct state *st, chunk_t hash, + const pb_stream *sig_pbs, #ifdef USE_KEYRR -, const pubkey_list_t *keys_from_dns + const pubkey_list_t *keys_from_dns, #endif /* USE_KEYRR */ -, const struct gw_info *gateways_from_dns -) + const struct gw_info *gateways_from_dns) { - const struct connection *c = st->st_connection; - struct tac_state s; - err_t dns_ugh = NULL; - - s.st = st; - s.hash_val = hash_val; - s.hash_len = hash_len; - s.sig_pbs = sig_pbs; - - s.best_ugh = NULL; - s.tried_cnt = 0; - s.tn = s.tried; - - /* 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 - && same_id(&gw->gw_id, &c->spd.that.id) - && take_a_crack(&s, gw->key, "key saved from DNS TXT")) - return STF_OK; - } - } + const struct connection *c = st->st_connection; + struct tac_state s; - /* try all appropriate Public keys */ - { - pubkey_list_t *p, **pp; + s.st = st; + s.hash = hash; + s.sig = chunk_create(sig_pbs->cur, pbs_left(sig_pbs)); + s.tried_cnt = 0; - pp = &pubkeys; + /* try all gateway records hung off c */ + if (c->policy & POLICY_OPPO) + { + struct gw_info *gw; - for (p = pubkeys; p != NULL; p = *pp) + 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 && same_id(&gw->gw_id, &c->spd.that.id)&& + take_a_crack(&s, gw->key)) + { + return STF_OK; + } + } + } + + /* try all appropriate Public keys */ { - pubkey_t *key = p->key; + pubkey_list_t *p, **pp; - if (key->alg == PUBKEY_ALG_RSA && same_id(peer, &key->id)) - { - time_t now = time(NULL); + pp = &pubkeys; - /* check if found public key has expired */ - if (key->until_time != UNDEFINED_TIME && key->until_time < now) + for (p = pubkeys; p != NULL; p = *pp) { - loglog(RC_LOG_SERIOUS, - "cached RSA public key has expired and has been deleted"); - *pp = free_public_keyentry(p); - continue; /* continue with next public key */ - } + pubkey_t *key = p->key; + key_type_t type = key->public_key->get_type(key->public_key); - if (take_a_crack(&s, key, "preloaded key")) - return STF_OK; - } - pp = &p->next; - } + if (type == key_type && same_id(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 (evidenced by best_ugh == NULL) - * and that side of connection is key_from_DNS_on_demand - * then go search DNS for keys for peer. - */ - if (s.best_ugh == NULL && c->spd.that.key_from_DNS_on_demand) - { - if (gateways_from_dns != NULL) + /* 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) { - /* TXT keys */ - const struct gw_info *gwp; + 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, "key from DNS TXT")) - return STF_OK; - } + 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; + 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, "key from DNS KEY")) - return STF_OK; - } + 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; + else + { + /* nothing yet: ask for asynch DNS lookup */ + return STF_SUSPEND; + } } - } - - /* no acceptable key was found: diagnose */ - { - char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */ - (void) idtoa(peer, id_buf, sizeof(id_buf)); - - if (s.best_ugh == NULL) + /* no acceptable key was found: diagnose */ { - if (dns_ugh == NULL) - loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'" - , id_buf); - else - loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'" - "; DNS search for KEY failed (%s)" - , id_buf, dns_ugh); + char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */ - /* ??? is this the best code there is? */ - return STF_FAIL + INVALID_KEY_INFORMATION; - } + idtoa(peer, id_buf, sizeof(id_buf)); - if (s.best_ugh[0] == '9') - { - loglog(RC_LOG_SERIOUS, "%s", s.best_ugh + 1); - /* XXX Could send notification back */ - return STF_FAIL + INVALID_HASH_INFORMATION; - } - else - { - if (s.tried_cnt == 1) - { - loglog(RC_LOG_SERIOUS - , "Signature check (on %s) failed (wrong key?); tried%s" - , id_buf, s.tried); - DBG(DBG_CONTROL, - DBG_log("public key for %s failed:" - " decrypted SIG payload into a malformed ECB (%s)" - , id_buf, s.best_ugh + 1)); - } - else - { - loglog(RC_LOG_SERIOUS - , "Signature check (on %s) failed:" - " tried%s keys but none worked." - , id_buf, s.tried); - DBG(DBG_CONTROL, - DBG_log("all %d public keys for %s failed:" - " best decrypted SIG payload into a malformed ECB (%s)" - , s.tried_cnt, id_buf, s.best_ugh + 1)); - } - return STF_FAIL + INVALID_KEY_INFORMATION; + if (s.tried_cnt == 0) + { + loglog(RC_LOG_SERIOUS, "no public key known for '%s'", id_buf); + } + else if (s.tried_cnt == 1) + { + loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: " + " wrong key?; tried %d", id_buf, s.tried_cnt); + DBG(DBG_CONTROL, + DBG_log("public key for '%s' failed: " + "decrypted SIG payload into a malformed ECB", id_buf) + ) + } + else + { + loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: " + "tried %d keys but none worked.", id_buf, s.tried_cnt); + DBG(DBG_CONTROL, + DBG_log("all %d public keys for '%s' failed: " + "best decrypted SIG payload into a malformed ECB", + s.tried_cnt, id_buf) + ) + } + return STF_FAIL + INVALID_KEY_INFORMATION; } - } } -static notification_t -accept_nonce(struct msg_digest *md, chunk_t *dest, const char *name) +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 PAYLOAD_MALFORMED; /* ??? */ - } - clonereplacechunk(*dest, nonce_pbs->cur, len, "nonce"); - return NOTHING_WRONG; + 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 PAYLOAD_MALFORMED; /* ??? */ + } + free(dest->ptr); + *dest = chunk_create(nonce_pbs->cur, len); + *dest = chunk_clone(*dest); + return NOTHING_WRONG; } /* encrypt message, sans fixed part of header @@ -1861,36 +1685,51 @@ accept_nonce(struct msg_digest *md, chunk_t *dest, const char *name) bool encrypt_message(pb_stream *pbs, struct state *st) { - const struct encrypt_desc *e = st->st_oakley.encrypter; - u_int8_t *enc_start = pbs->start + sizeof(struct isakmp_hdr); - size_t enc_len = pbs_offset(pbs) - sizeof(struct isakmp_hdr); - - DBG_cond_dump(DBG_CRYPT | DBG_RAW, "encrypting:\n", enc_start, enc_len); - - /* 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, e->enc_blocksize); - - if (padding != 0) + 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; + 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); + + /* Pad up to multiple of encryption blocksize. + * See the description associated with the definition of + * struct isakmp_hdr in packet.h. + */ { - if (!out_zero(padding, pbs, "encryption padding")) - return FALSE; - enc_len += padding; + 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))); + DBG(DBG_CRYPT, DBG_log("encrypting using %s", enum_show(&oakley_enc_names, st->st_oakley.encrypt))); + data = chunk_create(enc_start, enc_len); - /* e->crypt(TRUE, enc_start, enc_len, st); */ - crypto_cbc_encrypt(e, TRUE, enc_start, enc_len, st); + /* form iv by truncation */ + st->st_new_iv_len = crypter_block_size; + iv = chunk_create(st->st_new_iv, st->st_new_iv_len); - update_iv(st); - DBG_cond_dump(DBG_CRYPT, "next IV:", st->st_iv, st->st_iv_len); - close_message(pbs); - return TRUE; + crypter->set_key(crypter, st->st_enc_key); + crypter->encrypt(crypter, data, iv, NULL); + crypter->destroy(crypter); + + new_iv = data.ptr + data.len - crypter_block_size; + memcpy(st->st_new_iv, new_iv, crypter_block_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. @@ -1899,31 +1738,33 @@ encrypt_message(pb_stream *pbs, struct state *st) * 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, const u_char *start, const u_char *roof -, const struct state *st, const msgid_t *msgid, bool hash2) +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) { - struct hmac_ctx ctx; - -#if 0 /* if desperate to debug hashing */ -# define hmac_update(ctx, ptr, len) { \ - DBG_dump("hash input", (ptr), (len)); \ - (hmac_update)((ctx), (ptr), (len)); \ - } - DBG_dump("hash key", st->st_skeyid_a.ptr, st->st_skeyid_a.len); -#endif - hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); - hmac_update(&ctx, (const void *) msgid, sizeof(msgid_t)); - if (hash2) - hmac_update_chunk(&ctx, st->st_ni); /* include Ni_b in the hash */ - hmac_update(&ctx, start, roof-start); - hmac_final(dest, &ctx); - - DBG(DBG_CRYPT, - DBG_log("HASH(%d) computed:", hash2 + 1); - DBG_dump("", dest, ctx.hmac_digest_size)); - return ctx.hmac_digest_size; -# undef hmac_update + 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). @@ -1932,44 +1773,54 @@ quick_mode_hash12(u_char *dest, const u_char *start, const u_char *roof * 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) +static size_t quick_mode_hash3(u_char *dest, struct state *st) { - struct hmac_ctx ctx; - - hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); - hmac_update(&ctx, "\0", 1); - hmac_update(&ctx, (u_char *) &st->st_msgid, sizeof(st->st_msgid)); - hmac_update_chunk(&ctx, st->st_ni); - hmac_update_chunk(&ctx, st->st_nr); - hmac_final(dest, &ctx); - DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, ctx.hmac_digest_size); - return ctx.hmac_digest_size; + char seed_buf[] = { 0x00 }; + chunk_t seed_chunk = chunk_from_buf(seed_buf); + 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) +void init_phase2_iv(struct state *st, const msgid_t *msgid) { - const struct hash_desc *h = st->st_oakley.hasher; - union hash_ctx ctx; + 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; - DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:" - , st->st_ph1_iv, st->st_ph1_iv_len); + hash_alg = oakley_to_hash_algorithm(st->st_oakley.hash); + hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - st->st_new_iv_len = h->hash_digest_size; - passert(st->st_new_iv_len <= sizeof(st->st_new_iv)); + DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:", + st->st_ph1_iv, st->st_ph1_iv_len); - h->hash_init(&ctx); - h->hash_update(&ctx, st->st_ph1_iv, st->st_ph1_iv_len); - passert(*msgid != 0); - h->hash_update(&ctx, (const u_char *)msgid, sizeof(*msgid)); - h->hash_final(st->st_new_iv, &ctx); + 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); + DBG_cond_dump(DBG_CRYPT, "computed Phase 2 IV:", + st->st_new_iv, st->st_new_iv_len); } /* Initiate quick mode. @@ -1978,474 +1829,467 @@ init_phase2_iv(struct state *st, const msgid_t *msgid) * 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) +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; + 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; - if (!subnetishost(net)) - { - maskof(net, &ta); + networkof(net, &ta); tal = addrbytesptr(&ta, &tbp); - if (!out_raw(tbp, tal, &id_pbs, "client mask")) - return FALSE; - } + 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; + close_output_pbs(&id_pbs); + return TRUE; } -stf_status -quick_outI1(int whack_sock -, struct state *isakmp_sa -, struct connection *c -, lset_t policy -, unsigned long try -, so_serial_t replacing) +stf_status quick_outI1(int whack_sock, struct state *isakmp_sa, + struct connection *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; - - 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 - */ + 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; + + 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) + 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; - } + /* 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) */ + /* [ 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)) + if (st->st_pfs_group != NULL) { - reset_cur_state(); - return STF_INTERNAL_ERROR; + 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)) + /* [ IDci, IDcr ] out */ + if (has_client) { - reset_cur_state(); - return STF_INTERNAL_ERROR; + /* 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)) + /* Send NAT-OA if our address is NATed */ + if (send_natoa) { - reset_cur_state(); - return STF_INTERNAL_ERROR; + 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); + /* 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 */ + /* 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); - 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; + } - if (!encrypt_message(&rbody, st)) - { + /* 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_INTERNAL_ERROR; - } - - /* save packet, now that we know its size */ - clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply) - , "reply packet from quick_outI1"); - - /* 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; + return STF_OK; } /* * Decode the CERT payload of Phase 1. */ -static void -decode_cert(struct msg_digest *md) +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) - { - x509cert_t cert = empty_x509cert; - if (parse_x509cert(blob, 0, &cert)) - { - if (verify_x509cert(&cert, strict_crl_policy, &valid_until)) + 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) + { + x509cert_t cert = empty_x509cert; + if (parse_x509cert(blob, 0, &cert)) + { + if (verify_x509cert(&cert, strict_crl_policy, &valid_until)) + { + DBG(DBG_PARSING, + DBG_log("Public key validated") + ) + add_x509_public_key(&cert, valid_until, DAL_SIGNED); + } + else + { + plog("X.509 certificate rejected"); + } + DESTROY_IF(cert.public_key); + free_generalNames(cert.subjectAltName, FALSE); + free_generalNames(cert.crlDistributionPoints, FALSE); + } + else + plog("Syntax error in X.509 certificate"); + } + else if (cert->isacert_type == CERT_PKCS7_WRAPPED_X509) { - DBG(DBG_PARSING, - DBG_log("Public key validated") - ) - add_x509_public_key(&cert, valid_until, DAL_SIGNED); + x509cert_t *cert = NULL; + + if (pkcs7_parse_signedData(blob, NULL, &cert, NULL, NULL)) + store_x509certs(&cert, strict_crl_policy); + else + plog("Syntax error in PKCS#7 wrapped X.509 certificates"); } else { - plog("X.509 certificate rejected"); + 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); } - free_generalNames(cert.subjectAltName, FALSE); - free_generalNames(cert.crlDistributionPoints, FALSE); - } - else - plog("Syntax error in X.509 certificate"); - } - else if (cert->isacert_type == CERT_PKCS7_WRAPPED_X509) - { - x509cert_t *cert = NULL; - - if (pkcs7_parse_signedData(blob, NULL, &cert, NULL, NULL)) - store_x509certs(&cert, strict_crl_policy); - else - plog("Syntax error in PKCS#7 wrapped X.509 certificates"); - } - 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, struct connection *c) +static void decode_cr(struct msg_digest *md, struct connection *c) { - struct payload_digest *p; + 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; + 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); + DBG_cond_dump_chunk(DBG_PARSING, "CR", ca_name); - if (cr->isacr_type == CERT_X509_SIGNATURE) - { - char buf[BUF_LEN]; + if (cr->isacr_type == CERT_X509_SIGNATURE) + { + char buf[BUF_LEN]; - if (ca_name.len > 0) - { - generalName_t *gn; - - if (!is_asn1(ca_name)) - continue; - - gn = alloc_thing(generalName_t, "generalName"); - clonetochunk(ca_name, ca_name.ptr,ca_name.len, "ca name"); - gn->kind = GN_DIRECTORY_NAME; - gn->name = ca_name; - gn->next = c->requested_ca; - c->requested_ca = gn; - } - c->got_certrequest = TRUE; - - DBG(DBG_PARSING | DBG_CONTROL, - dntoa_or_null(buf, BUF_LEN, ca_name, "%any"); - DBG_log("requested CA: '%s'", buf); - ) + if (ca_name.len > 0) + { + generalName_t *gn; + + if (!is_asn1(ca_name)) + continue; + + gn = malloc_thing(generalName_t); + ca_name = chunk_clone(ca_name); + gn->kind = GN_DIRECTORY_NAME; + gn->name = ca_name; + gn->next = c->requested_ca; + c->requested_ca = gn; + } + c->got_certrequest = TRUE; + + DBG(DBG_PARSING | DBG_CONTROL, + dntoa_or_null(buf, BUF_LEN, ca_name, "%any"); + DBG_log("requested CA: '%s'", buf); + ) + } + else + loglog(RC_LOG_SERIOUS, "ignoring %s certificate request payload", + enum_show(&cert_type_names, cr->isacr_type)); } - 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 RSA key or ID. + * may change the peer's public key or ID. */ -static bool -decode_peer_id(struct msg_digest *md, struct id *peer) +static bool decode_peer_id(struct msg_digest *md, struct id *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; - - /* 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; - } - - peer->kind = id->isaid_idtype; - - switch (peer->kind) - { - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - /* failure mode for initaddr is probably inappropriate address length */ + 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; + + /* 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)) { - err_t ugh = initaddr(id_pbs->cur, pbs_left(id_pbs) - , peer->kind == ID_IPV4_ADDR? AF_INET : AF_INET6 - , &peer->ip_addr); - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "improper %s identification payload: %s" - , enum_show(&ident_names, peer->kind), ugh); - /* XXX Could send notification back */ - return FALSE; - } + 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); } - break; - - case ID_USER_FQDN: - if (memchr(id_pbs->cur, '@', pbs_left(id_pbs)) == NULL) + 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, "peer's ID_USER_FQDN contains no @"); - return FALSE; + 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; } - /* FALLTHROUGH */ - case ID_FQDN: - if (memchr(id_pbs->cur, '\0', pbs_left(id_pbs)) != NULL) + + peer->kind = id->isaid_idtype; + + switch (peer->kind) { - loglog(RC_LOG_SERIOUS, "Phase 1 ID Payload of type %s contains a NUL" - , enum_show(&ident_names, peer->kind)); - return FALSE; - } + case ID_IPV4_ADDR: + case ID_IPV6_ADDR: + /* failure mode for initaddr is probably inappropriate address length */ + { + err_t ugh = initaddr(id_pbs->cur, pbs_left(id_pbs) + , peer->kind == ID_IPV4_ADDR? AF_INET : AF_INET6 + , &peer->ip_addr); + + if (ugh != NULL) + { + loglog(RC_LOG_SERIOUS, "improper %s identification payload: %s" + , enum_show(&ident_names, peer->kind), ugh); + /* XXX Could send notification back */ + return FALSE; + } + } + break; + + case ID_USER_FQDN: + if (memchr(id_pbs->cur, '@', pbs_left(id_pbs)) == NULL) + { + loglog(RC_LOG_SERIOUS, "peer's ID_USER_FQDN contains no @"); + return FALSE; + } + /* FALLTHROUGH */ + case ID_FQDN: + if (memchr(id_pbs->cur, '\0', pbs_left(id_pbs)) != NULL) + { + loglog(RC_LOG_SERIOUS, "Phase 1 ID Payload of type %s contains a NUL" + , enum_show(&ident_names, peer->kind)); + return FALSE; + } - /* ??? ought to do some more sanity check, but what? */ + /* ??? ought to do some more sanity check, but what? */ - setchunk(peer->name, id_pbs->cur, pbs_left(id_pbs)); - break; + peer->name = chunk_create(id_pbs->cur, pbs_left(id_pbs)); + break; - case ID_KEY_ID: - setchunk(peer->name, id_pbs->cur, pbs_left(id_pbs)); - DBG(DBG_PARSING, - DBG_dump_chunk("KEY ID:", peer->name)); - break; + case ID_KEY_ID: + peer->name = chunk_create(id_pbs->cur, pbs_left(id_pbs)); + DBG(DBG_PARSING, + DBG_dump_chunk("KEY ID:", peer->name)); + break; - case ID_DER_ASN1_DN: - setchunk(peer->name, id_pbs->cur, pbs_left(id_pbs)); - DBG(DBG_PARSING, - DBG_dump_chunk("DER ASN1 DN:", peer->name)); - break; + case ID_DER_ASN1_DN: + peer->name = chunk_create(id_pbs->cur, pbs_left(id_pbs)); + DBG(DBG_PARSING, + DBG_dump_chunk("DER ASN1 DN:", peer->name)); + break; - default: - /* XXX Could send notification back */ - loglog(RC_LOG_SERIOUS, "Unacceptable identity type (%s) in Phase 1 ID Payload" - , enum_show(&ident_names, peer->kind)); - return FALSE; - } + default: + /* XXX Could send notification back */ + loglog(RC_LOG_SERIOUS, "Unacceptable identity type (%s) in Phase 1 ID Payload" + , enum_show(&ident_names, peer->kind)); + return FALSE; + } - { - char buf[BUF_LEN]; + { + char buf[BUF_LEN]; - idtoa(peer, buf, sizeof(buf)); - plog("Peer ID is %s: '%s'", - enum_show(&ident_names, id->isaid_idtype), buf); - } + idtoa(peer, buf, sizeof(buf)); + plog("Peer ID is %s: '%s'", + enum_show(&ident_names, id->isaid_idtype), buf); + } - /* check for certificates */ - decode_cert(md); - return TRUE; + /* check for certificates */ + decode_cert(md); + return TRUE; } /* Now that we've decoded the ID payload, let's see if we @@ -2454,111 +2298,111 @@ decode_peer_id(struct msg_digest *md, struct id *peer) * - 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, struct id *peer, bool initiator) +static bool switch_connection(struct msg_digest *md, struct id *peer, + bool initiator) { - struct state *const st = md->st; - struct connection *c = st->st_connection; - - chunk_t peer_ca = (st->st_peer_pubkey != NULL) - ? st->st_peer_pubkey->issuer : empty_chunk; + struct state *const st = md->st; + struct connection *c = st->st_connection; - DBG(DBG_CONTROL, - char buf[BUF_LEN]; + chunk_t peer_ca = (st->st_peer_pubkey != NULL) + ? st->st_peer_pubkey->issuer : chunk_empty; - dntoa_or_null(buf, BUF_LEN, peer_ca, "%none"); - DBG_log("peer CA: '%s'", buf); - ) + DBG(DBG_CONTROL, + char buf[BUF_LEN]; - if (initiator) - { - int pathlen; + dntoa_or_null(buf, BUF_LEN, peer_ca, "%none"); + DBG_log("peer CA: '%s'", buf); + ) - if (!same_id(&c->spd.that.id, peer)) + if (initiator) { - char expect[BUF_LEN] - , found[BUF_LEN]; + int pathlen; - idtoa(&c->spd.that.id, expect, sizeof(expect)); - idtoa(peer, found, sizeof(found)); - loglog(RC_LOG_SERIOUS - , "we require peer to have ID '%s', but peer declares '%s'" - , expect, found); - return FALSE; - } + if (!same_id(&c->spd.that.id, peer)) + { + char expect[BUF_LEN] + , found[BUF_LEN]; + + idtoa(&c->spd.that.id, expect, sizeof(expect)); + idtoa(peer, found, sizeof(found)); + loglog(RC_LOG_SERIOUS + , "we require peer to have ID '%s', but peer declares '%s'" + , expect, found); + return FALSE; + } - DBG(DBG_CONTROL, - char buf[BUF_LEN]; + DBG(DBG_CONTROL, + char buf[BUF_LEN]; - dntoa_or_null(buf, BUF_LEN, c->spd.that.ca, "%none"); - DBG_log("required CA: '%s'", buf); - ) + dntoa_or_null(buf, BUF_LEN, c->spd.that.ca, "%none"); + DBG_log("required CA: '%s'", buf); + ) - if (!trusted_ca(peer_ca, c->spd.that.ca, &pathlen)) - { - loglog(RC_LOG_SERIOUS - , "we don't accept the peer's CA"); - return FALSE; + 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 - { - struct connection *r; + else + { + struct connection *r; - /* check for certificate requests */ - decode_cr(md, c); + /* check for certificate requests */ + decode_cr(md, c); - r = refine_host_connection(st, peer, peer_ca); + r = refine_host_connection(st, peer, peer_ca); - /* delete the collected certificate requests */ - free_generalNames(c->requested_ca, TRUE); - c->requested_ca = NULL; + /* delete the collected certificate requests */ + free_generalNames(c->requested_ca, TRUE); + c->requested_ca = NULL; - if (r == NULL) - { - char buf[BUF_LEN]; + if (r == NULL) + { + char buf[BUF_LEN]; - idtoa(peer, buf, sizeof(buf)); - loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%s'", buf); - return FALSE; - } + idtoa(peer, buf, sizeof(buf)); + loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%s'", buf); + return FALSE; + } - DBG(DBG_CONTROL, - char buf[BUF_LEN]; + DBG(DBG_CONTROL, + char buf[BUF_LEN]; - dntoa_or_null(buf, BUF_LEN, r->spd.this.ca, "%none"); - DBG_log("offered CA: '%s'", buf); - ) + dntoa_or_null(buf, BUF_LEN, r->spd.this.ca, "%none"); + DBG_log("offered CA: '%s'", buf); + ) - if (r != c) - { - /* apparently, r is an improvement on c -- replace */ + 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); - } + 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; + /* 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) - { - free_id_content(&c->spd.that.id); - c->spd.that.id = *peer; - c->spd.that.has_id_wildcards = FALSE; - unshare_id_content(&c->spd.that.id); + st->st_connection = r; /* kill reference to c */ + set_cur_connection(r); + connection_discard(c); + } + else if (c->spd.that.has_id_wildcards) + { + free_id_content(&c->spd.that.id); + c->spd.that.id = *peer; + c->spd.that.has_id_wildcards = FALSE; + unshare_id_content(&c->spd.that.id); + } } - } - return TRUE; + return TRUE; } /* Decode the variable part of an ID packet (during Quick Mode). @@ -2566,227 +2410,218 @@ switch_connection(struct msg_digest *md, struct id *peer, bool initiator) * 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) +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; + 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); + /* 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: + switch (id->isaiid_idtype) { - 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: + 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; } - case ID_IPV4_ADDR_SUBNET: - case ID_IPV6_ADDR_SUBNET: + switch (id->isaiid_idtype) { - ip_address temp_address, temp_mask; - err_t ugh; + case ID_IPV4_ADDR: + case ID_IPV6_ADDR: + { + ip_address temp_address; + 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, + 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: { - char temp_buff[SUBNETTOT_BUF]; + ip_address temp_address, temp_mask; + err_t ugh; - subnettot(net, 0, temp_buff, sizeof(temp_buff)); - DBG_log("%s is subnet %s", which, temp_buff); - }); - break; - } + 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]; - case ID_IPV4_ADDR_RANGE: - case ID_IPV6_ADDR_RANGE: - { - ip_address temp_address_from, temp_address_to; - err_t ugh; + subnettot(net, 0, temp_buff, sizeof(temp_buff)); + DBG_log("%s is subnet %s", which, temp_buff); + }); + break; + } - 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, + case ID_IPV4_ADDR_RANGE: + case ID_IPV6_ADDR_RANGE: { - char temp_buff[SUBNETTOT_BUF]; + ip_address temp_address_from, temp_address_to; + err_t ugh; - subnettot(net, 0, temp_buff, sizeof(temp_buff)); - DBG_log("%s is subnet %s (received as range)" - , which, temp_buff); - }); - break; + 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); + /* 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) - ) + DBG(DBG_PARSING | DBG_CONTROL, + DBG_log("%s protocol/port is %d/%d", which, id->isaiid_protoid, id->isaiid_port) + ) - return TRUE; + 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) +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; + ip_subnet net_temp; - if (!decode_net_id(id, id_pbs, &net_temp, which)) - return FALSE; + 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; + 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) +static bool has_preloaded_public_key(struct state *st) { - struct connection *c = st->st_connection; + struct connection *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) + /* do not consider rw connections since + * the peer's identity must be known + */ + if (c->kind == CK_PERMANENT) { - pubkey_t *key = p->key; + pubkey_list_t *p; - if (key->alg == PUBKEY_ALG_RSA && - same_id(&c->spd.that.id, &key->id) && - key->until_time == UNDEFINED_TIME) - { - /* found a preloaded public key */ - return TRUE; - } + /* 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 && same_id(&c->spd.that.id, &key->id) && + key->until_time == UNDEFINED_TIME) + { + /* found a preloaded public key */ + return TRUE; + } + } } - } - return FALSE; + return FALSE; } /* @@ -2794,161 +2629,181 @@ has_preloaded_public_key(struct state *st) * 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) +static void compute_proto_keymat(struct state *st, u_int8_t protoid, + struct ipsec_proto_info *pi) { - 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: - switch (pi->attrs.transid) - { - case ESP_NULL: - needed_len = 0; - break; - case ESP_DES: - needed_len = DES_CBC_BLOCK_SIZE; - break; - case ESP_3DES: - needed_len = DES_CBC_BLOCK_SIZE * 3; - break; - default: + 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: + switch (pi->attrs.transid) + { + case ESP_NULL: + needed_len = 0; + break; + case ESP_DES: + needed_len = DES_CBC_BLOCK_SIZE; + break; + case ESP_3DES: + needed_len = DES_CBC_BLOCK_SIZE * 3; + break; + default: #ifndef NO_KERNEL_ALG - if((needed_len=kernel_alg_esp_enc_keylen(pi->attrs.transid))>0) { - /* XXX: check key_len "coupling with kernel.c's */ - if (pi->attrs.key_len) { - needed_len=pi->attrs.key_len/8; - DBG(DBG_PARSING, DBG_log("compute_proto_keymat:" - "key_len=%d from peer", - (int)needed_len)); - } - break; - } + if((needed_len=kernel_alg_esp_enc_keylen(pi->attrs.transid))>0) { + /* XXX: check key_len "coupling with kernel.c's */ + if (pi->attrs.key_len) { + needed_len=pi->attrs.key_len/8; + DBG(DBG_PARSING, DBG_log("compute_proto_keymat:" + "key_len=%d from peer", + (int)needed_len)); + } + break; + } #endif - bad_case(pi->attrs.transid); - } + bad_case(pi->attrs.transid); + } #ifndef NO_KERNEL_ALG - DBG(DBG_PARSING, DBG_log("compute_proto_keymat:" - "needed_len (after ESP enc)=%d", - (int)needed_len)); - if (kernel_alg_esp_auth_ok(pi->attrs.auth, NULL)) { - needed_len += kernel_alg_esp_auth_keylen(pi->attrs.auth); - } else + DBG(DBG_PARSING, DBG_log("compute_proto_keymat:" + "needed_len (after ESP enc)=%d", + (int)needed_len)); + if (kernel_alg_esp_auth_ok(pi->attrs.auth, NULL)) { + needed_len += kernel_alg_esp_auth_keylen(pi->attrs.auth); + } else #endif - 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); - } - DBG(DBG_PARSING, DBG_log("compute_proto_keymat:" - "needed_len (after ESP auth)=%d", - (int)needed_len)); - 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; - - /* Allocate space for the keying material. - * Although only needed_len bytes are desired, we - * must round up to a multiple of ctx.hmac_digest_size - * so that our buffer isn't overrun. - */ - { - struct hmac_ctx ctx_me, ctx_peer; - size_t needed_space; /* space needed for keying material (rounded up) */ - size_t i; - - hmac_init_chunk(&ctx_me, st->st_oakley.hasher, st->st_skeyid_d); - ctx_peer = ctx_me; /* duplicate initial conditions */ - - needed_space = needed_len + pad_up(needed_len, ctx_me.hmac_digest_size); - replace(pi->our_keymat, alloc_bytes(needed_space, "keymat in compute_keymat()")); - replace(pi->peer_keymat, alloc_bytes(needed_space, "peer_keymat in quick_inI1_outR1()")); - - for (i = 0;; ) - { - if (st->st_shared.ptr != NULL) - { - /* PFS: include the g^xy */ - hmac_update_chunk(&ctx_me, st->st_shared); - hmac_update_chunk(&ctx_peer, st->st_shared); - } - hmac_update(&ctx_me, &protoid, sizeof(protoid)); - hmac_update(&ctx_peer, &protoid, sizeof(protoid)); - - hmac_update(&ctx_me, (u_char *)&pi->our_spi, sizeof(pi->our_spi)); - hmac_update(&ctx_peer, (u_char *)&pi->attrs.spi, sizeof(pi->attrs.spi)); - - hmac_update_chunk(&ctx_me, st->st_ni); - hmac_update_chunk(&ctx_peer, st->st_ni); - - hmac_update_chunk(&ctx_me, st->st_nr); - hmac_update_chunk(&ctx_peer, st->st_nr); - - hmac_final(pi->our_keymat + i, &ctx_me); - hmac_final(pi->peer_keymat + i, &ctx_peer); - - i += ctx_me.hmac_digest_size; - if (i >= needed_space) - break; + 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); + } + DBG(DBG_PARSING, DBG_log("compute_proto_keymat:" + "needed_len (after ESP auth)=%d", + (int)needed_len)); + 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; + + /* Allocate space for the keying material. Although only needed_len bytes + * are desired, we must round up to a multiple of hash_size + * so that our buffer isn't overrun. + */ + { + size_t needed_space; /* space needed for keying material (rounded up) */ + size_t i, prf_block_size; + chunk_t protoid_chunk = chunk_from_thing(protoid); + chunk_t spi_our = chunk_from_thing(pi->our_spi); + chunk_t spi_peer = chunk_from_thing(pi->attrs.spi); + pseudo_random_function_t prf_alg; + prf_t *prf_our, *prf_peer; + + prf_alg = oakley_to_prf(st->st_oakley.hash); + prf_our = lib->crypto->create_prf(lib->crypto, prf_alg); + prf_peer = lib->crypto->create_prf(lib->crypto, prf_alg); + prf_our->set_key(prf_our, st->st_skeyid_d); + prf_peer->set_key(prf_peer, st->st_skeyid_d); + prf_block_size = prf_our->get_block_size(prf_our); + + needed_space = needed_len + pad_up(needed_len, prf_block_size); + replace(pi->our_keymat, malloc(needed_space)); + replace(pi->peer_keymat, malloc(needed_space)); + + for (i = 0;; ) + { + char *keymat_i_our = pi->our_keymat + i; + char *keymat_i_peer = pi->peer_keymat + i; + chunk_t keymat_our = { keymat_i_our, prf_block_size }; + chunk_t keymat_peer = { keymat_i_peer, prf_block_size }; + + if (st->st_shared.ptr != NULL) + { + /* PFS: include the g^xy */ + prf_our->get_bytes(prf_our, st->st_shared, NULL); + prf_peer->get_bytes(prf_peer, st->st_shared, NULL); + } + prf_our->get_bytes(prf_our, protoid_chunk, NULL); + prf_peer->get_bytes(prf_peer, protoid_chunk, NULL); + + prf_our->get_bytes(prf_our, spi_our, NULL); + prf_peer->get_bytes(prf_peer, spi_peer, NULL); - /* more keying material needed: prepare to go around again */ + prf_our->get_bytes(prf_our, st->st_ni, NULL); + prf_peer->get_bytes(prf_peer, st->st_ni, NULL); - hmac_reinit(&ctx_me); - hmac_reinit(&ctx_peer); + prf_our->get_bytes(prf_our, st->st_nr, keymat_i_our); + prf_peer->get_bytes(prf_peer, st->st_nr, keymat_i_peer); + + i += prf_block_size; + if (i >= needed_space) + { + break; + } - hmac_update(&ctx_me, pi->our_keymat + i - ctx_me.hmac_digest_size - , ctx_me.hmac_digest_size); - hmac_update(&ctx_peer, pi->peer_keymat + i - ctx_peer.hmac_digest_size - , ctx_peer.hmac_digest_size); + /* more keying material needed: prepare to go around again */ + prf_our->get_bytes(prf_our, keymat_our, NULL); + prf_peer->get_bytes(prf_peer, keymat_peer, NULL); + } + prf_our->destroy(prf_our); + prf_peer->destroy(prf_peer); } - } + DBG(DBG_CRYPT, + DBG_dump("KEYMAT computed:\n", pi->our_keymat, pi->keymat_len); + DBG_dump("Peer KEYMAT computed:\n", pi->peer_keymat, pi->keymat_len)); +} - DBG(DBG_CRYPT, - DBG_dump("KEYMAT computed:\n", pi->our_keymat, pi->keymat_len); - DBG_dump("Peer KEYMAT computed:\n", pi->peer_keymat, pi->keymat_len)); +static void compute_keymats(struct state *st) +{ + if (st->st_ah.present) + compute_proto_keymat(st, PROTO_IPSEC_AH, &st->st_ah); + if (st->st_esp.present) + compute_proto_keymat(st, PROTO_IPSEC_ESP, &st->st_esp); } -static void -compute_keymats(struct state *st) +static bool uses_pubkey_auth(int auth) { - if (st->st_ah.present) - compute_proto_keymat(st, PROTO_IPSEC_AH, &st->st_ah); - if (st->st_esp.present) - compute_proto_keymat(st, PROTO_IPSEC_ESP, &st->st_esp); + 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; + } } /* State Transition Functions. @@ -2973,261 +2828,272 @@ compute_keymats(struct state *st) /* Handle a Main Mode Oakley first packet (responder side). * HDR;SA --> HDR;SA */ -stf_status -main_inI1_outR1(struct msg_digest *md) +stf_status main_inI1_outR1(struct msg_digest *md) { - struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; - struct state *st; - struct connection *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. + struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; + struct state *st; + struct connection *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) { - struct connection *d; + c = find_host_connection(&md->iface->addr, NAT_T_IKE_FLOAT_PORT + , &md->sender, md->sender_port, policy); + } - d = find_host_connection(&md->iface->addr - , pluto_port, (ip_address*)NULL, 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. + */ + { + struct connection *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; + } + } + } - for (; d != NULL; d = d->hp_next) - { - if (d->kind == CK_GROUP) + if (c == NULL) { - /* ignore */ + 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 { - 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; + /* 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); } - if (c == NULL) + /* 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)) { - 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; + 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_TEMPLATE) + else if (c->kind == CK_INSTANCE) { - 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; + plog("responding to Main Mode from unknown peer %s" + , ip_str(&c->spd.that.host_addr)); } 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); + plog("responding to Main Mode"); } - } - 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; + /* 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. + */ - r_sa.isasa_np = vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; + /* 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++; + } - if (!out_struct(&r_sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs)) - return STF_INTERNAL_ERROR; - } + /* HDR out. + * We can't leave this to comm_handle() because we must + * fill in the cookie. + */ + { + struct isakmp_hdr r_hdr = md->hdr; - /* SA body in and out */ - RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit, &proposal_pbs - ,&proposal, &r_sa_pbs, st, FALSE)); + 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; + } - /* 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)) + /* start of SA out */ { - return STF_INTERNAL_ERROR; + 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; } - } - /* 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)) + /* 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) { - return STF_INTERNAL_ERROR; + if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE + , &md->rbody, VID_STRONGSWAN)) + { + 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)) + /* if enabled send Cisco Unity Vendor ID */ + if (SEND_CISCO_UNITY_VID) { - return STF_INTERNAL_ERROR; + if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE + , &md->rbody, VID_CISCO_UNITY)) + { + 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)) + /* + * if the peer sent an OpenPGP Vendor ID we offer the same capability + */ + if (md->openpgp) { - return STF_INTERNAL_ERROR; + 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 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; - } + /* 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; + } + } - 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); + /* 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 (st->nat_traversal - && !out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, md->nat_traversal_vid)) + if (md->nat_traversal_vid && nat_traversal_enabled) { - return STF_INTERNAL_ERROR; + /* 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); + close_message(&md->rbody); - /* save initiator SA for HASH */ - clonereplacechunk(st->st_p1isa, sa_pd->pbs.start, pbs_room(&sa_pd->pbs), "sa in main_inI1_outR1()"); + /* 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; + return STF_OK; } /* STATE_MAIN_I1: HDR, SA --> auth dependent @@ -3240,95 +3106,94 @@ main_inI1_outR1(struct msg_digest *md) * * We must verify that the proposal received matches one we sent. */ -stf_status -main_inR1_outI2(struct msg_digest *md) +stf_status main_inR1_outI2(struct msg_digest *md) { - struct state *const st = md->st; + struct state *const st = md->st; - u_int8_t np = ISAKMP_NEXT_NONE; + 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(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; + /* 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(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); - } + /* 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; + /* 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; - } + 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); + /* 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) */ + /* 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; + return STF_OK; } /* STATE_MAIN_R1: @@ -3336,140 +3201,137 @@ main_inR1_outI2(struct msg_digest *md) * * 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 + * --> 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 + * 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) +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 and no preloaded RSA public key exists*/ - bool RSA_auth = st->st_oakley.auth == OAKLEY_RSA_SIG - || st->st_oakley.auth == XAUTHInitRSA - || st->st_oakley.auth == XAUTHRespRSA; - bool send_cr = !no_cr_send && RSA_auth && !has_preloaded_public_key(st); + 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; + u_int8_t np = ISAKMP_NEXT_NONE; - /* KE in */ - RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs)); + /* 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")); + /* 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); + 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(); - } + 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); + /* decode certificate requests */ + st->st_connection->got_certrequest = FALSE; + decode_cr(md, st->st_connection); - /**************** build output packet HDR;KE;Nr ****************/ + /**************** build output packet HDR;KE;Nr ****************/ - /* HDR out done */ + /* 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; + /* 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); - } + /* 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; + /* 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) + /* CR out */ + if (send_cr) { - if (!build_and_ship_CR(CERT_X509_SIGNATURE - , st->st_connection->spd.that.ca - , &md->rbody, np)) - return STF_INTERNAL_ERROR; + if (st->st_connection->kind == CK_PERMANENT) + { + if (!build_and_ship_CR(CERT_X509_SIGNATURE + , st->st_connection->spd.that.ca + , &md->rbody, np)) + return STF_INTERNAL_ERROR; + } + else + { + generalName_t *ca = NULL; + + if (collect_rw_ca_candidates(md, &ca)) + { + generalName_t *gn; + + for (gn = ca; gn != NULL; gn = gn->next) + { + if (!build_and_ship_CR(CERT_X509_SIGNATURE, gn->name + , &md->rbody + , gn->next == NULL ? np : ISAKMP_NEXT_CR)) + return STF_INTERNAL_ERROR; + } + free_generalNames(ca, FALSE); + } + else + { + if (!build_and_ship_CR(CERT_X509_SIGNATURE, chunk_empty + , &md->rbody, np)) + return STF_INTERNAL_ERROR; + } + } } - else + + if (st->nat_traversal & NAT_T_WITH_NATD) { - generalName_t *ca = NULL; + if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md)) + return STF_INTERNAL_ERROR; + } - if (collect_rw_ca_candidates(md, &ca)) - { - generalName_t *gn; + /* finish message */ + close_message(&md->rbody); - for (gn = ca; gn != NULL; gn = gn->next) - { - if (!build_and_ship_CR(CERT_X509_SIGNATURE, gn->name - , &md->rbody - , gn->next == NULL ? np : ISAKMP_NEXT_CR)) - return STF_INTERNAL_ERROR; - } - free_generalNames(ca, FALSE); - } - else - { - if (!build_and_ship_CR(CERT_X509_SIGNATURE, empty_chunk - , &md->rbody, np)) - 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, st->st_oakley.group); - if (!generate_skeyids_iv(st)) - return STF_FAIL + AUTHENTICATION_FAILED; - update_iv(st); - - return STF_OK; + /* 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 + AUTHENTICATION_FAILED; + update_iv(st); + + return STF_OK; } /* STATE_MAIN_I2: @@ -3478,172 +3340,174 @@ main_inI2_outR2(struct msg_digest *md) * * The following are not yet implemented. * SMF_PKE_AUTH: HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i - * --> HDR*, HASH_I + * --> HDR*, HASH_I * SMF_RPKE_AUTH: HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r - * --> HDR*, HASH_I + * --> HDR*, HASH_I */ -stf_status -main_inR2_outI3(struct msg_digest *md) +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 */ - - certpolicy_t cert_policy = st->st_connection->spd.this.sendcert; - cert_t mycert = st->st_connection->spd.this.cert; - bool requested, send_cert, send_cr; - - bool RSA_auth = st->st_oakley.auth == OAKLEY_RSA_SIG - || st->st_oakley.auth == XAUTHInitRSA - || st->st_oakley.auth == XAUTHRespRSA; - - int auth_payload = RSA_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 */ - st->st_connection->got_certrequest = FALSE; - decode_cr(md, st->st_connection); - - /* free collected certificate requests since as initiator - * we don't heed them anyway - */ - free_generalNames(st->st_connection->requested_ca, TRUE); - st->st_connection->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 - && st->st_connection->got_certrequest; - send_cert = RSA_auth && mycert.type != CERT_NONE - && (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, st->st_oakley.group); - if (!generate_skeyids_iv(st)) - return STF_FAIL + 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, &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, &id_pbs) - || !out_chunk(id_b, &id_pbs, "my identity")) - return STF_INTERNAL_ERROR; - close_output_pbs(&id_pbs); - } + 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 */ - /* CERT out */ - if (RSA_auth) - { - DBG(DBG_CONTROL, - DBG_log("our certificate policy is %s" - , enum_name(&cert_policy_names, cert_policy)) - ) - if (mycert.type != CERT_NONE) - { - const char *request_text = ""; + certpolicy_t cert_policy = st->st_connection->spd.this.sendcert; + cert_t mycert = st->st_connection->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 */ + st->st_connection->got_certrequest = FALSE; + decode_cr(md, st->st_connection); + + /* free collected certificate requests since as initiator + * we don't heed them anyway + */ + free_generalNames(st->st_connection->requested_ca, TRUE); + st->st_connection->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 + && st->st_connection->got_certrequest; + send_cert = pubkey_auth && mycert.type != CERT_NONE + && (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); - 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); + /* done parsing; initialize crypto */ + compute_dh_shared(st, st->st_gr); + if (!generate_skeyids_iv(st)) + return STF_FAIL + AUTHENTICATION_FAILED; + + if (st->nat_traversal & NAT_T_WITH_NATD) + { + nat_traversal_natd_lookup(md); } - else + if (st->nat_traversal) + { + nat_traversal_show_result(st->nat_traversal, md->sender_port); + } + if (st->nat_traversal & NAT_T_WITH_KA) { - plog("we don't have a cert"); + nat_traversal_new_ka_event(); } - } - if (send_cert) - { - 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 = mycert.type; + /*************** build output packet HDR*;IDii;HASH/SIG_I ***************/ + /* ??? NOTE: this is almost the same as main_inI3_outR3's code */ - if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) - return STF_INTERNAL_ERROR; - if (!out_chunk(get_mycert(mycert), &cert_pbs, "CERT")) - return STF_INTERNAL_ERROR; - close_output_pbs(&cert_pbs); - } + /* HDR* out done */ - /* CR out */ - if (send_cr) - { - if (!build_and_ship_CR(mycert.type, st->st_connection->spd.that.ca - , &md->rbody, ISAKMP_NEXT_SIG)) - return STF_INTERNAL_ERROR; - } + /* IDii out */ + { + struct isakmp_ipsec_id id_hd; + chunk_t id_b; - /* HASH_I or SIG_I out */ - { - u_char hash_val[MAX_DIGEST_LEN]; - size_t hash_len = main_mode_hash(st, hash_val, TRUE, &id_pbs); + 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, &id_pbs) + || !out_chunk(id_b, &id_pbs, "my identity")) + return STF_INTERNAL_ERROR; + close_output_pbs(&id_pbs); + } - if (auth_payload == ISAKMP_NEXT_HASH) + /* CERT out */ + if (pubkey_auth) { - /* HASH_I out */ - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody - , hash_val, hash_len, "HASH_I")) - return STF_INTERNAL_ERROR; + DBG(DBG_CONTROL, + DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) + ) + if (mycert.type != CERT_NONE) + { + 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"); + } } - else + if (send_cert) { - /* SIG_I out */ - u_char sig_val[RSA_MAX_OCTETS]; - size_t sig_len = RSA_sign_hash(st->st_connection - , sig_val, hash_val, hash_len); + pb_stream cert_pbs; - if (sig_len == 0) - { - loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature"); - return STF_FAIL + AUTHENTICATION_FAILED; - } + struct isakmp_cert cert_hd; + cert_hd.isacert_np = (send_cr)? ISAKMP_NEXT_CR : ISAKMP_NEXT_SIG; + cert_hd.isacert_type = mycert.type; - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc - , &md->rbody, sig_val, sig_len, "SIG_I")) - return STF_INTERNAL_ERROR; + if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) + return STF_INTERNAL_ERROR; + if (!out_chunk(cert_get_encoding(mycert), &cert_pbs, "CERT")) + return STF_INTERNAL_ERROR; + close_output_pbs(&cert_pbs); + } + + /* CR out */ + if (send_cr) + { + if (!build_and_ship_CR(mycert.type, st->st_connection->spd.that.ca + , &md->rbody, ISAKMP_NEXT_SIG)) + return STF_INTERNAL_ERROR; + } + + /* HASH_I or SIG_I out */ + { + u_char hash_buf[MAX_DIGEST_LEN]; + chunk_t hash = chunk_from_buf(hash_buf); + + 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, 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 + 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 */ + /* 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 */ + /* 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; + return STF_OK; } /* Shared logic for asynchronous lookup of DNS KEY records. @@ -3651,31 +3515,31 @@ main_inR2_outI3(struct msg_digest *md) */ enum key_oppo_step { - kos_null, - kos_his_txt + kos_null, + kos_his_txt #ifdef USE_KEYRR - , kos_his_key + , 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; + 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(struct id *id, err_t ugh) + , struct key_continuation *kc); + +static void report_key_dns_failure(struct id *id, err_t ugh) { - char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */ + char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */ - (void) idtoa(id, id_buf, sizeof(id_buf)); - loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'" - "; DNS search for KEY failed (%s)", id_buf, ugh); + (void) idtoa(id, id_buf, sizeof(id_buf)); + loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'" + "; DNS search for KEY failed (%s)", id_buf, ugh); } @@ -3688,135 +3552,145 @@ report_key_dns_failure(struct id *id, err_t ugh) */ 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 */ + , bool initiator /* are we the Initiator? */ + , cont_fn_t cont_fn /* continuation function */ + , const struct key_continuation *kc /* current state, can be NULL */ ) { - struct state *st = md->st; - u_char hash_val[MAX_DIGEST_LEN]; - size_t hash_len; - struct id peer; - stf_status r = STF_OK; - - /* ID Payload in */ - if (!decode_peer_id(md, &peer)) - return STF_FAIL + 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; - hash_len = main_mode_hash(st, hash_val, !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_val, 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 + INVALID_HASH_INFORMATION; - } + u_char hash_buf[MAX_DIGEST_LEN]; + chunk_t hash = chunk_from_buf(hash_buf); + struct state *st = md->st; + struct id peer; + stf_status r = STF_OK; + + /* ID Payload in */ + if (!decode_peer_id(md, &peer)) + return STF_FAIL + 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; } - break; - case OAKLEY_RSA_SIG: - case XAUTHInitRSA: - case XAUTHRespRSA: - r = RSA_check_signature(&peer, st, hash_val, hash_len - , &md->chain[ISAKMP_NEXT_SIG]->pbs + 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 + 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 + kc == NULL? NULL : kc->ac.keys_from_dns, #endif /* USE_KEYRR */ - , kc == NULL? NULL : kc->ac.gateways_from_dns - ); - - if (r == STF_SUSPEND) - { - /* initiate/resume asynchronous DNS lookup for key */ - struct key_continuation *nkc - = alloc_thing(struct key_continuation, "key continuation"); - enum key_oppo_step step_done = kc == NULL? kos_null : kc->step; - err_t ugh = NULL; + kc == NULL? NULL : kc->ac.gateways_from_dns + ); + + if (r == STF_SUSPEND) + { + /* 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; + err_t ugh = NULL; - /* Record that state is used by a suspended md */ - passert(st->st_suspended_md == NULL); - st->st_suspended_md = md; + /* 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; + 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; + 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; + nkc->failure_ok = TRUE; #endif - ugh = start_adns_query(&peer - , &peer /* SG itself */ - , T_TXT - , cont_fn - , &nkc->ac); - break; + ugh = start_adns_query(&peer + , &peer /* SG itself */ + , 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 /* no sgw for KEY */ - , T_KEY - , cont_fn - , &nkc->ac); - break; + case kos_his_txt: + /* second try: look for the KEY records */ + nkc->step = kos_his_key; + ugh = start_adns_query(&peer + , NULL /* no sgw for KEY */ + , T_KEY + , cont_fn + , &nkc->ac); + break; #endif /* USE_KEYRR */ - default: - bad_case(step_done); - } + default: + bad_case(step_done); + } - if (ugh != NULL) - { - report_key_dns_failure(&peer, ugh); - st->st_suspended_md = NULL; - r = STF_FAIL + INVALID_KEY_INFORMATION; - } - } - break; + if (ugh != NULL) + { + report_key_dns_failure(&peer, ugh); + st->st_suspended_md = NULL; + r = STF_FAIL + INVALID_KEY_INFORMATION; + } + } + break; - default: - bad_case(st->st_oakley.auth); - } - if (r != STF_OK) - return r; + 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) + return r; - DBG(DBG_CRYPT, DBG_log("authentication succeeded")); + 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)) - return STF_FAIL + INVALID_ID_INFORMATION; + /* + * With the peer ID known, let's see if we need to switch connections. + */ + if (!switch_connection(md, &peer, initiator)) + return STF_FAIL + INVALID_ID_INFORMATION; - return r; + return r; } /* This continuation is called as part of either @@ -3840,46 +3714,44 @@ main_id_and_auth(struct msg_digest *md * 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) +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; + struct key_continuation *kc = (void *)cr; + struct state *st = kc->md->st; - passert(cur_state == NULL); + passert(cur_state == NULL); - /* if st == NULL, our state has been deleted -- just clean up */ - if (st != NULL) - { - stf_status r; + /* 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; + 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 + INVALID_KEY_INFORMATION; - } - else - { + if (!kc->failure_ok && ugh != NULL) + { + report_key_dns_failure(&st->st_connection->spd.that.id, ugh); + r = STF_FAIL + INVALID_KEY_INFORMATION; + } + else + { #ifdef USE_KEYRR - passert(kc->step == kos_his_txt || kc->step == kos_his_key); + passert(kc->step == kos_his_txt || kc->step == kos_his_key); #else - passert(kc->step == kos_his_txt); + 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; + 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: @@ -3893,174 +3765,173 @@ key_continue(struct adns_continuation *cr * - 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 */ +static key_tail_fn main_inI3_outR3_tail; /* forward */ -stf_status -main_inI3_outR3(struct msg_digest *md) +stf_status main_inI3_outR3(struct msg_digest *md) { - return main_inI3_outR3_tail(md, NULL); + return main_inI3_outR3_tail(md, NULL); } -static void -main_inI3_outR3_continue(struct adns_continuation *cr, err_t ugh) +static void main_inI3_outR3_continue(struct adns_continuation *cr, err_t ugh) { - key_continue(cr, ugh, main_inI3_outR3_tail); + 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 RSA_auth; - bool send_cert; - bool 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 auth is RSA, 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; - RSA_auth = st->st_oakley.auth == OAKLEY_RSA_SIG - || st->st_oakley.auth == XAUTHInitRSA - || st->st_oakley.auth == XAUTHRespRSA; - send_cert = RSA_auth - && mycert.type != CERT_NONE - && (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 = RSA_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 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! */ - 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 (RSA_auth) - { - DBG(DBG_CONTROL, - DBG_log("our certificate policy is %s" - , enum_name(&cert_policy_names, cert_policy)) - ) - if (mycert.type != CERT_NONE) { - const char *request_text = ""; + stf_status r = main_id_and_auth(md, FALSE + , main_inI3_outR3_continue + , kc); - 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); + if (r != STF_OK) + return r; } - else + + /* 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.type != CERT_NONE && + (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 */ { - plog("we don't have a cert"); + /* 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); } - } - if (send_cert) - { - pb_stream cert_pbs; - struct isakmp_cert cert_hd; - cert_hd.isacert_np = ISAKMP_NEXT_SIG; - cert_hd.isacert_type = mycert.type; + /* CERT out */ + if (pubkey_auth) + { + DBG(DBG_CONTROL, + DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) + ) + if (mycert.type != CERT_NONE) + { + const char *request_text = ""; - if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) - return STF_INTERNAL_ERROR; - if (!out_chunk(get_mycert(mycert), &cert_pbs, "CERT")) - return STF_INTERNAL_ERROR; - close_output_pbs(&cert_pbs); - } + 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) + { + pb_stream cert_pbs; - /* HASH_R or SIG_R out */ - { - u_char hash_val[MAX_DIGEST_LEN]; - size_t hash_len = main_mode_hash(st, hash_val, FALSE, &r_id_pbs); + struct isakmp_cert cert_hd; + cert_hd.isacert_np = ISAKMP_NEXT_SIG; + cert_hd.isacert_type = mycert.type; - if (auth_payload == ISAKMP_NEXT_HASH) - { - /* HASH_R out */ - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody - , hash_val, hash_len, "HASH_R")) + if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) return STF_INTERNAL_ERROR; + if (!out_chunk(cert_get_encoding(mycert), &cert_pbs, "CERT")) + return STF_INTERNAL_ERROR; + close_output_pbs(&cert_pbs); } - else + + /* HASH_R or SIG_R out */ { - /* SIG_R out */ - u_char sig_val[RSA_MAX_OCTETS]; - size_t sig_len = RSA_sign_hash(st->st_connection - , sig_val, hash_val, hash_len); + u_char hash_buf[MAX_DIGEST_LEN]; + chunk_t hash = chunk_from_buf(hash_buf); - if (sig_len == 0) - { - loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature"); - return STF_FAIL + AUTHENTICATION_FAILED; - } + main_mode_hash(st, &hash, FALSE, &r_id_pbs); - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc - , &md->rbody, sig_val, sig_len, "SIG_R")) - return STF_INTERNAL_ERROR; + 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 + 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 */ + /* encrypt message, sans fixed part of header */ - if (!encrypt_message(&md->rbody, st)) - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ + 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); + /* 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); + 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); + /* 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; + return STF_OK; } /* STATE_MAIN_I3: @@ -4073,48 +3944,45 @@ main_inI3_outR3_tail(struct msg_digest *md * - main_inR3_continue to start main_inR3_tail again */ -static key_tail_fn main_inR3_tail; /* forward */ +static key_tail_fn main_inR3_tail; /* forward */ -stf_status -main_inR3(struct msg_digest *md) +stf_status main_inR3(struct msg_digest *md) { - return main_inR3_tail(md, NULL); + return main_inR3_tail(md, NULL); } -static void -main_inR3_continue(struct adns_continuation *cr, err_t ugh) +static void main_inR3_continue(struct adns_continuation *cr, err_t ugh) { - key_continue(cr, ugh, main_inR3_tail); + key_continue(cr, ugh, main_inR3_tail); } -static stf_status -main_inR3_tail(struct msg_digest *md -, struct key_continuation *kc) +static stf_status main_inR3_tail(struct msg_digest *md, + struct key_continuation *kc) { - struct state *const st = md->st; + 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); + /* 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; - } + if (r != STF_OK) + return r; + } - /**************** done input ****************/ + /**************** done input ****************/ - ISAKMP_SA_established(st->st_connection, st->st_serialno); + 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); + /* 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 */ + update_iv(st); /* finalize our Phase 1 IV */ - return STF_OK; + return STF_OK; } /* Handle first message of Phase 2 -- Quick Mode. @@ -4182,15 +4050,15 @@ main_inR3_tail(struct msg_digest *md */ enum verify_oppo_step { - vos_fail, - vos_start, - vos_our_client, - vos_our_txt, + vos_fail, + vos_start, + vos_our_client, + vos_our_txt, #ifdef USE_KEYRR - vos_our_key, + vos_our_key, #endif /* USE_KEYRR */ - vos_his_client, - vos_done + vos_his_client, + vos_done }; static const char *const verify_step_name[] = { @@ -4207,834 +4075,833 @@ static const char *const verify_step_name[] = { /* hold anything we can handle of a Phase 2 ID */ struct p2id { - ip_subnet net; - u_int8_t proto; - u_int16_t port; + 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 */ + 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; + 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); + , struct adns_continuation *ac); -stf_status -quick_inI1_outR1(struct msg_digest *md) +stf_status quick_inI1_outR1(struct msg_digest *md) { - const struct state *const p1st = md->st; - struct connection *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 + 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 + 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); + const struct state *const p1st = md->st; + struct connection *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 + 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 + 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); } 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: + 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: + 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); + 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) +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 + INVALID_ID_INFORMATION; - } - else + 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) { - r = quick_inI1_outR1_tail(b, cr); + 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 + INVALID_ID_INFORMATION; + } + else + { + r = quick_inI1_outR1_tail(b, cr); + } + complete_state_transition(&b->md, r); } - complete_state_transition(&b->md, r); - } - if (b->md != NULL) - release_md(b->md); - cur_state = NULL; + 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) +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; - struct connection *c = p1st->st_connection; - struct verify_oppo_continuation *vc - = alloc_thing(struct verify_oppo_continuation, "verify continuation"); - struct id id /* subject of query */ - , *our_id /* needed for myid playing */ - , 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->kind == ID_NONE) - { - iptoid(&c->spd.this.host_addr, &our_id_space); - our_id = &our_id_space; - } - - switch (next_step) - { - case vos_our_client: - networkof(&b->my.net, &client); - iptoid(&client, &id); - 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; + struct msg_digest *md = b->md; + struct state *p1st = md->st; + struct connection *c = p1st->st_connection; + struct verify_oppo_continuation *vc = malloc_thing(struct verify_oppo_continuation); + struct id id /* subject of query */ + , *our_id /* needed for myid playing */ + , 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->kind == ID_ANY) + { + iptoid(&c->spd.this.host_addr, &our_id_space); + our_id = &our_id_space; + } + + switch (next_step) + { + case vos_our_client: + networkof(&b->my.net, &client); + iptoid(&client, &id); + 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; + 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); - iptoid(&client, &id); - 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 + INVALID_ID_INFORMATION; - } - else - { - return STF_SUSPEND; - } + case vos_his_client: + networkof(&b->his.net, &client); + iptoid(&client, &id); + 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 + 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) +static enum verify_oppo_step quick_inI1_outR1_process_answer( + struct verify_oppo_bundle *b, + struct adns_continuation *ac, + struct state *p1st) { - struct connection *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; - { - const struct RSA_private_key *pri = get_RSA_private_key(c); - struct gw_info *gwp; - - if (pri == 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 (same_RSA_public_key(&pri->pub, &gwp->key->u.rsa)) + struct connection *c = p1st->st_connection; + enum verify_oppo_step next_step = vos_our_client; + err_t ugh = NULL; + + DBG(DBG_CONTROL, { - ugh = NULL; /* good! */ - break; - } - } - } - break; + 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]); + }); - case vos_our_txt: - next_step = vos_his_client; + /* process just completed DNS query (if any) */ + switch (b->step) { - const struct RSA_private_key *pri = get_RSA_private_key(c); + 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 (pri == NULL) - { - ugh = "we don't know our own key"; + 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; - } - { - struct gw_info *gwp; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) + 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; + /* 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"; + ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key"; #endif - if (gwp->gw_key_present - && same_RSA_public_key(&pri->pub, &gwp->key->u.rsa)) - { - ugh = NULL; /* good! */ - break; - } + 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; + next_step = vos_our_key; #endif + } + } } - } - } - break; + break; #ifdef USE_KEYRR - case vos_our_key: - next_step = vos_his_client; - { - const struct RSA_private_key *pri = get_RSA_private_key(c); + case vos_our_key: + next_step = vos_his_client; + { + private_key_t *private = get_private_key(c); - if (pri == NULL) - { - ugh = "we don't know our own key"; + 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; - } - { - pubkey_list_t *kp; +#endif /* USE_KEYRR */ - ugh = "our client delegation depends on our missing " RRNAME " record"; - for (kp = ac->keys_from_dns; kp != NULL; kp = kp->next) + case vos_his_client: + next_step = vos_done; { - ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key"; - if (same_RSA_public_key(&pri->pub, &kp->key->u.rsa)) - { - /* do this only once a day */ - if (!logged_txt_warning) + public_key_t *pub_key; + identification_t *p1st_keyid; + 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; + p1st_keyid = pub_key->get_id(pub_key, ID_PUBKEY_INFO_SHA1); + + ugh = "peer's client does not delegate to peer"; + for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) { - 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 = "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 || p1st_keyid->equals(p1st_keyid, + gwp->key->public_key->get_id(gwp->key->public_key, + ID_PUBKEY_INFO_SHA1)) + ) + { + ugh = NULL; /* good! */ + break; + } } - ugh = NULL; /* good! */ - break; - } } - } + break; + + default: + bad_case(b->step); } - break; -#endif /* USE_KEYRR */ - case vos_his_client: - next_step = vos_done; + if (ugh != NULL) { - struct gw_info *gwp; - - /* check that the public key that authenticated - * the ISAKMP SA (p1st) will do for this gateway. - */ - - 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 - || same_RSA_public_key(&p1st->st_peer_pubkey->u.rsa - , &gwp->key->u.rsa)) - { - ugh = NULL; /* good! */ - break; - } - } + report_verify_failure(b, ugh); + next_step = vos_fail; } - break; - - default: - bad_case(b->step); - } - - if (ugh != NULL) - { - report_verify_failure(b, ugh); - next_step = vos_fail; - } - return next_step; + return next_step; } -static stf_status -quick_inI1_outR1_tail(struct verify_oppo_bundle *b -, struct adns_continuation *ac) +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; - struct connection *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). - */ - { - struct connection *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 + 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) - { - /* 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 + INVALID_ID_INFORMATION; + struct msg_digest *md = b->md; + struct state *const p1st = md->st; + struct connection *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; - /* 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; + u_char /* set by START_HASH_PAYLOAD: */ + *r_hashval, /* where in reply to jam hash value */ + *r_hash_start; /* from where to start hashing */ - /* 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 + /* Now that we have identities of client subnets, we must look for + * a suitable connection (our current one only matches for hosts). + */ + { + struct connection *p = find_client_connection(c + , our_net, his_net, b->my.proto, b->my.port, b->his.proto, b->his.port); + + if (p == NULL) { - /* Plain Road Warrior: - * instantiate, carrying over authenticated peer ID - */ - p = rw_instantiate(p, &c->spd.that.host_addr, md->sender_port - , his_net, &c->spd.that.id); + /* 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 + 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) + { + /* 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 + 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 + { + /* Plain Road Warrior: + * instantiate, carrying over authenticated peer ID + */ + p = rw_instantiate(p, &c->spd.that.host_addr, md->sender_port + , his_net, &c->spd.that.id); + } + } #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; - } + /* 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; - } + 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); + /* 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); + 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; + 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 */ - { - 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) + /* now that we are sure of our connection, create our new state */ { - struct connection *t = st->st_connection; + struct state *const st = duplicate_state(p1st); - st->st_connection = c; - set_cur_connection(c); - connection_discard(t); - } + /* 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. + */ - st->st_try = 0; /* not our job to try again from start */ + if (st->st_connection != c) + { + struct connection *t = st->st_connection; - st->st_msgid = md->hdr.isa_msgid; + st->st_connection = c; + set_cur_connection(c); + connection_discard(t); + } - st->st_new_iv_len = b->new_iv_len; - memcpy(st->st_new_iv, b->new_iv, b->new_iv_len); + st->st_try = 0; /* not our job to try again from start */ - set_cur_state(st); /* (caller will reset) */ - md->st = st; /* feed back new state */ + st->st_msgid = md->hdr.isa_msgid; - st->st_peeruserprotoid = b->his.proto; - st->st_peeruserport = b->his.port; - st->st_myuserprotoid = b->my.proto; - st->st_myuserport = b->my.port; + st->st_new_iv_len = b->new_iv_len; + memcpy(st->st_new_iv, b->new_iv, b->new_iv_len); - insert_state(st); /* needs cookies, connection, and msgid */ + set_cur_state(st); /* (caller will reset) */ + md->st = st; /* feed back new state */ - /* 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); + st->st_peeruserprotoid = b->his.proto; + st->st_peeruserport = b->his.port; + st->st_myuserprotoid = b->my.proto; + st->st_myuserport = b->my.port; - 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); - } + insert_state(st); /* needs cookies, connection, and msgid */ - /* 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 - */ + /* 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); - /* HDR* out */ - echo_hdr(md, TRUE, ISAKMP_NEXT_HASH); + 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); + } - /* HASH(2) out -- first pass */ - START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_SA); + /* 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 + */ - /* 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; + /* HDR* out */ + echo_hdr(md, TRUE, ISAKMP_NEXT_HASH); - /* 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; + /* HASH(2) out -- first pass */ + START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_SA); - /* 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)); - } + /* 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); + 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 + NO_PROPOSAL_CHOSEN; /* ??? */ - } + 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 + NO_PROPOSAL_CHOSEN; /* ??? */ + } - /* Ni in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); + /* 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")); + /* [ KE ] in (for PFS) */ + RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gi, "Gi", "Quick Mode I1")); - plog("responding to Quick Mode"); + plog("responding to Quick Mode"); - /**** finish reply packet: Nr [, KE ] [, IDci, IDcr ] ****/ + /**** 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; + /* 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) */ + /* [ 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; + 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, st->st_pfs_group); - } + /* 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! */ + /* [ 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; + 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! */ + 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 (!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; - } + 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); + /* 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); + /* Derive new keying material */ + compute_keymats(st); - /* 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)) - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ + /* 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)) + return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - /* encrypt message, except for fixed part of header */ + /* encrypt message, except for fixed part of header */ - if (!encrypt_message(&md->rbody, st)) - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ + if (!encrypt_message(&md->rbody, st)) + return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - return STF_OK; - } + return STF_OK; + } } /* * Initialize RFC 3706 Dead Peer Detection */ -static void -dpd_init(struct state *st) +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); - } + 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. @@ -5043,152 +4910,151 @@ dpd_init(struct state *st) * (see RFC 2409 "IKE" 5.5) * Installs inbound and outbound IPsec SAs, routing, etc. */ -stf_status -quick_inR1_outI2(struct msg_digest *md) +stf_status quick_inR1_outI2(struct msg_digest *md) { - struct state *const st = md->st; - const struct connection *c = st->st_connection; + struct state *const st = md->st; + const struct connection *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]; + /* 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"); - RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs - , &sa_pd->payload.sa, NULL, TRUE, st)); - } + /* SA in */ + { + struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; - /* Nr in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr")); + RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs + , &sa_pd->payload.sa, NULL, TRUE, st)); + } - /* [ KE ] in (for PFS) */ - RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1")); + /* Nr in */ + RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr")); - if (st->st_pfs_group != NULL) - compute_dh_shared(st, st->st_gr, st->st_pfs_group); + /* [ KE ] in (for PFS) */ + RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1")); - /* [ IDci, IDcr ] in; these must match what we sent */ + if (st->st_pfs_group != NULL) + compute_dh_shared(st, st->st_gr); - { - struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; + /* [ IDci, IDcr ] in; these must match what we sent */ - if (id_pd != NULL) { - /* ??? we are assuming IPSEC_DOI */ + struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; - /* IDci (we are initiator) */ + if (id_pd != NULL) + { + /* ??? we are assuming IPSEC_DOI */ - 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 + INVALID_ID_INFORMATION; + /* IDci (we are initiator) */ - /* IDcr (responder is peer) */ + 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 + INVALID_ID_INFORMATION; - 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 + 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 + 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 + 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 + INVALID_ID_INFORMATION; + } + } } - } - /* check the peer's group attributes */ - - { - const ietfAttrList_t *peer_list = NULL; + /* check the peer's group attributes */ - get_peer_ca_and_groups(st->st_connection, &peer_list); - - if (!group_membership(peer_list, st->st_connection->name - , st->st_connection->spd.that.groups)) { - char buf[BUF_LEN]; + const ietfAttrList_t *peer_list = NULL; + + get_peer_ca_and_groups(st->st_connection, &peer_list); - format_groups(st->st_connection->spd.that.groups, buf, BUF_LEN); - loglog(RC_LOG_SERIOUS, "peer is not member of one of the groups: %s" - , buf); - return STF_FAIL + INVALID_ID_INFORMATION; - } - } + if (!group_membership(peer_list, st->st_connection->name + , st->st_connection->spd.that.groups)) + { + char buf[BUF_LEN]; - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->nat_traversal & NAT_T_WITH_NATOA)) - { - nat_traversal_natoa_lookup(md); + format_groups(st->st_connection->spd.that.groups, buf, BUF_LEN); + loglog(RC_LOG_SERIOUS, "peer is not member of one of the groups: %s" + , buf); + return STF_FAIL + INVALID_ID_INFORMATION; + } } - /* ??? 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). - */ + 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) ****************/ + /**************** build reply packet HDR*, HASH(3) ****************/ - /* HDR* out done */ + /* 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 */ + /* 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); - } + START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_NONE); + (void)quick_mode_hash3(r_hashval, st); + } - /* Derive new keying material */ - compute_keymats(st); + /* Derive new keying material */ + compute_keymats(st); - /* 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)) - return STF_INTERNAL_ERROR; + /* 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)) + return STF_INTERNAL_ERROR; - /* encrypt message, except for fixed part of header */ + /* encrypt message, except for fixed part of header */ - if (!encrypt_message(&md->rbody, st)) - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ + 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; + { + 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(); + /* 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); + /* 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; + return STF_OK; } /* Handle last message of Quick Mode. @@ -5196,245 +5062,253 @@ quick_inR1_outI2(struct msg_digest *md) * (see RFC 2409 "IKE" 5.5) * Installs outbound IPsec SAs, routing, etc. */ -stf_status -quick_inI2(struct msg_digest *md) +stf_status quick_inI2(struct msg_digest *md) { - struct state *const st = md->st; - - /* HASH(3) in */ - CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st) - , "HASH(3)", "Quick I2"); - - /* 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)) - return STF_INTERNAL_ERROR; - - { - 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; + struct state *const st = md->st; + + /* HASH(3) in */ + CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st) + , "HASH(3)", "Quick I2"); + + /* 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)) + return STF_INTERNAL_ERROR; + + { + 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) +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 */ - struct hmac_ctx ctx; - hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); - hmac_update(&ctx, (const u_char *) &msgid, sizeof(msgid_t)); - hmac_update(&ctx, r_hash_start, rbody.cur-r_hash_start); - hmac_final(r_hashval, &ctx); - - DBG(DBG_CRYPT, - DBG_log("HASH computed:"); - DBG_dump("", r_hashval, ctx.hmac_digest_size)); - } - - /* Encrypt message (preserve st_iv and st_new_iv) */ - { - u_char old_iv[MAX_DIGEST_LEN]; - u_char new_iv[MAX_DIGEST_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); - u_int old_iv_len = st->st_iv_len; - u_int new_iv_len = st->st_new_iv_len; + /* 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]; - if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN) - return STF_INTERNAL_ERROR; + u_int old_iv_len = st->st_iv_len; + u_int new_iv_len = st->st_new_iv_len; - memcpy(old_iv, st->st_iv, old_iv_len); - memcpy(new_iv, st->st_new_iv, new_iv_len); + if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN) + return STF_INTERNAL_ERROR; - 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; - - setchunk(st->st_tpacket, reply.start, pbs_offset(&reply)); - send_packet(st, "ISAKMP notify"); - st->st_tpacket = saved_tpacket; - } - - return STF_IGNORE; + 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) +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)) - { + 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("recent eroute activity %u seconds ago, " - "no need to send DPD notification" - , (int)idle_time) + 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; - 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) - { - /* Get a non-zero random value that has room to grow */ - get_rnd_bytes((u_char *)&st->st_dpd_seqno, sizeof(st->st_dpd_seqno)); - 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); - } + /* 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); + } } /* @@ -5444,139 +5318,139 @@ 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 + PAYLOAD_MALFORMED; - } - - if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) - { + 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 + PAYLOAD_MALFORMED; + } + + if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) + { #ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ + /* Ignore it, cisco sends odd icookies */ #else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid icookie (broken Cisco?)"); - return STF_FAIL + INVALID_COOKIE; + loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid icookie (broken Cisco?)"); + return STF_FAIL + 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 + 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 + 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; + } + 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 + 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 + 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) +stf_status dpd_inR(struct state *st, struct isakmp_notification *const n, + pb_stream *pbs) { - u_int32_t seqno; + 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 (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 + PAYLOAD_MALFORMED; - } - - if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) - { + { + loglog(RC_LOG_SERIOUS + , "DPD: R_U_THERE_ACK has invalid SPI length (%d)" + , n->isan_spisize); + return STF_FAIL + PAYLOAD_MALFORMED; + } + + if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) + { #ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ + /* Ignore it, cisco sends odd icookies */ #else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid icookie"); - return STF_FAIL + INVALID_COOKIE; + loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid icookie"); + return STF_FAIL + INVALID_COOKIE; #endif - } - pbs->cur += COOKIE_SIZE; + } + pbs->cur += COOKIE_SIZE; - if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0) - { + if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0) + { #ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ + /* Ignore it, cisco sends odd icookies */ #else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid rcookie"); - return STF_FAIL + INVALID_COOKIE; + loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid rcookie"); + return STF_FAIL + 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 + 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"); - return STF_FAIL + PAYLOAD_MALFORMED; - } - - st->st_dpd_expectseqno = 0; - delete_dpd_event(st); - return STF_IGNORE; + } + 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 + 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"); + return STF_FAIL + PAYLOAD_MALFORMED; + } + + st->st_dpd_expectseqno = 0; + delete_dpd_event(st); + return STF_IGNORE; } /* @@ -5589,67 +5463,67 @@ dpd_inR(struct state *st, struct isakmp_notification *const n, pb_stream *pbs) void dpd_timeout(struct state *st) { - struct state *newest_phase1_st; - struct connection *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); - - if (c->kind == CK_INSTANCE) - delete_connection(c, TRUE); - initiate_connection(cname, NULL_FD); - break; - default: - loglog(RC_LOG_SERIOUS, "DPD: unknown action"); - } + struct state *newest_phase1_st; + struct connection *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); + + 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 index 60b5e4e31..2e242e903 100644 --- a/src/pluto/ipsec_doi.h +++ b/src/pluto/ipsec_doi.h @@ -10,55 +10,53 @@ * 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. - * - * RCSID $Id: ipsec_doi.h 3252 2007-10-06 21:24:50Z andreas $ */ 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); + , 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); + , 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; + 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); + , 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); + 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); + , 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); + , struct isakmp_notification *const n, pb_stream *n_pbs); extern void dpd_timeout(struct state *st); /* START_HASH_PAYLOAD @@ -70,14 +68,14 @@ extern void dpd_timeout(struct state *st); * - 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 */ \ + 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 @@ -88,17 +86,17 @@ extern void dpd_timeout(struct state *st); * 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 + INVALID_HASH_INFORMATION; \ - } \ - } + 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 + INVALID_HASH_INFORMATION; \ + } \ + } diff --git a/src/pluto/kameipsec.h b/src/pluto/kameipsec.h index 5f08c7d38..5e9d8ce99 100644 --- a/src/pluto/kameipsec.h +++ b/src/pluto/kameipsec.h @@ -3,45 +3,45 @@ /* The definitions, required to talk to KAME racoon IKE. */ -#define IPSEC_PORT_ANY 0 -#define IPSEC_ULPROTO_ANY 255 -#define IPSEC_PROTO_ANY 255 +#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 + 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 + 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 + 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 + IPSEC_LEVEL_DEFAULT = 0, + IPSEC_LEVEL_USE = 1, + IPSEC_LEVEL_REQUIRE = 2, + IPSEC_LEVEL_UNIQUE = 3 }; -#define IPSEC_MANUAL_REQID_MAX 0x3fff +#define IPSEC_MANUAL_REQID_MAX 0x3fff #define IPSEC_REPLAYWSIZE 32 #define IP_IPSEC_POLICY 16 #define IPV6_IPSEC_POLICY 34 -#endif /* __IPSEC_H */ +#endif /* __IPSEC_H */ diff --git a/src/pluto/kernel.c b/src/pluto/kernel.c index d42ac3372..f698de2c8 100644 --- a/src/pluto/kernel.c +++ b/src/pluto/kernel.c @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: kernel.c 3846 2008-04-18 17:01:45Z andreas $ */ #include <stddef.h> @@ -31,12 +29,14 @@ #include <arpa/inet.h> #include <freeswan.h> -#include <ipsec_policy.h> + +#include <library.h> +#include <crypto/rngs/rng.h> #ifdef KLIPS #include <signal.h> -#include <sys/time.h> /* for select(2) */ -#include <sys/types.h> /* for select(2) */ +#include <sys/time.h> /* for select(2) */ +#include <sys/types.h> /* for select(2) */ #include <pfkeyv2.h> #include <pfkey.h> #include "kameipsec.h" @@ -44,7 +44,6 @@ #include "constants.h" #include "defs.h" -#include "rnd.h" #include "id.h" #include "connections.h" #include "state.h" @@ -56,7 +55,7 @@ #include "log.h" #include "ca.h" #include "server.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ +#include "whack.h" /* for RC_LOG_SERIOUS */ #include "keys.h" #include "nat_traversal.h" #include "alg_info.h" @@ -69,7 +68,7 @@ bool can_do_IPcomp = TRUE; /* can system actually perform IPCOMP? */ * logic loses track and swats them? 64 is the best KLIPS can do. * And 32 is the best XFRM can do... */ -#define REPLAY_WINDOW 64 +#define REPLAY_WINDOW 64 #define REPLAY_WINDOW_XFRM 32 /* test if the routes required for two different connections agree @@ -77,11 +76,11 @@ bool can_do_IPcomp = TRUE; /* can system actually perform IPCOMP? */ * 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)) + && sameaddr(&(c)->spd.this.host_nexthop, &(d)->spd.this.host_nexthop)) #ifndef KLIPS -bool no_klips = TRUE; /* don't actually use KLIPS */ +bool no_klips = TRUE; /* don't actually use KLIPS */ #else /* !KLIPS */ @@ -96,50 +95,49 @@ bool no_klips = TRUE; /* don't actually use KLIPS */ * which %holds are news and which others should expire. */ -#define SHUNT_SCAN_INTERVAL (60 * 2) /* time between scans of eroutes */ +#define SHUNT_SCAN_INTERVAL (60 * 2) /* time between scans of eroutes */ /* SHUNT_PATIENCE only has resolution down to a multiple of the sample rate, * SHUNT_SCAN_INTERVAL. * By making SHUNT_PATIENCE an odd multiple of half of SHUNT_SCAN_INTERVAL, * we minimize the effects of jitter. */ -#define SHUNT_PATIENCE (SHUNT_SCAN_INTERVAL * 15 / 2) /* inactivity timeout */ +#define SHUNT_PATIENCE (SHUNT_SCAN_INTERVAL * 15 / 2) /* inactivity timeout */ struct bare_shunt { - policy_prio_t policy_prio; - ip_subnet ours; - ip_subnet his; - ip_said said; - int transport_proto; - unsigned long count; - time_t last_activity; - char *why; - struct bare_shunt *next; + policy_prio_t policy_prio; + ip_subnet ours; + ip_subnet his; + ip_said said; + int transport_proto; + unsigned long count; + time_t last_activity; + char *why; + struct bare_shunt *next; }; static struct bare_shunt *bare_shunts = NULL; #ifdef DEBUG -static void -DBG_bare_shunt(const char *op, const struct bare_shunt *bs) +static void DBG_bare_shunt(const char *op, const struct bare_shunt *bs) { - DBG(DBG_KLIPS, - { - int ourport = ntohs(portof(&(bs)->ours.addr)); - int hisport = ntohs(portof(&(bs)->his.addr)); - char ourst[SUBNETTOT_BUF]; - char hist[SUBNETTOT_BUF]; - char sat[SATOT_BUF]; - char prio[POLICY_PRIO_BUF]; - - subnettot(&(bs)->ours, 0, ourst, sizeof(ourst)); - subnettot(&(bs)->his, 0, hist, sizeof(hist)); - satot(&(bs)->said, 0, sat, sizeof(sat)); - fmt_policy_prio(bs->policy_prio, prio); - DBG_log("%s bare shunt %p %s:%d -> %s:%d => %s:%d %s %s" - , op, (const void *)(bs), ourst, ourport, hist, hisport - , sat, (bs)->transport_proto, prio, (bs)->why); - }); + DBG(DBG_KLIPS, + { + int ourport = ntohs(portof(&(bs)->ours.addr)); + int hisport = ntohs(portof(&(bs)->his.addr)); + char ourst[SUBNETTOT_BUF]; + char hist[SUBNETTOT_BUF]; + char sat[SATOT_BUF]; + char prio[POLICY_PRIO_BUF]; + + subnettot(&(bs)->ours, 0, ourst, sizeof(ourst)); + subnettot(&(bs)->his, 0, hist, sizeof(hist)); + satot(&(bs)->said, 0, sat, sizeof(sat)); + fmt_policy_prio(bs->policy_prio, prio); + DBG_log("%s bare shunt %p %s:%d -> %s:%d => %s:%d %s %s" + , op, (const void *)(bs), ourst, ourport, hist, hisport + , sat, (bs)->transport_proto, prio, (bs)->why); + }); } #else /* !DEBUG */ #define DBG_bare_shunt(op, bs) {} @@ -152,112 +150,108 @@ DBG_bare_shunt(const char *op, const struct bare_shunt *bs) struct eroute_info *orphaned_holds = NULL; /* forward declaration */ -static bool shunt_eroute(struct connection *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); +static bool shunt_eroute(struct connection *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); -bool no_klips = FALSE; /* don't actually use KLIPS */ +bool no_klips = FALSE; /* don't actually use KLIPS */ static const struct pfkey_proto_info null_proto_info[2] = { + { + proto: IPPROTO_ESP, + encapsulation: ENCAPSULATION_MODE_TRANSPORT, + reqid: 0 + }, + { + proto: 0, + encapsulation: 0, + reqid: 0 + } +}; + +void record_and_initiate_opportunistic(const ip_subnet *ours, + const ip_subnet *his, + int transport_proto, const char *why) +{ + passert(samesubnettype(ours, his)); + + /* Add to bare shunt list. + * We need to do this because the shunt was installed by KLIPS + * which can't do this itself. + */ { - proto: IPPROTO_ESP, - encapsulation: ENCAPSULATION_MODE_TRANSPORT, - reqid: 0 - }, + struct bare_shunt *bs = malloc_thing(struct bare_shunt); + + bs->why = clone_str(why); + bs->ours = *ours; + bs->his = *his; + bs->transport_proto = transport_proto; + bs->policy_prio = BOTTOM_PRIO; + + bs->said.proto = SA_INT; + bs->said.spi = htonl(SPI_HOLD); + bs->said.dst = *aftoinfo(subnettypeof(ours))->any; + + bs->count = 0; + bs->last_activity = now(); + + bs->next = bare_shunts; + bare_shunts = bs; + DBG_bare_shunt("add", bs); + } + + /* actually initiate opportunism */ { - proto: 0, - encapsulation: 0, - reqid: 0 + ip_address src, dst; + + networkof(ours, &src); + networkof(his, &dst); + initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD); } -}; -void -record_and_initiate_opportunistic(const ip_subnet *ours - , const ip_subnet *his - , int transport_proto - , const char *why) -{ - passert(samesubnettype(ours, his)); - - /* Add to bare shunt list. - * We need to do this because the shunt was installed by KLIPS - * which can't do this itself. - */ - { - struct bare_shunt *bs = alloc_thing(struct bare_shunt, "bare shunt"); - - bs->why = clone_str(why, "story for bare shunt"); - bs->ours = *ours; - bs->his = *his; - bs->transport_proto = transport_proto; - bs->policy_prio = BOTTOM_PRIO; - - bs->said.proto = SA_INT; - bs->said.spi = htonl(SPI_HOLD); - bs->said.dst = *aftoinfo(subnettypeof(ours))->any; - - bs->count = 0; - bs->last_activity = now(); - - bs->next = bare_shunts; - bare_shunts = bs; - DBG_bare_shunt("add", bs); - } - - /* actually initiate opportunism */ - { - ip_address src, dst; - - networkof(ours, &src); - networkof(his, &dst); - initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD); - } - - /* if present, remove from orphaned_holds list. - * NOTE: we do this last in case ours or his is a pointer into a member. - */ - { - struct eroute_info **pp, *p; - - for (pp = &orphaned_holds; (p = *pp) != NULL; pp = &p->next) - { - if (samesubnet(ours, &p->ours) - && samesubnet(his, &p->his) - && transport_proto == p->transport_proto - && portof(&ours->addr) == portof(&p->ours.addr) - && portof(&his->addr) == portof(&p->his.addr)) - { - *pp = p->next; - pfree(p); - break; - } + /* if present, remove from orphaned_holds list. + * NOTE: we do this last in case ours or his is a pointer into a member. + */ + { + struct eroute_info **pp, *p; + + for (pp = &orphaned_holds; (p = *pp) != NULL; pp = &p->next) + { + if (samesubnet(ours, &p->ours) + && samesubnet(his, &p->his) + && transport_proto == p->transport_proto + && portof(&ours->addr) == portof(&p->ours.addr) + && portof(&his->addr) == portof(&p->his.addr)) + { + *pp = p->next; + free(p); + break; + } + } } - } } #endif /* KLIPS */ static unsigned get_proto_reqid(unsigned base, int proto) { - switch (proto) - { - default: - case IPPROTO_COMP: - base++; - /* fall through */ - case IPPROTO_ESP: - base++; - /* fall through */ - case IPPROTO_AH: - break; - } - - return base; + switch (proto) + { + default: + case IPPROTO_COMP: + base++; + /* fall through */ + case IPPROTO_ESP: + base++; + /* fall through */ + case IPPROTO_AH: + break; + } + + return base; } /* Generate Unique SPI numbers. @@ -281,33 +275,39 @@ static unsigned get_proto_reqid(unsigned base, int proto) * check if the number was previously used (assuming that no * SPI lives longer than 4G of its successors). */ -ipsec_spi_t -get_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, bool tunnel) +ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, + bool tunnel) { - static ipsec_spi_t spi = 0; /* host order, so not returned directly! */ - char text_said[SATOT_BUF]; + static ipsec_spi_t spi = 0; /* host order, so not returned directly! */ + char text_said[SATOT_BUF]; + rng_t *rng; - set_text_said(text_said, &sr->this.host_addr, 0, proto); + set_text_said(text_said, &sr->this.host_addr, 0, proto); - if (kernel_ops->get_spi) - return kernel_ops->get_spi(&sr->that.host_addr - , &sr->this.host_addr, proto, tunnel - , get_proto_reqid(sr->reqid, proto) - , IPSEC_DOI_SPI_OUR_MIN, 0xffffffff - , text_said); - - spi++; - while (spi < IPSEC_DOI_SPI_OUR_MIN || spi == ntohl(avoid)) - get_rnd_bytes((u_char *)&spi, sizeof(spi)); + if (kernel_ops->get_spi) + { + return kernel_ops->get_spi(&sr->that.host_addr + , &sr->this.host_addr, proto, tunnel + , get_proto_reqid(sr->reqid, proto) + , IPSEC_DOI_SPI_OUR_MIN, 0xffffffff + , text_said); + } - DBG(DBG_CONTROL, + spi++; + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + while (spi < IPSEC_DOI_SPI_OUR_MIN || spi == ntohl(avoid)) { - ipsec_spi_t spi_net = htonl(spi); + rng->get_bytes(rng, sizeof(spi), (u_char *)&spi); + } + rng->destroy(rng); + DBG(DBG_CONTROL, + { + ipsec_spi_t spi_net = htonl(spi); - DBG_dump("generate SPI:", (u_char *)&spi_net, sizeof(spi_net)); - }); + DBG_dump("generate SPI:", (u_char *)&spi_net, sizeof(spi_net)); + }); - return htonl(spi); + return htonl(spi); } /* Generate Unique CPI numbers. @@ -318,38 +318,40 @@ get_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, bool tunnel) * If we can't find one easily, return 0 (a bad SPI, * no matter what order) indicating failure. */ -ipsec_spi_t -get_my_cpi(struct spd_route *sr, bool tunnel) +ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel) { - static cpi_t - first_busy_cpi = 0, - latest_cpi; - char text_said[SATOT_BUF]; + static cpi_t first_busy_cpi = 0, latest_cpi; + char text_said[SATOT_BUF]; + rng_t *rng; - set_text_said(text_said, &sr->this.host_addr, 0, IPPROTO_COMP); + set_text_said(text_said, &sr->this.host_addr, 0, IPPROTO_COMP); - if (kernel_ops->get_spi) - return kernel_ops->get_spi(&sr->that.host_addr - , &sr->this.host_addr, IPPROTO_COMP, tunnel - , get_proto_reqid(sr->reqid, IPPROTO_COMP) - , IPCOMP_FIRST_NEGOTIATED, IPCOMP_LAST_NEGOTIATED - , text_said); + if (kernel_ops->get_spi) + { + return kernel_ops->get_spi(&sr->that.host_addr + , &sr->this.host_addr, IPPROTO_COMP, tunnel + , get_proto_reqid(sr->reqid, IPPROTO_COMP) + , IPCOMP_FIRST_NEGOTIATED, IPCOMP_LAST_NEGOTIATED + , text_said); + } - while (!(IPCOMP_FIRST_NEGOTIATED <= first_busy_cpi && first_busy_cpi < IPCOMP_LAST_NEGOTIATED)) - { - get_rnd_bytes((u_char *)&first_busy_cpi, sizeof(first_busy_cpi)); - latest_cpi = first_busy_cpi; - } + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + while (!(IPCOMP_FIRST_NEGOTIATED <= first_busy_cpi && first_busy_cpi < IPCOMP_LAST_NEGOTIATED)) + { + rng->get_bytes(rng, sizeof(first_busy_cpi), (u_char *)&first_busy_cpi); + latest_cpi = first_busy_cpi; + } + rng->destroy(rng); - latest_cpi++; + latest_cpi++; - if (latest_cpi == first_busy_cpi) - find_my_cpi_gap(&latest_cpi, &first_busy_cpi); + if (latest_cpi == first_busy_cpi) + find_my_cpi_gap(&latest_cpi, &first_busy_cpi); - if (latest_cpi > IPCOMP_LAST_NEGOTIATED) - latest_cpi = IPCOMP_FIRST_NEGOTIATED; + if (latest_cpi > IPCOMP_LAST_NEGOTIATED) + latest_cpi = IPCOMP_FIRST_NEGOTIATED; - return htonl((ipsec_spi_t)latest_cpi); + return htonl((ipsec_spi_t)latest_cpi); } /* invoke the updown script to do the routing and firewall commands required @@ -386,872 +388,864 @@ get_my_cpi(struct spd_route *sr, bool tunnel) */ #ifndef DEFAULT_UPDOWN -# define DEFAULT_UPDOWN "ipsec _updown" +# define DEFAULT_UPDOWN "ipsec _updown" #endif -static bool -do_command(struct connection *c, struct spd_route *sr, const char *verb) +static bool do_command(struct connection *c, struct spd_route *sr, + const char *verb) { - char cmd[1536]; /* arbitrary limit on shell command length */ - const char *verb_suffix; + 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)) + /* figure out which verb suffix applies */ { - 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], - secure_myid_str[BUF_LEN] = "", - secure_peerid_str[BUF_LEN] = "", - secure_peerca_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 (addrbytesptr(&sr->this.host_srcip, NULL) - && !isanyaddr(&sr->this.host_srcip)) - { - char *n; - - strcpy(srcip_str, "PLUTO_MY_SOURCEIP='"); - n = srcip_str + strlen(srcip_str); - - addrtot(&sr->this.host_srcip, 0 - ,n , sizeof(srcip_str)-strlen(srcip_str)); - strncat(srcip_str, "' ", sizeof(srcip_str)); - } - - addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str)); - idtoa(&sr->this.id, myid_str, sizeof(myid_str)); - 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)); - - addrtot(&sr->that.host_addr, 0, peer_str, sizeof(peer_str)); - idtoa(&sr->that.id, peerid_str, sizeof(peerid_str)); - 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; - int pathlen; - - if (key->alg == PUBKEY_ALG_RSA && same_id(&sr->that.id, &key->id) - && trusted_ca(key->issuer, sr->that.ca, &pathlen)) - { - dntoa_or_null(peerca_str, BUF_LEN, key->issuer, ""); - escape_metachar(peerca_str, secure_peerca_str, sizeof(secure_peerca_str)); - 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" /* actual script */ - , verb, verb_suffix - , c->name - , nexthop_str - , c->interface->vname - , sr->this.hostaccess? "PLUTO_HOST_ACCESS='1' " : "" - , sr->reqid + 1 /* ESP requid */ - , 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 - , 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)); + const char *hs, *cs; -#ifdef KLIPS - if (!no_klips) - { - /* 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; + 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; } - /* log any output */ - for (;;) + /* form the command string */ { - /* if response doesn't fit in this buffer, it will be folded */ - char resp[256]; + 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], + secure_myid_str[BUF_LEN] = "", + secure_peerid_str[BUF_LEN] = "", + secure_peerca_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 (fgets(resp, sizeof(resp), f) == NULL) - { - if (ferror(f)) + if (addrbytesptr(&sr->this.host_srcip, NULL) + && !isanyaddr(&sr->this.host_srcip)) { - log_errno((e, "fgets failed on output of %s%s command" - , verb, verb_suffix)); - return FALSE; + char *n; + + strcpy(srcip_str, "PLUTO_MY_SOURCEIP='"); + n = srcip_str + strlen(srcip_str); + + addrtot(&sr->this.host_srcip, 0 + ,n , sizeof(srcip_str)-strlen(srcip_str)); + strncat(srcip_str, "' ", sizeof(srcip_str)); } - else + + addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str)); + idtoa(&sr->this.id, myid_str, sizeof(myid_str)); + 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)); + + addrtot(&sr->that.host_addr, 0, peer_str, sizeof(peer_str)); + idtoa(&sr->that.id, peerid_str, sizeof(peerid_str)); + 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) { - passert(feof(f)); - break; + pubkey_t *key = p->key; + key_type_t type = key->public_key->get_type(key->public_key); + int pathlen; + + if (type == KEY_RSA && same_id(&sr->that.id, &key->id) && + trusted_ca(key->issuer, sr->that.ca, &pathlen)) + { + dntoa_or_null(peerca_str, BUF_LEN, key->issuer, ""); + escape_metachar(peerca_str, secure_peerca_str, sizeof(secure_peerca_str)); + 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); - } + 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" /* actual script */ + , verb, verb_suffix + , c->name + , nexthop_str + , c->interface->vname + , sr->this.hostaccess? "PLUTO_HOST_ACCESS='1' " : "" + , sr->reqid + 1 /* ESP requid */ + , 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 + , sr->this.updown == NULL? DEFAULT_UPDOWN : sr->this.updown)) + { + loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, verb_suffix); + return FALSE; + } } - /* report on and react to return code */ + DBG(DBG_CONTROL, DBG_log("executing %s%s: %s" + , verb, verb_suffix, cmd)); + +#ifdef KLIPS + if (!no_klips) { - int r = pclose(f); + /* 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 (r == -1) - { - log_errno((e, "pclose failed for %s%s command" - , verb, verb_suffix)); - return FALSE; - } - else if (WIFEXITED(r)) - { - if (WEXITSTATUS(r) != 0) + if (f == NULL) { - loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d" - , verb, verb_suffix, WEXITSTATUS(r)); - return FALSE; + 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; + } } - } - 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; - } } - } #endif /* KLIPS */ - return TRUE; + 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 + route_impossible = 0, + route_easy = 1, + route_nearconflict = 2, + route_farconflict = 3 }; -static enum routability -could_route(struct connection *c) +static enum routability could_route(struct connection *c) { - struct spd_route *esr, *rosr; - struct connection *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 (!no_klips - && 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 */ - } + struct spd_route *esr, *rosr; + struct connection *ero /* who, if anyone, owns our eroute? */ + , *ro = route_owner(c, &rosr, &ero, &esr); /* who owns our route? */ -#ifdef KLIPS - /* if there is an eroute for another connection, there is a problem */ - if (ero != NULL && ero != c) - { - struct connection *ero2, *ero_top; - struct connection *inside, *outside; - - /* - * note, wavesec (PERMANENT) goes *outside* and - * OE goes *inside* (TEMPLATE) + /* 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. */ - inside = NULL; - outside= NULL; - if (ero->kind == CK_PERMANENT - && c->kind == CK_TEMPLATE) + if (c->kind == CK_TEMPLATE && !(c->policy & POLICY_OPPO)) { - outside = ero; - inside = c; + loglog(RC_ROUTE, "cannot route Road Warrior template"); + return route_impossible; } - else if (c->kind == CK_PERMANENT - && ero->kind == CK_TEMPLATE) + + /* if we don't know nexthop, we cannot route */ + if (isanyaddr(&c->spd.this.host_nexthop)) { - outside = c; - inside = ero; + loglog(RC_ROUTE, "cannot route connection without knowing our nexthop"); + return route_impossible; } - /* okay, check again, with correct order */ - if (outside && outside->kind == CK_PERMANENT - && inside && inside->kind == CK_TEMPLATE) + /* if routing would affect IKE messages, reject */ + if (!no_klips + && 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)) { - char inst[CONN_INST_BUF]; + loglog(RC_LOG_SERIOUS, "cannot install route: peer is within its client"); + return route_impossible; + } - /* this is a co-terminal attempt of the "near" kind. */ - /* when chaining, we chain from inside to outside */ + /* 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 */ + } - /* XXX permit multiple deep connections? */ - passert(inside->policy_next == NULL); +#ifdef KLIPS + /* if there is an eroute for another connection, there is a problem */ + if (ero != NULL && ero != c) + { + struct connection *ero2, *ero_top; + struct connection *inside, *outside; - inside->policy_next = 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; + } - /* 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; + /* okay, check again, with correct order */ + if (outside && outside->kind == CK_PERMANENT + && inside && inside->kind == CK_TEMPLATE) + { + char inst[CONN_INST_BUF]; - /* set the priority of the new eroute owner to be higher - * than that of the current eroute owner - */ - inside->prio = outside->prio + 1; + /* this is a co-terminal attempt of the "near" kind. */ + /* when chaining, we chain from inside to outside */ - fmt_conn_instance(inside, inst); + /* XXX permit multiple deep connections? */ + passert(inside->policy_next == NULL); - loglog(RC_LOG_SERIOUS - , "conflict on eroute (%s), switching eroute to %s and linking %s" - , inst, inside->name, outside->name); + inside->policy_next = outside; - return route_nearconflict; - } + /* 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; - /* look along the chain of policies for one with the same name */ - ero_top = ero; + /* set the priority of the new eroute owner to be higher + * than that of the current eroute owner + */ + inside->prio = outside->prio + 1; - for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next) - { - if (ero2->kind == CK_TEMPLATE - && streq(ero2->name, c->name)) - break; - } + fmt_conn_instance(inside, inst); - /* 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]; + 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); + 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 FALSE; /* another connection already using the eroute */ + loglog(RC_LOG_SERIOUS + , "cannot install eroute -- it is in use for \"%s\"%s #%lu" + , ero->name, inst, esr->eroute_owner); + return FALSE; /* another connection already using the eroute */ + } } - } #endif /* KLIPS */ - return route_easy; + return route_easy; } -bool -trap_connection(struct connection *c) +bool trap_connection(struct connection *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) + switch (could_route(c)) { - return route_and_eroute(c, &c->spd, NULL); + 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 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(struct connection *c) +/** + * Delete any eroute for a connection and unroute it if route isn't shared + */ +void unroute_connection(struct connection *c) { - struct spd_route *sr; - enum routing_t cr; - - for (sr = &c->spd; sr; sr = sr->next) - { - cr = sr->routing; + struct spd_route *sr; + enum routing_t cr; - if (erouted(cr)) + for (sr = &c->spd; sr; sr = sr->next) { - /* cannot handle a live one */ - passert(sr->routing != RT_ROUTED_TUNNEL); + cr = sr->routing; + + if (erouted(cr)) + { + /* cannot handle a live one */ + passert(sr->routing != RT_ROUTED_TUNNEL); #ifdef KLIPS - shunt_eroute(c, sr, RT_UNROUTED, ERO_DELETE, "delete"); + shunt_eroute(c, sr, RT_UNROUTED, ERO_DELETE, "delete"); #endif - } + } - sr->routing = RT_UNROUTED; /* do now so route_owner won't find us */ + 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, "unroute"); - } + /* only unroute if no other connection shares it */ + if (routed(cr) && route_owner(c, NULL, NULL, NULL) == NULL) + (void) do_command(c, sr, "unroute"); + } } #ifdef KLIPS -static void -set_text_said(char *text_said, const ip_address *dst, ipsec_spi_t spi, int proto) +static void set_text_said(char *text_said, const ip_address *dst, + ipsec_spi_t spi, int proto) { - ip_said said; + ip_said said; - initsaid(dst, spi, proto, &said); - satot(&said, 0, text_said, SATOT_BUF); + initsaid(dst, spi, proto, &said); + satot(&said, 0, text_said, SATOT_BUF); } /* find an entry in the bare_shunt table. * Trick: return a pointer to the pointer to the entry; * this allows the entry to be deleted. */ -static struct bare_shunt ** -bare_shunt_ptr(const ip_subnet *ours, const ip_subnet *his, int transport_proto) +static struct bare_shunt** bare_shunt_ptr(const ip_subnet *ours, + const ip_subnet *his, + int transport_proto) { - struct bare_shunt *p, **pp; - - for (pp = &bare_shunts; (p = *pp) != NULL; pp = &p->next) - { - if (samesubnet(ours, &p->ours) - && samesubnet(his, &p->his) - && transport_proto == p->transport_proto - && portof(&ours->addr) == portof(&p->ours.addr) - && portof(&his->addr) == portof(&p->his.addr)) - return pp; - } - return NULL; + struct bare_shunt *p, **pp; + + for (pp = &bare_shunts; (p = *pp) != NULL; pp = &p->next) + { + if (samesubnet(ours, &p->ours) + && samesubnet(his, &p->his) + && transport_proto == p->transport_proto + && portof(&ours->addr) == portof(&p->ours.addr) + && portof(&his->addr) == portof(&p->his.addr)) + return pp; + } + return NULL; } /* free a bare_shunt entry, given a pointer to the pointer */ -static void -free_bare_shunt(struct bare_shunt **pp) +static void free_bare_shunt(struct bare_shunt **pp) { - if (pp == NULL) - { - DBG(DBG_CONTROL, - DBG_log("delete bare shunt: null pointer") - ) - } - else - { - struct bare_shunt *p = *pp; - - *pp = p->next; - DBG_bare_shunt("delete", p); - pfree(p->why); - pfree(p); - } + if (pp == NULL) + { + DBG(DBG_CONTROL, + DBG_log("delete bare shunt: null pointer") + ) + } + else + { + struct bare_shunt *p = *pp; + + *pp = p->next; + DBG_bare_shunt("delete", p); + free(p->why); + free(p); + } } void show_shunt_status(void) { - struct bare_shunt *bs; - - for (bs = bare_shunts; bs != NULL; bs = bs->next) - { - /* Print interesting fields. Ignore count and last_active. */ - - int ourport = ntohs(portof(&bs->ours.addr)); - int hisport = ntohs(portof(&bs->his.addr)); - char ourst[SUBNETTOT_BUF]; - char hist[SUBNETTOT_BUF]; - char sat[SATOT_BUF]; - char prio[POLICY_PRIO_BUF]; - - subnettot(&(bs)->ours, 0, ourst, sizeof(ourst)); - subnettot(&(bs)->his, 0, hist, sizeof(hist)); - satot(&(bs)->said, 0, sat, sizeof(sat)); - fmt_policy_prio(bs->policy_prio, prio); - - whack_log(RC_COMMENT, "%s:%d -> %s:%d => %s:%d %s %s" - , ourst, ourport, hist, hisport, sat, bs->transport_proto - , prio, bs->why); - } - if (bare_shunts != NULL) - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ + struct bare_shunt *bs; + + for (bs = bare_shunts; bs != NULL; bs = bs->next) + { + /* Print interesting fields. Ignore count and last_active. */ + + int ourport = ntohs(portof(&bs->ours.addr)); + int hisport = ntohs(portof(&bs->his.addr)); + char ourst[SUBNETTOT_BUF]; + char hist[SUBNETTOT_BUF]; + char sat[SATOT_BUF]; + char prio[POLICY_PRIO_BUF]; + + subnettot(&(bs)->ours, 0, ourst, sizeof(ourst)); + subnettot(&(bs)->his, 0, hist, sizeof(hist)); + satot(&(bs)->said, 0, sat, sizeof(sat)); + fmt_policy_prio(bs->policy_prio, prio); + + whack_log(RC_COMMENT, "%s:%d -> %s:%d => %s:%d %s %s" + , ourst, ourport, hist, hisport, sat, bs->transport_proto + , prio, bs->why); + } + if (bare_shunts != NULL) + whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ } /* 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 - , ipsec_spi_t spi - , unsigned int proto - , unsigned int satype - , unsigned int transport_proto - , const struct pfkey_proto_info *proto_info - , time_t use_lifetime - , unsigned int op - , const char *opname USED_BY_DEBUG) +static bool raw_eroute(const ip_address *this_host, + const ip_subnet *this_client, + const ip_address *that_host, + const ip_subnet *that_client, + ipsec_spi_t spi, + unsigned int proto, + unsigned int satype, + unsigned int transport_proto, + const struct pfkey_proto_info *proto_info, + time_t use_lifetime, + unsigned int op, + const char *opname USED_BY_DEBUG) { - char text_said[SATOT_BUF]; + char text_said[SATOT_BUF]; - set_text_said(text_said, that_host, spi, proto); + set_text_said(text_said, that_host, spi, proto); - DBG(DBG_CONTROL | DBG_KLIPS, - { - 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); - }); - - return kernel_ops->raw_eroute(this_host, this_client - , that_host, that_client, spi, satype, transport_proto, proto_info - , use_lifetime, op, text_said); + DBG(DBG_CONTROL | DBG_KLIPS, + { + 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); + }); + + return kernel_ops->raw_eroute(this_host, this_client + , that_host, that_client, spi, satype, transport_proto, proto_info + , use_lifetime, op, text_said); } /* test to see if %hold remains */ -bool -has_bare_hold(const ip_address *src, const ip_address *dst, int transport_proto) +bool has_bare_hold(const ip_address *src, const ip_address *dst, + int transport_proto) { - ip_subnet this_client, that_client; - struct bare_shunt **bspp; - - passert(addrtypeof(src) == addrtypeof(dst)); - happy(addrtosubnet(src, &this_client)); - happy(addrtosubnet(dst, &that_client)); - bspp = bare_shunt_ptr(&this_client, &that_client, transport_proto); - return bspp != NULL - && (*bspp)->said.proto == SA_INT && (*bspp)->said.spi == htonl(SPI_HOLD); + ip_subnet this_client, that_client; + struct bare_shunt **bspp; + + passert(addrtypeof(src) == addrtypeof(dst)); + happy(addrtosubnet(src, &this_client)); + happy(addrtosubnet(dst, &that_client)); + bspp = bare_shunt_ptr(&this_client, &that_client, transport_proto); + return bspp != NULL + && (*bspp)->said.proto == SA_INT && (*bspp)->said.spi == htonl(SPI_HOLD); } /* Replace (or delete) a shunt that is in the bare_shunts table. * Issues the PF_KEY commands and updates the bare_shunts table. */ -bool -replace_bare_shunt(const ip_address *src, const ip_address *dst - , policy_prio_t policy_prio - , ipsec_spi_t shunt_spi /* in host order! */ - , bool repl /* if TRUE, replace; if FALSE, delete */ - , unsigned int transport_proto - , const char *why) +bool replace_bare_shunt(const ip_address *src, const ip_address *dst, + policy_prio_t policy_prio, ipsec_spi_t shunt_spi, + bool repl, unsigned int transport_proto, const char *why) { - ip_subnet this_client, that_client; - ip_subnet this_broad_client, that_broad_client; - const ip_address *null_host = aftoinfo(addrtypeof(src))->any; - - passert(addrtypeof(src) == addrtypeof(dst)); - happy(addrtosubnet(src, &this_client)); - happy(addrtosubnet(dst, &that_client)); - this_broad_client = this_client; - that_broad_client = that_client; - setportof(0, &this_broad_client.addr); - setportof(0, &that_broad_client.addr); - - if (repl) - { - struct bare_shunt **bs_pp = bare_shunt_ptr(&this_broad_client - , &that_broad_client, 0); - - /* is there already a broad host-to-host bare shunt? */ - if (bs_pp == NULL) - { - if (raw_eroute(null_host, &this_broad_client, null_host, &that_broad_client - , htonl(shunt_spi), SA_INT, SADB_X_SATYPE_INT - , 0, null_proto_info - , SHUNT_PATIENCE, ERO_ADD, why)) - { - struct bare_shunt *bs = alloc_thing(struct bare_shunt, "bare shunt"); - - bs->ours = this_broad_client; - bs->his = that_broad_client; - bs->transport_proto = 0; - bs->said.proto = SA_INT; - bs->why = clone_str(why, "bare shunt story"); - bs->policy_prio = policy_prio; - bs->said.spi = htonl(shunt_spi); - bs->said.dst = *null_host; - bs->count = 0; - bs->last_activity = now(); - bs->next = bare_shunts; - bare_shunts = bs; - DBG_bare_shunt("add", bs); - } + ip_subnet this_client, that_client; + ip_subnet this_broad_client, that_broad_client; + const ip_address *null_host = aftoinfo(addrtypeof(src))->any; + + passert(addrtypeof(src) == addrtypeof(dst)); + happy(addrtosubnet(src, &this_client)); + happy(addrtosubnet(dst, &that_client)); + this_broad_client = this_client; + that_broad_client = that_client; + setportof(0, &this_broad_client.addr); + setportof(0, &that_broad_client.addr); + + if (repl) + { + struct bare_shunt **bs_pp = bare_shunt_ptr(&this_broad_client + , &that_broad_client, 0); + + /* is there already a broad host-to-host bare shunt? */ + if (bs_pp == NULL) + { + if (raw_eroute(null_host, &this_broad_client, null_host, &that_broad_client + , htonl(shunt_spi), SA_INT, SADB_X_SATYPE_INT + , 0, null_proto_info + , SHUNT_PATIENCE, ERO_ADD, why)) + { + struct bare_shunt *bs = malloc_thing(struct bare_shunt); + + bs->ours = this_broad_client; + bs->his = that_broad_client; + bs->transport_proto = 0; + bs->said.proto = SA_INT; + bs->why = clone_str(why); + bs->policy_prio = policy_prio; + bs->said.spi = htonl(shunt_spi); + bs->said.dst = *null_host; + bs->count = 0; + bs->last_activity = now(); + bs->next = bare_shunts; + bare_shunts = bs; + DBG_bare_shunt("add", bs); + } + } + shunt_spi = SPI_HOLD; } - shunt_spi = SPI_HOLD; - } - if (raw_eroute(null_host, &this_client, null_host, &that_client - , htonl(shunt_spi), SA_INT, SADB_X_SATYPE_INT - , transport_proto, null_proto_info - , SHUNT_PATIENCE, ERO_DELETE, why)) - { - struct bare_shunt **bs_pp = bare_shunt_ptr(&this_client, &that_client - , transport_proto); + if (raw_eroute(null_host, &this_client, null_host, &that_client + , htonl(shunt_spi), SA_INT, SADB_X_SATYPE_INT + , transport_proto, null_proto_info + , SHUNT_PATIENCE, ERO_DELETE, why)) + { + struct bare_shunt **bs_pp = bare_shunt_ptr(&this_client, &that_client + , transport_proto); - /* delete bare eroute */ - free_bare_shunt(bs_pp); - return TRUE; - } - else - { - return FALSE; - } + /* delete bare eroute */ + free_bare_shunt(bs_pp); + return TRUE; + } + else + { + return FALSE; + } } -static bool -eroute_connection(struct spd_route *sr -, ipsec_spi_t spi, unsigned int proto, unsigned int satype -, const struct pfkey_proto_info *proto_info -, unsigned int op, const char *opname) +static bool eroute_connection(struct spd_route *sr, ipsec_spi_t spi, + unsigned int proto, unsigned int satype, + const struct pfkey_proto_info *proto_info, + unsigned int op, const char *opname) { - const ip_address *peer = &sr->that.host_addr; - char buf2[256]; + const ip_address *peer = &sr->that.host_addr; + char buf2[256]; - snprintf(buf2, sizeof(buf2) - , "eroute_connection %s", opname); + snprintf(buf2, sizeof(buf2) + , "eroute_connection %s", opname); - if (proto == SA_INT) - peer = aftoinfo(addrtypeof(peer))->any; + if (proto == SA_INT) + peer = aftoinfo(addrtypeof(peer))->any; - return raw_eroute(&sr->this.host_addr, &sr->this.client - , peer - , &sr->that.client - , spi, proto, satype - , sr->this.protocol, proto_info, 0, op, buf2); + return raw_eroute(&sr->this.host_addr, &sr->this.client + , peer + , &sr->that.client + , spi, proto, satype + , sr->this.protocol, proto_info, 0, op, buf2); } /* assign a bare hold to a connection */ -bool -assign_hold(struct connection *c USED_BY_DEBUG - , struct spd_route *sr - , int transport_proto - , const ip_address *src, const ip_address *dst) +bool assign_hold(struct connection *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, not the narrow one. - * 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. - * Once the broad %hold is in place, delete the narrow one. - */ - if (rn != ro) - { - if (erouted(ro) - ? !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT - , null_proto_info - , ERO_REPLACE, "replace %trap with broad %hold") - : !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT - , null_proto_info - , ERO_ADD, "add broad %hold")) - { - return FALSE; - } - } - if (!replace_bare_shunt(src, dst, BOTTOM_PRIO, SPI_HOLD, FALSE - , transport_proto, "delete narrow %hold")) - { - return FALSE; - } - sr->routing = rn; - return TRUE; + /* 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, not the narrow one. + * 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. + * Once the broad %hold is in place, delete the narrow one. + */ + if (rn != ro) + { + if (erouted(ro) + ? !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT + , null_proto_info + , ERO_REPLACE, "replace %trap with broad %hold") + : !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT + , null_proto_info + , ERO_ADD, "add broad %hold")) + { + return FALSE; + } + } + if (!replace_bare_shunt(src, dst, BOTTOM_PRIO, SPI_HOLD, FALSE + , transport_proto, "delete narrow %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) +static bool sag_eroute(struct state *st, struct spd_route *sr, + unsigned op, const char *opname) { - u_int inner_proto = 0; - u_int inner_satype = 0; - ipsec_spi_t inner_spi = 0; - struct pfkey_proto_info proto_info[4]; - int i; - bool tunnel; - - /* figure out the SPI and protocol (in two forms) - * for the innermost transformation. - */ - - i = sizeof(proto_info) / sizeof(proto_info[0]) - 1; - proto_info[i].proto = 0; - tunnel = FALSE; - - if (st->st_ah.present) - { - inner_spi = st->st_ah.attrs.spi; - inner_proto = SA_AH; - inner_satype = SADB_SATYPE_AH; - - i--; - proto_info[i].proto = IPPROTO_AH; - proto_info[i].encapsulation = st->st_ah.attrs.encapsulation; - tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; - proto_info[i].reqid = sr->reqid; - } - - if (st->st_esp.present) - { - inner_spi = st->st_esp.attrs.spi; - inner_proto = SA_ESP; - inner_satype = SADB_SATYPE_ESP; - - i--; - proto_info[i].proto = IPPROTO_ESP; - proto_info[i].encapsulation = st->st_esp.attrs.encapsulation; - tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; - proto_info[i].reqid = sr->reqid + 1; - } - - if (st->st_ipcomp.present) - { - inner_spi = st->st_ipcomp.attrs.spi; - inner_proto = SA_COMP; - inner_satype = SADB_X_SATYPE_COMP; - - i--; - proto_info[i].proto = IPPROTO_COMP; - proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation; - tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; - proto_info[i].reqid = sr->reqid + 2; - } - - if (i == sizeof(proto_info) / sizeof(proto_info[0]) - 1) - { - impossible(); /* no transform at all! */ - } - - if (tunnel) - { - int j; - - inner_spi = st->st_tunnel_out_spi; - inner_proto = SA_IPIP; - inner_satype = SADB_X_SATYPE_IPIP; - - proto_info[i].encapsulation = ENCAPSULATION_MODE_TUNNEL; - for (j = i + 1; proto_info[j].proto; j++) - { - proto_info[j].encapsulation = ENCAPSULATION_MODE_TRANSPORT; - } - } - - return eroute_connection(sr - , inner_spi, inner_proto, inner_satype, proto_info + i - , op, opname); + u_int inner_proto = 0; + u_int inner_satype = 0; + ipsec_spi_t inner_spi = 0; + struct pfkey_proto_info proto_info[4]; + int i; + bool tunnel; + + /* figure out the SPI and protocol (in two forms) + * for the innermost transformation. + */ + + i = sizeof(proto_info) / sizeof(proto_info[0]) - 1; + proto_info[i].proto = 0; + tunnel = FALSE; + + if (st->st_ah.present) + { + inner_spi = st->st_ah.attrs.spi; + inner_proto = SA_AH; + inner_satype = SADB_SATYPE_AH; + + i--; + proto_info[i].proto = IPPROTO_AH; + proto_info[i].encapsulation = st->st_ah.attrs.encapsulation; + tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; + proto_info[i].reqid = sr->reqid; + } + + if (st->st_esp.present) + { + inner_spi = st->st_esp.attrs.spi; + inner_proto = SA_ESP; + inner_satype = SADB_SATYPE_ESP; + + i--; + proto_info[i].proto = IPPROTO_ESP; + proto_info[i].encapsulation = st->st_esp.attrs.encapsulation; + tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; + proto_info[i].reqid = sr->reqid + 1; + } + + if (st->st_ipcomp.present) + { + inner_spi = st->st_ipcomp.attrs.spi; + inner_proto = SA_COMP; + inner_satype = SADB_X_SATYPE_COMP; + + i--; + proto_info[i].proto = IPPROTO_COMP; + proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation; + tunnel |= proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; + proto_info[i].reqid = sr->reqid + 2; + } + + if (i == sizeof(proto_info) / sizeof(proto_info[0]) - 1) + { + impossible(); /* no transform at all! */ + } + + if (tunnel) + { + int j; + + inner_spi = st->st_tunnel_out_spi; + inner_proto = SA_IPIP; + inner_satype = SADB_X_SATYPE_IPIP; + + proto_info[i].encapsulation = ENCAPSULATION_MODE_TUNNEL; + for (j = i + 1; proto_info[j].proto; j++) + { + proto_info[j].encapsulation = ENCAPSULATION_MODE_TRANSPORT; + } + } + + return eroute_connection(sr + , inner_spi, inner_proto, inner_satype, proto_info + i + , op, opname); } /* compute a (host-order!) SPI to implement the policy in connection c */ ipsec_spi_t shunt_policy_spi(struct connection *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]; + /* 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. @@ -1261,89 +1255,87 @@ shunt_policy_spi(struct connection *c, bool prospective) * If negotiation has failed, the choice between %trap/%pass/%drop/%reject * is specified in the policy of connection c. */ -static bool -shunt_eroute(struct connection *c -, struct spd_route *sr -, enum routing_t rt_kind -, unsigned int op, const char *opname) +static bool shunt_eroute(struct connection *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); - bool ok; - - 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. + /* 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. */ - 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); + ipsec_spi_t spi = shunt_policy_spi(c, rt_kind == RT_ROUTED_PROSPECTIVE); + bool ok; + + 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); + } } - } - else if (eclipse_count > 0 && op == ERO_DELETE && eclipsable(sr)) - { - /* maybe we are uneclipsing something */ - struct spd_route *esr; - struct connection *ue = eclipsed(c, &esr); - - if (ue != NULL) - { - esr->routing = RT_ROUTED_PROSPECTIVE; - return shunt_eroute(ue, esr - , RT_ROUTED_PROSPECTIVE, ERO_REPLACE, "restoring eclipsed"); - } - } - - ok = TRUE; - if (kernel_ops->inbound_eroute) - { - ok = raw_eroute(&c->spd.that.host_addr, &c->spd.that.client - , &c->spd.this.host_addr, &c->spd.this.client - , htonl(spi), SA_INT, SADB_X_SATYPE_INT - , 0, null_proto_info, 0 - , op | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT), opname); - } - return eroute_connection(sr, htonl(spi), SA_INT, SADB_X_SATYPE_INT - , null_proto_info, op, opname) && ok; + 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; + struct connection *ue = eclipsed(c, &esr); + + if (ue != NULL) + { + esr->routing = RT_ROUTED_PROSPECTIVE; + return shunt_eroute(ue, esr + , RT_ROUTED_PROSPECTIVE, ERO_REPLACE, "restoring eclipsed"); + } + } + + ok = TRUE; + if (kernel_ops->inbound_eroute) + { + ok = raw_eroute(&c->spd.that.host_addr, &c->spd.that.client + , &c->spd.this.host_addr, &c->spd.this.client + , htonl(spi), SA_INT, SADB_X_SATYPE_INT + , 0, null_proto_info, 0 + , op | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT), opname); + } + return eroute_connection(sr, htonl(spi), SA_INT, SADB_X_SATYPE_INT + , null_proto_info, op, opname) && ok; } @@ -1357,28 +1349,27 @@ shunt_eroute(struct connection *c * The task here is to remove the ":p" part so that the rest can be read * by another routine. */ -static const char * -read_proto(const char * s, size_t * len, int * transport_proto) +static const char *read_proto(const char * s, size_t * len, int * transport_proto) { - const char * p; - const char * ugh; - unsigned long proto; - size_t l; - - l = *len; - p = memchr(s, ':', l); - if (p == 0) { - *transport_proto = 0; - return 0; - } - ugh = ttoul(p+1, l-((p-s)+1), 10, &proto); - if (ugh != 0) - return ugh; - if (proto > 65535) - return "protocol number is too large, legal range is 0-65535"; - *len = p-s; - *transport_proto = proto; - return 0; + const char * p; + const char * ugh; + unsigned long proto; + size_t l; + + l = *len; + p = memchr(s, ':', l); + if (p == 0) { + *transport_proto = 0; + return 0; + } + ugh = ttoul(p+1, l-((p-s)+1), 10, &proto); + if (ugh != 0) + return ugh; + if (proto > 65535) + return "protocol number is too large, legal range is 0-65535"; + *len = p-s; + *transport_proto = proto; + return 0; } @@ -1407,937 +1398,931 @@ read_proto(const char * s, size_t * len, int * transport_proto) * searching for each is sequential. If this becomes a problem, faster * searches could be implemented (hash or radix tree, for example). */ -void -scan_proc_shunts(void) +void scan_proc_shunts(void) { - static const char procname[] = "/proc/net/ipsec_eroute"; - FILE *f; - time_t nw = now(); - int lino; - struct eroute_info *expired = NULL; - - event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL); - - DBG(DBG_CONTROL, - DBG_log("scanning for shunt eroutes") - ) - - /* free any leftover entries: they will be refreshed if still current */ - while (orphaned_holds != NULL) - { - struct eroute_info *p = orphaned_holds; - - orphaned_holds = p->next; - pfree(orphaned_holds); - } - - /* decode the /proc file. Don't do anything strenuous to it - * (certainly no PF_KEY stuff) to minimize the chance that it - * might change underfoot. - */ - - f = fopen(procname, "r"); - if (f == NULL) - return; - - /* for each line... */ - for (lino = 1; ; lino++) - { - unsigned char buf[1024]; /* should be big enough */ - chunk_t field[10]; /* 10 is loose upper bound */ - chunk_t *ff = NULL; /* fixed fields (excluding optional count) */ - int fi; - struct eroute_info eri; - char *cp; - err_t context = "" - , ugh = NULL; - - cp = fgets(buf, sizeof(buf), f); - if (cp == NULL) - break; - - /* break out each field - * Note: if there are too many fields, just stop; - * it will be diagnosed a little later. - */ - for (fi = 0; fi < (int)elemsof(field); fi++) + static const char procname[] = "/proc/net/ipsec_eroute"; + FILE *f; + time_t nw = now(); + int lino; + struct eroute_info *expired = NULL; + + event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL); + + DBG(DBG_CONTROL, + DBG_log("scanning for shunt eroutes") + ) + + /* free any leftover entries: they will be refreshed if still current */ + while (orphaned_holds != NULL) { - static const char sep[] = " \t\n"; /* field-separating whitespace */ - size_t w; + struct eroute_info *p = orphaned_holds; - cp += strspn(cp, sep); /* find start of field */ - w = strcspn(cp, sep); /* find width of field */ - setchunk(field[fi], cp, w); - cp += w; - if (w == 0) - break; + orphaned_holds = p->next; + free(orphaned_holds); } - /* This odd do-hickey is to share error reporting code. - * A break will get to that common code. The setting - * of "ugh" and "context" parameterize it. + /* decode the /proc file. Don't do anything strenuous to it + * (certainly no PF_KEY stuff) to minimize the chance that it + * might change underfoot. */ - do { - /* Old entries have no packet count; new ones do. - * check if things are as they should be. - */ - if (fi == 5) - ff = &field[0]; /* old form, with no count */ - else if (fi == 6) - ff = &field[1]; /* new form, with count */ - else - { - ugh = "has wrong number of fields"; - break; - } - - if (ff[1].len != 2 - || strncmp(ff[1].ptr, "->", 2) != 0 - || ff[3].len != 2 - || strncmp(ff[3].ptr, "=>", 2) != 0) - { - ugh = "is missing -> or =>"; - break; - } - /* actually digest fields of interest */ + f = fopen(procname, "r"); + if (f == NULL) + return; - /* packet count */ + /* for each line... */ + for (lino = 1; ; lino++) + { + unsigned char buf[1024]; /* should be big enough */ + chunk_t field[10]; /* 10 is loose upper bound */ + chunk_t *ff = NULL; /* fixed fields (excluding optional count) */ + int fi; + struct eroute_info eri; + char *cp; + err_t context = "" + , ugh = NULL; + + cp = fgets(buf, sizeof(buf), f); + if (cp == NULL) + break; - eri.count = 0; - if (ff != field) - { - context = "count field is malformed: "; - ugh = ttoul(field[0].ptr, field[0].len, 10, &eri.count); - if (ugh != NULL) - break; - } + /* break out each field + * Note: if there are too many fields, just stop; + * it will be diagnosed a little later. + */ + for (fi = 0; fi < (int)countof(field); fi++) + { + static const char sep[] = " \t\n"; /* field-separating whitespace */ + size_t w; + + cp += strspn(cp, sep); /* find start of field */ + w = strcspn(cp, sep); /* find width of field */ + field[fi] = chunk_create(cp, w); + cp += w; + if (w == 0) + break; + } - /* our client */ + /* This odd do-hickey is to share error reporting code. + * A break will get to that common code. The setting + * of "ugh" and "context" parameterize it. + */ + do { + /* Old entries have no packet count; new ones do. + * check if things are as they should be. + */ + if (fi == 5) + ff = &field[0]; /* old form, with no count */ + else if (fi == 6) + ff = &field[1]; /* new form, with count */ + else + { + ugh = "has wrong number of fields"; + break; + } - context = "source subnet field malformed: "; - ugh = ttosubnet(ff[0].ptr, ff[0].len, AF_INET, &eri.ours); - if (ugh != NULL) - break; + if (ff[1].len != 2 + || strncmp(ff[1].ptr, "->", 2) != 0 + || ff[3].len != 2 + || strncmp(ff[3].ptr, "=>", 2) != 0) + { + ugh = "is missing -> or =>"; + break; + } - /* his client */ + /* actually digest fields of interest */ - context = "destination subnet field malformed: "; - ugh = ttosubnet(ff[2].ptr, ff[2].len, AF_INET, &eri.his); - if (ugh != NULL) - break; + /* packet count */ - /* SAID */ + eri.count = 0; + if (ff != field) + { + context = "count field is malformed: "; + ugh = ttoul(field[0].ptr, field[0].len, 10, &eri.count); + if (ugh != NULL) + break; + } - context = "SA ID field malformed: "; - ugh = read_proto(ff[4].ptr, &ff[4].len, &eri.transport_proto); - if (ugh != NULL) - break; - ugh = ttosa(ff[4].ptr, ff[4].len, &eri.said); - } while (FALSE); - - if (ugh != NULL) - { - plog("INTERNAL ERROR: %s line %d %s%s" - , procname, lino, context, ugh); - continue; /* ignore rest of line */ - } - - /* Now we have decoded eroute, let's consider it. - * For shunt eroutes: - * - * %hold: if not known, add to orphaned_holds list for initiation - * because ACQUIRE might have been lost. - * - * %pass, %drop, %reject: determine if idle; if so, blast it away. - * Can occur bare (if DNS provided insufficient information) - * or with a connection (failure context). - * Could even be installed by ipsec manual. - * - * %trap: always welcome. - * - * For other eroutes: find state and record count change - */ - if (eri.said.proto == SA_INT) - { - /* shunt eroute */ - switch (ntohl(eri.said.spi)) - { - case SPI_HOLD: - if (bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto) == NULL - && shunt_owner(&eri.ours, &eri.his) == NULL) + /* our client */ + + context = "source subnet field malformed: "; + ugh = ttosubnet(ff[0].ptr, ff[0].len, AF_INET, &eri.ours); + if (ugh != NULL) + break; + + /* his client */ + + context = "destination subnet field malformed: "; + ugh = ttosubnet(ff[2].ptr, ff[2].len, AF_INET, &eri.his); + if (ugh != NULL) + break; + + /* SAID */ + + context = "SA ID field malformed: "; + ugh = read_proto(ff[4].ptr, &ff[4].len, &eri.transport_proto); + if (ugh != NULL) + break; + ugh = ttosa(ff[4].ptr, ff[4].len, &eri.said); + } while (FALSE); + + if (ugh != NULL) { - int ourport = ntohs(portof(&eri.ours.addr)); - int hisport = ntohs(portof(&eri.his.addr)); - char ourst[SUBNETTOT_BUF]; - char hist[SUBNETTOT_BUF]; - char sat[SATOT_BUF]; - - subnettot(&eri.ours, 0, ourst, sizeof(ourst)); - subnettot(&eri.his, 0, hist, sizeof(hist)); - satot(&eri.said, 0, sat, sizeof(sat)); - - DBG(DBG_CONTROL, - DBG_log("add orphaned shunt %s:%d -> %s:%d => %s:%d" - , ourst, ourport, hist, hisport, sat, eri.transport_proto) - ) - eri.next = orphaned_holds; - orphaned_holds = clone_thing(eri, "orphaned %hold"); + plog("INTERNAL ERROR: %s line %d %s%s" + , procname, lino, context, ugh); + continue; /* ignore rest of line */ } - break; - case SPI_PASS: - case SPI_DROP: - case SPI_REJECT: - /* nothing sensible to do if we don't have counts */ - if (ff != field) + /* Now we have decoded eroute, let's consider it. + * For shunt eroutes: + * + * %hold: if not known, add to orphaned_holds list for initiation + * because ACQUIRE might have been lost. + * + * %pass, %drop, %reject: determine if idle; if so, blast it away. + * Can occur bare (if DNS provided insufficient information) + * or with a connection (failure context). + * Could even be installed by ipsec manual. + * + * %trap: always welcome. + * + * For other eroutes: find state and record count change + */ + if (eri.said.proto == SA_INT) { - struct bare_shunt **bs_pp - = bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto); - - if (bs_pp != NULL) - { - struct bare_shunt *bs = *bs_pp; - - if (eri.count != bs->count) + /* shunt eroute */ + switch (ntohl(eri.said.spi)) { - bs->count = eri.count; - bs->last_activity = nw; + case SPI_HOLD: + if (bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto) == NULL + && shunt_owner(&eri.ours, &eri.his) == NULL) + { + int ourport = ntohs(portof(&eri.ours.addr)); + int hisport = ntohs(portof(&eri.his.addr)); + char ourst[SUBNETTOT_BUF]; + char hist[SUBNETTOT_BUF]; + char sat[SATOT_BUF]; + + subnettot(&eri.ours, 0, ourst, sizeof(ourst)); + subnettot(&eri.his, 0, hist, sizeof(hist)); + satot(&eri.said, 0, sat, sizeof(sat)); + + DBG(DBG_CONTROL, + DBG_log("add orphaned shunt %s:%d -> %s:%d => %s:%d" + , ourst, ourport, hist, hisport, sat, eri.transport_proto) + ) + eri.next = orphaned_holds; + orphaned_holds = clone_thing(eri); + } + break; + + case SPI_PASS: + case SPI_DROP: + case SPI_REJECT: + /* nothing sensible to do if we don't have counts */ + if (ff != field) + { + struct bare_shunt **bs_pp + = bare_shunt_ptr(&eri.ours, &eri.his, eri.transport_proto); + + if (bs_pp != NULL) + { + struct bare_shunt *bs = *bs_pp; + + if (eri.count != bs->count) + { + bs->count = eri.count; + bs->last_activity = nw; + } + else if (nw - bs->last_activity > SHUNT_PATIENCE) + { + eri.next = expired; + expired = clone_thing(eri); + } + } + } + break; + + case SPI_TRAP: + break; + + default: + bad_case(ntohl(eri.said.spi)); } - else if (nw - bs->last_activity > SHUNT_PATIENCE) - { - eri.next = expired; - expired = clone_thing(eri, "expired %pass"); - } - } } - break; - - case SPI_TRAP: - break; + else + { + /* regular (non-shunt) eroute */ + state_eroute_usage(&eri.ours, &eri.his, eri.count, nw); + } + } /* for each line */ + fclose(f); - default: - bad_case(ntohl(eri.said.spi)); - } - } - else + /* Now that we've finished processing the /proc file, + * it is safe to delete the expired %pass shunts. + */ + while (expired != NULL) { - /* regular (non-shunt) eroute */ - state_eroute_usage(&eri.ours, &eri.his, eri.count, nw); - } - } /* for each line */ - fclose(f); - - /* Now that we've finished processing the /proc file, - * it is safe to delete the expired %pass shunts. - */ - while (expired != NULL) - { - struct eroute_info *p = expired; - ip_address src, dst; - - networkof(&p->ours, &src); - networkof(&p->his, &dst); - (void) replace_bare_shunt(&src, &dst - , BOTTOM_PRIO /* not used because we are deleting. This value is a filler */ - , SPI_PASS /* not used because we are deleting. This value is a filler */ - , FALSE, p->transport_proto, "delete expired bare shunts"); - expired = p->next; - pfree(p); - } + struct eroute_info *p = expired; + ip_address src, dst; + + networkof(&p->ours, &src); + networkof(&p->his, &dst); + (void) replace_bare_shunt(&src, &dst + , BOTTOM_PRIO /* not used because we are deleting. This value is a filler */ + , SPI_PASS /* not used because we are deleting. This value is a filler */ + , FALSE, p->transport_proto, "delete expired bare shunts"); + expired = p->next; + free(p); + } } -static bool -del_spi(ipsec_spi_t spi, int proto -, const ip_address *src, const ip_address *dest) +static bool del_spi(ipsec_spi_t spi, int proto, + const ip_address *src, const ip_address *dest) { - char text_said[SATOT_BUF]; - struct kernel_sa sa; + char text_said[SATOT_BUF]; + struct kernel_sa sa; - set_text_said(text_said, dest, spi, proto); + set_text_said(text_said, dest, spi, proto); - DBG(DBG_KLIPS, DBG_log("delete %s", text_said)); + DBG(DBG_KLIPS, DBG_log("delete %s", text_said)); - memset(&sa, 0, sizeof(sa)); - sa.spi = spi; - sa.proto = proto; - sa.src = src; - sa.dst = dest; - sa.text_said = text_said; + memset(&sa, 0, sizeof(sa)); + sa.spi = spi; + sa.proto = proto; + sa.src = src; + sa.dst = dest; + sa.text_said = text_said; - return kernel_ops->del_sa(&sa); + return kernel_ops->del_sa(&sa); } /* Setup a pair of SAs. Code taken from setsa.c and spigrp.c, in * ipsec-0.5. */ -static bool -setup_half_ipsec_sa(struct state *st, bool inbound) +static bool setup_half_ipsec_sa(struct state *st, bool inbound) { - /* Build an inbound or outbound SA */ - - struct connection *c = st->st_connection; - ip_subnet src, dst; - ip_subnet src_client, dst_client; - ipsec_spi_t inner_spi = 0; - u_int proto = 0; - u_int satype = SADB_SATYPE_UNSPEC; - bool replace; - - /* SPIs, saved for spigrouping or undoing, if necessary */ - struct kernel_sa - said[EM_MAXRELSPIS], - *said_next = said; - - char text_said[SATOT_BUF]; - int encapsulation; - - replace = inbound && (kernel_ops->get_spi != NULL); - - src.maskbits = 0; - dst.maskbits = 0; - - if (inbound) - { - src.addr = c->spd.that.host_addr; - dst.addr = c->spd.this.host_addr; - src_client = c->spd.that.client; - dst_client = c->spd.this.client; - } - else - { - src.addr = c->spd.this.host_addr, - dst.addr = c->spd.that.host_addr; - src_client = c->spd.this.client; - dst_client = c->spd.that.client; - } - - encapsulation = ENCAPSULATION_MODE_TRANSPORT; - 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) - { - encapsulation = ENCAPSULATION_MODE_TUNNEL; - } - - memset(said, 0, sizeof(said)); - - /* If we are tunnelling, set up IP in IP pseudo SA */ - - if (kernel_ops->inbound_eroute) - { - inner_spi = 256; - proto = SA_IPIP; - satype = SADB_SATYPE_UNSPEC; - } - else if (encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - /* XXX hack alert -- we SHOULD NOT HAVE TO HAVE A DIFFERENT SPI - * XXX FOR IP-in-IP ENCAPSULATION! - */ + /* Build an inbound or outbound SA */ - ipsec_spi_t ipip_spi; + struct connection *c = st->st_connection; + ip_subnet src, dst; + ip_subnet src_client, dst_client; + ipsec_spi_t inner_spi = 0; + u_int proto = 0; + u_int satype = SADB_SATYPE_UNSPEC; + bool replace; - /* Allocate an SPI for the tunnel. - * Since our peer will never see this, - * and it comes from its own number space, - * it is purely a local implementation wart. - */ + /* SPIs, saved for spigrouping or undoing, if necessary */ + struct kernel_sa + said[EM_MAXRELSPIS], + *said_next = said; + + char text_said[SATOT_BUF]; + int encapsulation; + + replace = inbound && (kernel_ops->get_spi != NULL); + + src.maskbits = 0; + dst.maskbits = 0; + + if (inbound) + { + src.addr = c->spd.that.host_addr; + dst.addr = c->spd.this.host_addr; + src_client = c->spd.that.client; + dst_client = c->spd.this.client; + } + else { - static ipsec_spi_t last_tunnel_spi = IPSEC_DOI_SPI_OUR_MIN; + src.addr = c->spd.this.host_addr, + dst.addr = c->spd.that.host_addr; + src_client = c->spd.this.client; + dst_client = c->spd.that.client; + } - ipip_spi = htonl(++last_tunnel_spi); - if (inbound) - st->st_tunnel_in_spi = ipip_spi; - else - st->st_tunnel_out_spi = ipip_spi; + encapsulation = ENCAPSULATION_MODE_TRANSPORT; + 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) + { + encapsulation = ENCAPSULATION_MODE_TUNNEL; } - set_text_said(text_said - , &c->spd.that.host_addr, ipip_spi, SA_IPIP); + memset(said, 0, sizeof(said)); - said_next->src = &src.addr; - said_next->dst = &dst.addr; - said_next->src_client = &src_client; - said_next->dst_client = &dst_client; - said_next->spi = ipip_spi; - said_next->satype = SADB_X_SATYPE_IPIP; - said_next->text_said = text_said; + /* If we are tunnelling, set up IP in IP pseudo SA */ - if (!kernel_ops->add_sa(said_next, replace)) - goto fail; + if (kernel_ops->inbound_eroute) + { + inner_spi = 256; + proto = SA_IPIP; + satype = SADB_SATYPE_UNSPEC; + } + else if (encapsulation == ENCAPSULATION_MODE_TUNNEL) + { + /* XXX hack alert -- we SHOULD NOT HAVE TO HAVE A DIFFERENT SPI + * XXX FOR IP-in-IP ENCAPSULATION! + */ - said_next++; + ipsec_spi_t ipip_spi; - inner_spi = ipip_spi; - proto = SA_IPIP; - satype = SADB_X_SATYPE_IPIP; - } + /* Allocate an SPI for the tunnel. + * Since our peer will never see this, + * and it comes from its own number space, + * it is purely a local implementation wart. + */ + { + static ipsec_spi_t last_tunnel_spi = IPSEC_DOI_SPI_OUR_MIN; - /* set up IPCOMP SA, if any */ + ipip_spi = htonl(++last_tunnel_spi); + if (inbound) + st->st_tunnel_in_spi = ipip_spi; + else + st->st_tunnel_out_spi = ipip_spi; + } - if (st->st_ipcomp.present) - { - ipsec_spi_t ipcomp_spi = inbound? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi; - unsigned compalg; + set_text_said(text_said + , &c->spd.that.host_addr, ipip_spi, SA_IPIP); - switch (st->st_ipcomp.attrs.transid) - { - case IPCOMP_DEFLATE: - compalg = SADB_X_CALG_DEFLATE; - break; + said_next->src = &src.addr; + said_next->dst = &dst.addr; + said_next->src_client = &src_client; + said_next->dst_client = &dst_client; + said_next->spi = ipip_spi; + said_next->satype = SADB_X_SATYPE_IPIP; + said_next->text_said = text_said; - default: - loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented" - , enum_name(&ipcomp_transformid_names, st->st_ipcomp.attrs.transid)); - goto fail; - } + if (!kernel_ops->add_sa(said_next, replace)) + goto fail; - set_text_said(text_said, &dst.addr, ipcomp_spi, SA_COMP); + said_next++; - said_next->src = &src.addr; - said_next->dst = &dst.addr; - said_next->src_client = &src_client; - said_next->dst_client = &dst_client; - said_next->spi = ipcomp_spi; - said_next->satype = SADB_X_SATYPE_COMP; - said_next->compalg = compalg; - said_next->encapsulation = encapsulation; - said_next->reqid = c->spd.reqid + 2; - said_next->text_said = text_said; + inner_spi = ipip_spi; + proto = SA_IPIP; + satype = SADB_X_SATYPE_IPIP; + } - if (!kernel_ops->add_sa(said_next, replace)) - goto fail; + /* set up IPCOMP SA, if any */ - said_next++; + if (st->st_ipcomp.present) + { + ipsec_spi_t ipcomp_spi = inbound? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi; + unsigned compalg; - encapsulation = ENCAPSULATION_MODE_TRANSPORT; - } + switch (st->st_ipcomp.attrs.transid) + { + case IPCOMP_DEFLATE: + compalg = SADB_X_CALG_DEFLATE; + break; + + default: + loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented" + , enum_name(&ipcomp_transformid_names, st->st_ipcomp.attrs.transid)); + goto fail; + } - /* set up ESP SA, if any */ + set_text_said(text_said, &dst.addr, ipcomp_spi, SA_COMP); - 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; - const struct esp_info *ei; - u_int16_t key_len; - - static const struct esp_info esp_info[] = { - { ESP_NULL, AUTH_ALGORITHM_HMAC_MD5, - 0, HMAC_MD5_KEY_LEN, - SADB_EALG_NULL, SADB_AALG_MD5HMAC }, - { ESP_NULL, AUTH_ALGORITHM_HMAC_SHA1, - 0, HMAC_SHA1_KEY_LEN, - SADB_EALG_NULL, SADB_AALG_SHA1HMAC }, - - { ESP_DES, AUTH_ALGORITHM_NONE, - DES_CBC_BLOCK_SIZE, 0, - SADB_EALG_DESCBC, SADB_AALG_NONE }, - { ESP_DES, AUTH_ALGORITHM_HMAC_MD5, - DES_CBC_BLOCK_SIZE, HMAC_MD5_KEY_LEN, - SADB_EALG_DESCBC, SADB_AALG_MD5HMAC }, - { ESP_DES, AUTH_ALGORITHM_HMAC_SHA1, - DES_CBC_BLOCK_SIZE, - HMAC_SHA1_KEY_LEN, SADB_EALG_DESCBC, SADB_AALG_SHA1HMAC }, - - { ESP_3DES, AUTH_ALGORITHM_NONE, - DES_CBC_BLOCK_SIZE * 3, 0, - SADB_EALG_3DESCBC, SADB_AALG_NONE }, - { ESP_3DES, AUTH_ALGORITHM_HMAC_MD5, - DES_CBC_BLOCK_SIZE * 3, HMAC_MD5_KEY_LEN, - SADB_EALG_3DESCBC, SADB_AALG_MD5HMAC }, - { ESP_3DES, AUTH_ALGORITHM_HMAC_SHA1, - DES_CBC_BLOCK_SIZE * 3, HMAC_SHA1_KEY_LEN, - SADB_EALG_3DESCBC, SADB_AALG_SHA1HMAC }, - }; + said_next->src = &src.addr; + said_next->dst = &dst.addr; + said_next->src_client = &src_client; + said_next->dst_client = &dst_client; + said_next->spi = ipcomp_spi; + said_next->satype = SADB_X_SATYPE_COMP; + said_next->compalg = compalg; + said_next->encapsulation = encapsulation; + said_next->reqid = c->spd.reqid + 2; + said_next->text_said = text_said; - u_int8_t natt_type = 0; - u_int16_t natt_sport = 0; - u_int16_t natt_dport = 0; - ip_address natt_oa; + if (!kernel_ops->add_sa(said_next, replace)) + goto fail; - if (st->nat_traversal & NAT_T_DETECTED) - { - natt_type = (st->nat_traversal & NAT_T_WITH_PORT_FLOATING) ? - ESPINUDP_WITH_NON_ESP : ESPINUDP_WITH_NON_IKE; - natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port; - natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port; - natt_oa = st->nat_oa; + said_next++; + + encapsulation = ENCAPSULATION_MODE_TRANSPORT; } - for (ei = esp_info; ; ei++) + /* set up ESP SA, if any */ + + if (st->st_esp.present) { - if (ei == &esp_info[elemsof(esp_info)]) - { - /* Check for additional kernel alg */ -#ifndef NO_KERNEL_ALG - if ((ei=kernel_alg_esp_info(st->st_esp.attrs.transid, - st->st_esp.attrs.auth))!=NULL) { - break; + 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; + const struct esp_info *ei; + u_int16_t key_len; + + static const struct esp_info esp_info[] = { + { ESP_NULL, AUTH_ALGORITHM_HMAC_MD5, + 0, HMAC_MD5_KEY_LEN, + SADB_EALG_NULL, SADB_AALG_MD5HMAC }, + { ESP_NULL, AUTH_ALGORITHM_HMAC_SHA1, + 0, HMAC_SHA1_KEY_LEN, + SADB_EALG_NULL, SADB_AALG_SHA1HMAC }, + + { ESP_DES, AUTH_ALGORITHM_NONE, + DES_CBC_BLOCK_SIZE, 0, + SADB_EALG_DESCBC, SADB_AALG_NONE }, + { ESP_DES, AUTH_ALGORITHM_HMAC_MD5, + DES_CBC_BLOCK_SIZE, HMAC_MD5_KEY_LEN, + SADB_EALG_DESCBC, SADB_AALG_MD5HMAC }, + { ESP_DES, AUTH_ALGORITHM_HMAC_SHA1, + DES_CBC_BLOCK_SIZE, + HMAC_SHA1_KEY_LEN, SADB_EALG_DESCBC, SADB_AALG_SHA1HMAC }, + + { ESP_3DES, AUTH_ALGORITHM_NONE, + DES_CBC_BLOCK_SIZE * 3, 0, + SADB_EALG_3DESCBC, SADB_AALG_NONE }, + { ESP_3DES, AUTH_ALGORITHM_HMAC_MD5, + DES_CBC_BLOCK_SIZE * 3, HMAC_MD5_KEY_LEN, + SADB_EALG_3DESCBC, SADB_AALG_MD5HMAC }, + { ESP_3DES, AUTH_ALGORITHM_HMAC_SHA1, + DES_CBC_BLOCK_SIZE * 3, HMAC_SHA1_KEY_LEN, + SADB_EALG_3DESCBC, SADB_AALG_SHA1HMAC }, + }; + + u_int8_t natt_type = 0; + u_int16_t natt_sport = 0; + u_int16_t natt_dport = 0; + ip_address natt_oa; + + if (st->nat_traversal & NAT_T_DETECTED) + { + natt_type = (st->nat_traversal & NAT_T_WITH_PORT_FLOATING) ? + ESPINUDP_WITH_NON_ESP : ESPINUDP_WITH_NON_IKE; + natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port; + natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port; + natt_oa = st->nat_oa; } -#endif - /* note: enum_show may use a static buffer, so two - * calls in one printf would be a mistake. - * enum_name does the same job, without a static buffer, - * assuming the name will be found. - */ - loglog(RC_LOG_SERIOUS, "ESP transform %s / auth %s not implemented yet" - , enum_name(&esp_transformid_names, st->st_esp.attrs.transid) - , enum_name(&auth_alg_names, st->st_esp.attrs.auth)); - goto fail; - } - - if (st->st_esp.attrs.transid == ei->transid - && st->st_esp.attrs.auth == ei->auth) - break; - } + for (ei = esp_info; ; ei++) + { + if (ei == &esp_info[countof(esp_info)]) + { + /* Check for additional kernel alg */ +#ifndef NO_KERNEL_ALG + if ((ei=kernel_alg_esp_info(st->st_esp.attrs.transid, + st->st_esp.attrs.auth))!=NULL) { + break; + } +#endif - 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 passed key_len=%d > %d", - enum_name(&esp_transformid_names, st->st_esp.attrs.transid), - (int)key_len, (int)ei->enckeylen); - goto fail; - } - } - else - { - key_len = ei->enckeylen; - } - /* Grrrrr.... f*cking 7 bits jurassic algos */ + /* note: enum_show may use a static buffer, so two + * calls in one printf would be a mistake. + * enum_name does the same job, without a static buffer, + * assuming the name will be found. + */ + loglog(RC_LOG_SERIOUS, "ESP transform %s / auth %s not implemented yet" + , enum_name(&esp_transformid_names, st->st_esp.attrs.transid) + , enum_name(&auth_alg_names, st->st_esp.attrs.auth)); + goto fail; + } - /* 168 bits in kernel, need 192 bits for keymat_len */ - if (ei->transid == ESP_3DES && key_len == 21) - key_len = 24; + if (st->st_esp.attrs.transid == ei->transid + && st->st_esp.attrs.auth == ei->auth) + break; + } - /* 56 bits in kernel, need 64 bits for keymat_len */ - if (ei->transid == ESP_DES && key_len == 7) - key_len = 8; + 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 passed key_len=%d > %d", + enum_name(&esp_transformid_names, st->st_esp.attrs.transid), + (int)key_len, (int)ei->enckeylen); + goto fail; + } + } + else + { + key_len = ei->enckeylen; + } + /* Grrrrr.... f*cking 7 bits jurassic algos */ + + /* 168 bits in kernel, need 192 bits for keymat_len */ + if (ei->transid == ESP_3DES && key_len == 21) + key_len = 24; + + /* 56 bits in kernel, need 64 bits for keymat_len */ + if (ei->transid == ESP_DES && key_len == 7) + key_len = 8; + + /* divide up keying material */ + /* passert(st->st_esp.keymat_len == ei->enckeylen + ei->authkeylen); */ + DBG(DBG_KLIPS|DBG_CONTROL|DBG_PARSING, + if(st->st_esp.keymat_len != key_len + ei->authkeylen) + DBG_log("keymat_len=%d key_len=%d authkeylen=%d", + st->st_esp.keymat_len, (int)key_len, (int)ei->authkeylen); + ) + passert(st->st_esp.keymat_len == key_len + ei->authkeylen); + + set_text_said(text_said, &dst.addr, esp_spi, SA_ESP); + + said_next->src = &src.addr; + said_next->dst = &dst.addr; + said_next->src_client = &src_client; + said_next->dst_client = &dst_client; + said_next->spi = esp_spi; + said_next->satype = SADB_SATYPE_ESP; + said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? REPLAY_WINDOW : REPLAY_WINDOW_XFRM; + said_next->authalg = ei->authalg; + said_next->authkeylen = ei->authkeylen; + /* said_next->authkey = esp_dst_keymat + ei->enckeylen; */ + said_next->authkey = esp_dst_keymat + key_len; + said_next->encalg = ei->encryptalg; + /* said_next->enckeylen = ei->enckeylen; */ + said_next->enckeylen = key_len; + said_next->enckey = esp_dst_keymat; + said_next->encapsulation = encapsulation; + said_next->reqid = c->spd.reqid + 1; + said_next->natt_sport = natt_sport; + said_next->natt_dport = natt_dport; + said_next->transid = st->st_esp.attrs.transid; + said_next->natt_type = natt_type; + said_next->natt_oa = &natt_oa; + said_next->text_said = text_said; + + if (!kernel_ops->add_sa(said_next, replace)) + goto fail; + + said_next++; + + encapsulation = ENCAPSULATION_MODE_TRANSPORT; + } - /* divide up keying material */ - /* passert(st->st_esp.keymat_len == ei->enckeylen + ei->authkeylen); */ - DBG(DBG_KLIPS|DBG_CONTROL|DBG_PARSING, - if(st->st_esp.keymat_len != key_len + ei->authkeylen) - DBG_log("keymat_len=%d key_len=%d authkeylen=%d", - st->st_esp.keymat_len, (int)key_len, (int)ei->authkeylen); - ) - passert(st->st_esp.keymat_len == key_len + ei->authkeylen); - - set_text_said(text_said, &dst.addr, esp_spi, SA_ESP); - - said_next->src = &src.addr; - said_next->dst = &dst.addr; - said_next->src_client = &src_client; - said_next->dst_client = &dst_client; - said_next->spi = esp_spi; - said_next->satype = SADB_SATYPE_ESP; - said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? REPLAY_WINDOW : REPLAY_WINDOW_XFRM; - said_next->authalg = ei->authalg; - said_next->authkeylen = ei->authkeylen; - /* said_next->authkey = esp_dst_keymat + ei->enckeylen; */ - said_next->authkey = esp_dst_keymat + key_len; - said_next->encalg = ei->encryptalg; - /* said_next->enckeylen = ei->enckeylen; */ - said_next->enckeylen = key_len; - said_next->enckey = esp_dst_keymat; - said_next->encapsulation = encapsulation; - said_next->reqid = c->spd.reqid + 1; - said_next->natt_sport = natt_sport; - said_next->natt_dport = natt_dport; - said_next->transid = st->st_esp.attrs.transid; - said_next->natt_type = natt_type; - said_next->natt_oa = &natt_oa; - said_next->text_said = text_said; - - if (!kernel_ops->add_sa(said_next, replace)) - goto fail; - - said_next++; + /* set up AH SA, if any */ - encapsulation = ENCAPSULATION_MODE_TRANSPORT; - } + 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; - /* set up AH SA, if any */ + unsigned char authalg; - 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; + switch (st->st_ah.attrs.auth) + { + case AUTH_ALGORITHM_HMAC_MD5: + authalg = SADB_AALG_MD5HMAC; + break; - unsigned char authalg; + case AUTH_ALGORITHM_HMAC_SHA1: + authalg = SADB_AALG_SHA1HMAC; + break; - switch (st->st_ah.attrs.auth) - { - case AUTH_ALGORITHM_HMAC_MD5: - authalg = SADB_AALG_MD5HMAC; - break; + default: + loglog(RC_LOG_SERIOUS, "%s not implemented yet" + , enum_show(&auth_alg_names, st->st_ah.attrs.auth)); + goto fail; + } - case AUTH_ALGORITHM_HMAC_SHA1: - authalg = SADB_AALG_SHA1HMAC; - break; + set_text_said(text_said, &dst.addr, ah_spi, SA_AH); - default: - loglog(RC_LOG_SERIOUS, "%s not implemented yet" - , enum_show(&auth_alg_names, st->st_ah.attrs.auth)); - goto fail; - } + said_next->src = &src.addr; + said_next->dst = &dst.addr; + said_next->src_client = &src_client; + said_next->dst_client = &dst_client; + said_next->spi = ah_spi; + said_next->satype = SADB_SATYPE_AH; + said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? REPLAY_WINDOW : REPLAY_WINDOW_XFRM; + said_next->authalg = authalg; + said_next->authkeylen = st->st_ah.keymat_len; + said_next->authkey = ah_dst_keymat; + said_next->encapsulation = encapsulation; + said_next->reqid = c->spd.reqid; + said_next->text_said = text_said; - set_text_said(text_said, &dst.addr, ah_spi, SA_AH); + if (!kernel_ops->add_sa(said_next, replace)) + goto fail; - said_next->src = &src.addr; - said_next->dst = &dst.addr; - said_next->src_client = &src_client; - said_next->dst_client = &dst_client; - said_next->spi = ah_spi; - said_next->satype = SADB_SATYPE_AH; - said_next->replay_window = (kernel_ops->type == KERNEL_TYPE_KLIPS) ? REPLAY_WINDOW : REPLAY_WINDOW_XFRM; - said_next->authalg = authalg; - said_next->authkeylen = st->st_ah.keymat_len; - said_next->authkey = ah_dst_keymat; - said_next->encapsulation = encapsulation; - said_next->reqid = c->spd.reqid; - said_next->text_said = text_said; + said_next++; - if (!kernel_ops->add_sa(said_next, replace)) - goto fail; + encapsulation = ENCAPSULATION_MODE_TRANSPORT; + } - said_next++; + 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) + { + encapsulation = ENCAPSULATION_MODE_TUNNEL; + } - encapsulation = ENCAPSULATION_MODE_TRANSPORT; - } - - 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) - { - encapsulation = ENCAPSULATION_MODE_TUNNEL; - } - - if (kernel_ops->inbound_eroute ? c->spd.eroute_owner == SOS_NOBODY - : encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - /* If inbound, and policy does not specifie DISABLEARRIVALCHECK, - * tell KLIPS to enforce the IP addresses appropriate for this tunnel. - * Note reversed ends. - * Not much to be done on failure. - */ - if (inbound && (c->policy & POLICY_DISABLEARRIVALCHECK) == 0) + if (kernel_ops->inbound_eroute ? c->spd.eroute_owner == SOS_NOBODY + : encapsulation == ENCAPSULATION_MODE_TUNNEL) { - struct pfkey_proto_info proto_info[4]; - int i = 0; - - if (st->st_ipcomp.present) - { - proto_info[i].proto = IPPROTO_COMP; - proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation; - proto_info[i].reqid = c->spd.reqid + 2; - i++; - } - - if (st->st_esp.present) - { - proto_info[i].proto = IPPROTO_ESP; - proto_info[i].encapsulation = st->st_esp.attrs.encapsulation; - proto_info[i].reqid = c->spd.reqid + 1; - i++; - } - - if (st->st_ah.present) - { - proto_info[i].proto = IPPROTO_AH; - proto_info[i].encapsulation = st->st_ah.attrs.encapsulation; - proto_info[i].reqid = c->spd.reqid; - i++; - } - - proto_info[i].proto = 0; - - if (kernel_ops->inbound_eroute - && encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - proto_info[0].encapsulation = ENCAPSULATION_MODE_TUNNEL; - for (i = 1; proto_info[i].proto; i++) + /* If inbound, and policy does not specifie DISABLEARRIVALCHECK, + * tell KLIPS to enforce the IP addresses appropriate for this tunnel. + * Note reversed ends. + * Not much to be done on failure. + */ + if (inbound && (c->policy & POLICY_DISABLEARRIVALCHECK) == 0) { - proto_info[i].encapsulation = ENCAPSULATION_MODE_TRANSPORT; + struct pfkey_proto_info proto_info[4]; + int i = 0; + + if (st->st_ipcomp.present) + { + proto_info[i].proto = IPPROTO_COMP; + proto_info[i].encapsulation = st->st_ipcomp.attrs.encapsulation; + proto_info[i].reqid = c->spd.reqid + 2; + i++; + } + + if (st->st_esp.present) + { + proto_info[i].proto = IPPROTO_ESP; + proto_info[i].encapsulation = st->st_esp.attrs.encapsulation; + proto_info[i].reqid = c->spd.reqid + 1; + i++; + } + + if (st->st_ah.present) + { + proto_info[i].proto = IPPROTO_AH; + proto_info[i].encapsulation = st->st_ah.attrs.encapsulation; + proto_info[i].reqid = c->spd.reqid; + i++; + } + + proto_info[i].proto = 0; + + if (kernel_ops->inbound_eroute + && encapsulation == ENCAPSULATION_MODE_TUNNEL) + { + proto_info[0].encapsulation = ENCAPSULATION_MODE_TUNNEL; + for (i = 1; proto_info[i].proto; i++) + { + proto_info[i].encapsulation = ENCAPSULATION_MODE_TRANSPORT; + } + } + + /* MCR - should be passed a spd_eroute structure here */ + (void) raw_eroute(&c->spd.that.host_addr, &c->spd.that.client + , &c->spd.this.host_addr, &c->spd.this.client + , inner_spi, proto, satype, c->spd.this.protocol + , proto_info, 0 + , ERO_ADD_INBOUND, "add inbound"); } - } - - /* MCR - should be passed a spd_eroute structure here */ - (void) raw_eroute(&c->spd.that.host_addr, &c->spd.that.client - , &c->spd.this.host_addr, &c->spd.this.client - , inner_spi, proto, satype, c->spd.this.protocol - , proto_info, 0 - , ERO_ADD_INBOUND, "add inbound"); - } - } - - /* If there are multiple SPIs, group them. */ - - if (kernel_ops->grp_sa && said_next > &said[1]) - { - struct kernel_sa *s; + } + + /* If there are multiple SPIs, group them. */ - /* group SAs, two at a time, inner to outer (backwards in said[]) - * The grouping is by pairs. So if said[] contains ah esp ipip, - * the grouping would be ipip:esp, esp:ah. - */ - for (s = said; s < said_next-1; s++) - { - char - text_said0[SATOT_BUF], - text_said1[SATOT_BUF]; - - /* group s[1] and s[0], in that order */ - - set_text_said(text_said0, s[0].dst, s[0].spi, s[0].proto); - set_text_said(text_said1, s[1].dst, s[1].spi, s[1].proto); - - DBG(DBG_KLIPS, DBG_log("grouping %s and %s", text_said1, text_said0)); - - s[0].text_said = text_said0; - s[1].text_said = text_said1; - - if (!kernel_ops->grp_sa(s + 1, s)) - goto fail; - } - /* could update said, but it will not be used */ - } - - return TRUE; + if (kernel_ops->grp_sa && said_next > &said[1]) + { + struct kernel_sa *s; + + /* group SAs, two at a time, inner to outer (backwards in said[]) + * The grouping is by pairs. So if said[] contains ah esp ipip, + * the grouping would be ipip:esp, esp:ah. + */ + for (s = said; s < said_next-1; s++) + { + char + text_said0[SATOT_BUF], + text_said1[SATOT_BUF]; + + /* group s[1] and s[0], in that order */ + + set_text_said(text_said0, s[0].dst, s[0].spi, s[0].proto); + set_text_said(text_said1, s[1].dst, s[1].spi, s[1].proto); + + DBG(DBG_KLIPS, DBG_log("grouping %s and %s", text_said1, text_said0)); + + s[0].text_said = text_said0; + s[1].text_said = text_said1; + + if (!kernel_ops->grp_sa(s + 1, s)) + goto fail; + } + /* could update said, but it will not be used */ + } + + return TRUE; fail: - { - /* undo the done SPIs */ - while (said_next-- != said) - (void) del_spi(said_next->spi, said_next->proto - , &src.addr, said_next->dst); - return FALSE; - } + { + /* undo the done SPIs */ + while (said_next-- != said) + (void) del_spi(said_next->spi, said_next->proto + , &src.addr, said_next->dst); + return FALSE; + } } /* teardown_ipsec_sa is a canibalized version of setup_ipsec_sa */ -static bool -teardown_half_ipsec_sa(struct state *st, bool inbound) +static bool teardown_half_ipsec_sa(struct state *st, bool inbound) { - /* We need to delete AH, ESP, and IP in IP SPIs. - * But if there is more than one, they have been grouped - * so deleting any one will do. So we just delete the - * first one found. It may or may not be the only one. - */ - struct connection *c = st->st_connection; - struct { - unsigned proto; - struct ipsec_proto_info *info; - } protos[4]; - int i; - bool result; - - i = 0; - if (kernel_ops->inbound_eroute && inbound - && c->spd.eroute_owner == SOS_NOBODY) - { - (void) raw_eroute(&c->spd.that.host_addr, &c->spd.that.client - , &c->spd.this.host_addr, &c->spd.this.client - , 256, IPSEC_PROTO_ANY, SADB_SATYPE_UNSPEC, c->spd.this.protocol - , null_proto_info, 0 - , ERO_DEL_INBOUND, "delete inbound"); - } - - if (!kernel_ops->grp_sa) - { - if (st->st_ah.present) + /* We need to delete AH, ESP, and IP in IP SPIs. + * But if there is more than one, they have been grouped + * so deleting any one will do. So we just delete the + * first one found. It may or may not be the only one. + */ + struct connection *c = st->st_connection; + struct { + unsigned proto; + struct ipsec_proto_info *info; + } protos[4]; + int i; + bool result; + + i = 0; + if (kernel_ops->inbound_eroute && inbound + && c->spd.eroute_owner == SOS_NOBODY) { - protos[i].info = &st->st_ah; - protos[i].proto = SA_AH; - i++; + (void) raw_eroute(&c->spd.that.host_addr, &c->spd.that.client + , &c->spd.this.host_addr, &c->spd.this.client + , 256, IPSEC_PROTO_ANY, SADB_SATYPE_UNSPEC, c->spd.this.protocol + , null_proto_info, 0 + , ERO_DEL_INBOUND, "delete inbound"); } - if (st->st_esp.present) + if (!kernel_ops->grp_sa) { - protos[i].info = &st->st_esp; - protos[i].proto = SA_ESP; - i++; - } + if (st->st_ah.present) + { + protos[i].info = &st->st_ah; + protos[i].proto = SA_AH; + i++; + } - if (st->st_ipcomp.present) - { - protos[i].info = &st->st_ipcomp; - protos[i].proto = SA_COMP; - i++; - } - } - else if (st->st_ah.present) - { - protos[i].info = &st->st_ah; - protos[i].proto = SA_AH; - i++; - } - else if (st->st_esp.present) - { - protos[i].info = &st->st_esp; - protos[i].proto = SA_ESP; - i++; - } - else - { - impossible(); /* neither AH nor ESP in outbound SA bundle! */ - } - protos[i].proto = 0; - - result = TRUE; - for (i = 0; protos[i].proto; i++) - { - unsigned proto = protos[i].proto; - ipsec_spi_t spi; - const ip_address *src, *dst; + if (st->st_esp.present) + { + protos[i].info = &st->st_esp; + protos[i].proto = SA_ESP; + i++; + } - if (inbound) + if (st->st_ipcomp.present) + { + protos[i].info = &st->st_ipcomp; + protos[i].proto = SA_COMP; + i++; + } + } + else if (st->st_ah.present) + { + protos[i].info = &st->st_ah; + protos[i].proto = SA_AH; + i++; + } + else if (st->st_esp.present) { - spi = protos[i].info->our_spi; - src = &c->spd.that.host_addr; - dst = &c->spd.this.host_addr; + protos[i].info = &st->st_esp; + protos[i].proto = SA_ESP; + i++; } else { - spi = protos[i].info->attrs.spi; - src = &c->spd.this.host_addr; - dst = &c->spd.that.host_addr; + impossible(); /* neither AH nor ESP in outbound SA bundle! */ } + protos[i].proto = 0; + + result = TRUE; + for (i = 0; protos[i].proto; i++) + { + unsigned proto = protos[i].proto; + ipsec_spi_t spi; + const ip_address *src, *dst; + + if (inbound) + { + spi = protos[i].info->our_spi; + src = &c->spd.that.host_addr; + dst = &c->spd.this.host_addr; + } + else + { + spi = protos[i].info->attrs.spi; + src = &c->spd.this.host_addr; + dst = &c->spd.that.host_addr; + } - result &= del_spi(spi, proto, src, dst); - } - return result; + result &= del_spi(spi, proto, src, 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) +bool get_sa_info(struct state *st, bool inbound, u_int *bytes, time_t *use_time) { - char text_said[SATOT_BUF]; - struct kernel_sa sa; - struct connection *c = st->st_connection; + char text_said[SATOT_BUF]; + struct kernel_sa sa; + struct connection *c = st->st_connection; - *use_time = UNDEFINED_TIME; + *use_time = UNDEFINED_TIME; - if (kernel_ops->get_sa == NULL || !st->st_esp.present) - return FALSE; + if (kernel_ops->get_sa == NULL || !st->st_esp.present) + return FALSE; - memset(&sa, 0, sizeof(sa)); - sa.proto = SA_ESP; - - if (inbound) - { - sa.src = &c->spd.that.host_addr; - sa.dst = &c->spd.this.host_addr; - sa.spi = st->st_esp.our_spi; - } - else - { - sa.src = &c->spd.this.host_addr; - sa.dst = &c->spd.that.host_addr; - sa.spi = st->st_esp.attrs.spi; - } - set_text_said(text_said, sa.dst, sa.spi, sa.proto); - - sa.text_said = text_said; - - DBG(DBG_KLIPS, - DBG_log("get %s", text_said) - ) - if (!kernel_ops->get_sa(&sa, bytes)) - return FALSE; - DBG(DBG_KLIPS, - DBG_log(" current: %d bytes", *bytes) - ) - - if (st->st_serialno == c->spd.eroute_owner) - { - DBG(DBG_KLIPS, - DBG_log("get %sbound policy with reqid %u" - , inbound? "in":"out", (u_int)c->spd.reqid + 1) - ) - sa.transport_proto = c->spd.this.protocol; - sa.encapsulation = st->st_esp.attrs.encapsulation; + memset(&sa, 0, sizeof(sa)); + sa.proto = SA_ESP; if (inbound) { - sa.src_client = &c->spd.that.client; - sa.dst_client = &c->spd.this.client; + sa.src = &c->spd.that.host_addr; + sa.dst = &c->spd.this.host_addr; + sa.spi = st->st_esp.our_spi; } else { - sa.src_client = &c->spd.this.client; - sa.dst_client = &c->spd.that.client; + sa.src = &c->spd.this.host_addr; + sa.dst = &c->spd.that.host_addr; + sa.spi = st->st_esp.attrs.spi; } - if (!kernel_ops->get_policy(&sa, inbound, use_time)) - return FALSE; + set_text_said(text_said, sa.dst, sa.spi, sa.proto); + + sa.text_said = text_said; + + DBG(DBG_KLIPS, + DBG_log("get %s", text_said) + ) + if (!kernel_ops->get_sa(&sa, bytes)) + return FALSE; DBG(DBG_KLIPS, - DBG_log(" use_time: %s", timetoa(use_time, FALSE)) + DBG_log(" current: %d bytes", *bytes) ) - } - return TRUE; + + if (st->st_serialno == c->spd.eroute_owner) + { + DBG(DBG_KLIPS, + DBG_log("get %sbound policy with reqid %u" + , inbound? "in":"out", (u_int)c->spd.reqid + 1) + ) + sa.transport_proto = c->spd.this.protocol; + sa.encapsulation = st->st_esp.attrs.encapsulation; + + if (inbound) + { + sa.src_client = &c->spd.that.client; + sa.dst_client = &c->spd.this.client; + } + else + { + sa.src_client = &c->spd.this.client; + sa.dst_client = &c->spd.that.client; + } + if (!kernel_ops->get_policy(&sa, inbound, use_time)) + return FALSE; + DBG(DBG_KLIPS, + DBG_log(" use_time: %T", use_time, FALSE) + ) + } + return TRUE; } const struct kernel_ops *kernel_ops; #endif /* KLIPS */ -void -init_kernel(void) +void init_kernel(void) { #ifdef KLIPS - if (no_klips) - { - kernel_ops = &noklips_kernel_ops; - return; - } + if (no_klips) + { + kernel_ops = &noklips_kernel_ops; + return; + } - init_pfkey(); + init_pfkey(); - kernel_ops = &klips_kernel_ops; + kernel_ops = &klips_kernel_ops; #if defined(linux) && defined(KERNEL26_SUPPORT) - { - bool linux_ipsec = 0; - struct stat buf; - - linux_ipsec = (stat("/proc/net/pfkey", &buf) == 0); - if (linux_ipsec) - { - plog("Using Linux 2.6 IPsec interface code"); - kernel_ops = &linux_kernel_ops; - } - else - { - plog("Using KLIPS IPsec interface code"); - } - } + { + bool linux_ipsec = 0; + struct stat buf; + + linux_ipsec = (stat("/proc/net/pfkey", &buf) == 0); + if (linux_ipsec) + { + plog("Using Linux 2.6 IPsec interface code"); + kernel_ops = &linux_kernel_ops; + } + else + { + plog("Using KLIPS IPsec interface code"); + } + } #endif - if (kernel_ops->init) - { - kernel_ops->init(); - } + if (kernel_ops->init) + { + kernel_ops->init(); + } - /* register SA types that we can negotiate */ - can_do_IPcomp = FALSE; /* until we get a response from KLIPS */ - kernel_ops->pfkey_register(); + /* register SA types that we can negotiate */ + can_do_IPcomp = FALSE; /* until we get a response from KLIPS */ + kernel_ops->pfkey_register(); - if (!kernel_ops->policy_lifetime) - { - event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL); - } + if (!kernel_ops->policy_lifetime) + { + event_schedule(EVENT_SHUNT_SCAN, SHUNT_SCAN_INTERVAL, NULL); + } #endif } @@ -2345,60 +2330,59 @@ init_kernel(void) * 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) +bool install_inbound_ipsec_sa(struct state *st) { - struct connection *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; - struct connection *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; - } + struct connection *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; + struct connection *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; + } #ifdef KLIPS - /* (attempt to) actually set up the SAs */ - return setup_half_ipsec_sa(st, TRUE); + /* (attempt to) actually set up the SAs */ + return setup_half_ipsec_sa(st, TRUE); #else /* !KLIPS */ - DBG(DBG_CONTROL, DBG_log("install_inbound_ipsec_sa()")); - return TRUE; + DBG(DBG_CONTROL, DBG_log("install_inbound_ipsec_sa()")); + return TRUE; #endif /* !KLIPS */ } @@ -2407,481 +2391,479 @@ install_inbound_ipsec_sa(struct state *st) * Any SA Group must have already been created. * On failure, steps will be unwound. */ -bool -route_and_eroute(struct connection *c USED_BY_KLIPS - , struct spd_route *sr USED_BY_KLIPS - , struct state *st USED_BY_KLIPS) +bool route_and_eroute(struct connection *c USED_BY_KLIPS, + struct spd_route *sr USED_BY_KLIPS, + struct state *st USED_BY_KLIPS) { #ifdef KLIPS - struct spd_route *esr; - struct spd_route *rosr; - struct connection *ero /* who, if anyone, owns our eroute? */ - , *ro = route_owner(c, &rosr, &ero, &esr); - bool eroute_installed = FALSE - , firewall_notified = FALSE - , route_installed = FALSE; - - struct connection *ero_top; - struct bare_shunt **bspp; - - 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; + struct spd_route *esr; + struct spd_route *rosr; + struct connection *ero /* who, if anyone, owns our eroute? */ + , *ro = route_owner(c, &rosr, &ero, &esr); + bool eroute_installed = FALSE + , firewall_notified = FALSE + , route_installed = FALSE; + + struct connection *ero_top; + struct bare_shunt **bspp; + + 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; + /* 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 - bspp = (ero == NULL) - ? bare_shunt_ptr(&sr->this.client, &sr->that.client, sr->this.protocol) - : NULL; + bspp = (ero == NULL) + ? bare_shunt_ptr(&sr->this.client, &sr->that.client, sr->this.protocol) + : NULL; - /* install the eroute */ + /* install the eroute */ - passert(bspp == NULL || ero == NULL); /* only one non-NULL */ + passert(bspp == NULL || ero == NULL); /* only one non-NULL */ - if (bspp != NULL || ero != NULL) - { - /* We're replacing an eroute */ + if (bspp != NULL || 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 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)); - } + /* 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 - /* remember to free bspp iff we make it out of here alive */ - } - 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, "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, "prepare"); /* just in case; ignore failure */ - route_installed = do_command(c, sr, "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, "unroute"); - route_installed = do_command(c, sr, "route"); + /* remember to free bspp iff we make it out of here alive */ } else { - route_installed = do_command(c, sr, "route"); - (void) do_command(ro, sr, "unroute"); + /* 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"); } - /* record unrouting */ - if (route_installed) - { - do { - passert(!erouted(rosr->routing)); - rosr->routing = RT_UNROUTED; + /* notify the firewall of a new tunnel */ - /* no need to keep old value */ - ro = route_owner(c, &rosr, NULL, NULL); - } while (ro != NULL); + 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, "up"); /* go ahead and notify */ } - } - /* all done -- clean up */ - if (route_installed) - { - /* Success! */ + /* install the route */ - if (bspp != NULL) + DBG(DBG_CONTROL, + DBG_log("route_and_eroute: firewall_notified: %s" + , firewall_notified ? "true" : "false")); + if (!firewall_notified) { - free_bare_shunt(bspp); + /* we're in trouble -- don't do routing */ } - else if (ero != NULL && ero != c) + else if (ro == NULL) { - /* check if ero is an ancestor of c. */ - struct connection *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++; - } - } + /* a new route: no deletion required, but preparation is */ + (void) do_command(c, sr, "prepare"); /* just in case; ignore failure */ + route_installed = do_command(c, sr, "route"); } - - if (st == NULL) + else if (routed(sr->routing) + || routes_agree(ro, c)) { - passert(sr->eroute_owner == SOS_NOBODY); - sr->routing = RT_ROUTED_PROSPECTIVE; + route_installed = TRUE; /* nothing to be done */ } else { - char cib[CONN_INST_BUF]; - sr->routing = RT_ROUTED_TUNNEL; + /* 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, "unroute"); + route_installed = do_command(c, sr, "route"); + } + else + { + route_installed = do_command(c, sr, "route"); + (void) do_command(ro, sr, "unroute"); + } - 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; - } + /* record unrouting */ + if (route_installed) + { + do { + passert(!erouted(rosr->routing)); + rosr->routing = RT_UNROUTED; - return TRUE; - } - else - { - /* Failure! Unwind our work. */ - if (firewall_notified && sr->eroute_owner == SOS_NOBODY) - (void) do_command(c, sr, "down"); + /* no need to keep old value */ + ro = route_owner(c, &rosr, NULL, NULL); + } while (ro != NULL); + } + } - if (eroute_installed) + /* all done -- clean up */ + if (route_installed) { - /* Restore original eroute, if we can. - * Since there is nothing much to be done if the restoration - * fails, ignore success or failure. - */ - if (bspp != NULL) - { - /* Restore old bare_shunt. - * I don't think that this case is very likely. - * Normally a bare shunt would have been assigned - * to a connection before we've gotten this far. - */ - struct bare_shunt *bs = *bspp; - - (void) raw_eroute(&bs->said.dst /* should be useless */ - , &bs->ours - , &bs->said.dst /* should be useless */ - , &bs->his - , bs->said.spi /* network order */ - , SA_INT - , SADB_X_SATYPE_INT - , 0 - , null_proto_info - , SHUNT_PATIENCE - , ERO_REPLACE, "restore"); - } - else if (ero != NULL) - { - /* restore ero's former glory */ - if (esr->eroute_owner == SOS_NOBODY) + /* Success! */ + + if (bspp != NULL) { - /* note: normal or eclipse case */ - (void) shunt_eroute(ero, esr - , esr->routing, ERO_REPLACE, "restore"); + free_bare_shunt(bspp); } - else + else if (ero != NULL && ero != c) { - /* 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"); + /* check if ero is an ancestor of c. */ + struct connection *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++; + } + } } - } - else - { - /* there was no previous eroute: delete whatever we installed */ + if (st == NULL) - (void) shunt_eroute(c, sr - , sr->routing, ERO_DELETE, "delete"); + { + passert(sr->eroute_owner == SOS_NOBODY); + sr->routing = RT_ROUTED_PROSPECTIVE; + } else - (void) sag_eroute(st, sr - , ERO_DELETE, "delete"); - } + { + 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, "down"); - return FALSE; - } + 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 (bspp != NULL) + { + /* Restore old bare_shunt. + * I don't think that this case is very likely. + * Normally a bare shunt would have been assigned + * to a connection before we've gotten this far. + */ + struct bare_shunt *bs = *bspp; + + (void) raw_eroute(&bs->said.dst /* should be useless */ + , &bs->ours + , &bs->said.dst /* should be useless */ + , &bs->his + , bs->said.spi /* network order */ + , SA_INT + , SADB_X_SATYPE_INT + , 0 + , null_proto_info + , SHUNT_PATIENCE + , ERO_REPLACE, "restore"); + } + else 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; + } #else /* !KLIPS */ - return TRUE; + return TRUE; #endif /* !KLIPS */ } -bool -install_ipsec_sa(struct state *st, bool inbound_also USED_BY_KLIPS) +bool install_ipsec_sa(struct state *st, bool inbound_also USED_BY_KLIPS) { #ifdef KLIPS - 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; + struct spd_route *sr; - default: - return FALSE; - } + DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() for #%ld: %s" + , st->st_serialno + , inbound_also? + "inbound and outbound" : "outbound only")); - /* (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; + switch (could_route(st->st_connection)) + { + case route_easy: + case route_nearconflict: + break; - 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))); + default: + return FALSE; + } - /* - * 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); + /* (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; - if (sr->eroute_owner != st->st_serialno - && sr->routing != RT_UNROUTED_KEYED) + for (sr = &st->st_connection->spd; sr != NULL; sr = sr->next) { - 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. + 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 */ - return FALSE; - } + 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; + } + } } - } #else /* !KLIPS */ - DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() %s" - , inbound_also? "inbound and oubound" : "outbound only")); + DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() %s" + , inbound_also? "inbound and oubound" : "outbound only")); - switch (could_route(st->st_connection)) - { - case route_easy: - case route_nearconflict: - break; + switch (could_route(st->st_connection)) + { + case route_easy: + case route_nearconflict: + break; - default: - return FALSE; - } + default: + return FALSE; + } #endif /* !KLIPS */ - return TRUE; + 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 USED_BY_KLIPS, bool inbound_only USED_BY_KLIPS) +void delete_ipsec_sa(struct state *st USED_BY_KLIPS, + bool inbound_only USED_BY_KLIPS) { #ifdef KLIPS - if (!inbound_only) - { - /* If the state is the eroute owner, we must adjust - * the routing for the connection. - */ - struct connection *c = st->st_connection; - struct spd_route *sr; - - passert(st->st_connection); - - for (sr = &c->spd; sr; sr = sr->next) + if (!inbound_only) { - 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. + /* If the state is the eroute owner, we must adjust + * the routing for the connection. */ - sr->routing = (c->policy & POLICY_FAIL_MASK) == POLICY_FAIL_NONE - ? RT_ROUTED_PROSPECTIVE : RT_ROUTED_FAILURE; + struct connection *c = st->st_connection; + struct spd_route *sr; - (void) do_command(c, sr, "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 + passert(st->st_connection); + + for (sr = &c->spd; sr; sr = sr->next) { - (void) shunt_eroute(c, sr, sr->routing, ERO_REPLACE, "replace with shunt"); + 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, "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, FALSE); - } - (void) teardown_half_ipsec_sa(st, TRUE); + (void) teardown_half_ipsec_sa(st, TRUE); #else /* !KLIPS */ - DBG(DBG_CONTROL, DBG_log("if I knew how, I'd eroute() and teardown_ipsec_sa()")); + DBG(DBG_CONTROL, DBG_log("if I knew how, I'd eroute() and teardown_ipsec_sa()")); #endif /* !KLIPS */ } #ifdef KLIPS static bool update_nat_t_ipsec_esp_sa (struct state *st, bool inbound) { - struct connection *c = st->st_connection; - char text_said[SATOT_BUF]; - struct kernel_sa sa; - ip_address - src = inbound? c->spd.that.host_addr : c->spd.this.host_addr, - dst = inbound? c->spd.this.host_addr : c->spd.that.host_addr; - - ipsec_spi_t esp_spi = inbound? st->st_esp.our_spi : st->st_esp.attrs.spi; - - u_int16_t - natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port, - natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port; - - set_text_said(text_said, &dst, esp_spi, SA_ESP); - - memset(&sa, 0, sizeof(sa)); - sa.spi = esp_spi; - sa.src = &src; - sa.dst = &dst; - sa.text_said = text_said; - sa.authalg = alg_info_esp_aa2sadb(st->st_esp.attrs.auth); - sa.natt_sport = natt_sport; - sa.natt_dport = natt_dport; - sa.transid = st->st_esp.attrs.transid; - - return kernel_ops->add_sa(&sa, TRUE); + struct connection *c = st->st_connection; + char text_said[SATOT_BUF]; + struct kernel_sa sa; + ip_address + src = inbound? c->spd.that.host_addr : c->spd.this.host_addr, + dst = inbound? c->spd.this.host_addr : c->spd.that.host_addr; + + ipsec_spi_t esp_spi = inbound? st->st_esp.our_spi : st->st_esp.attrs.spi; + + u_int16_t + natt_sport = inbound? c->spd.that.host_port : c->spd.this.host_port, + natt_dport = inbound? c->spd.this.host_port : c->spd.that.host_port; + + set_text_said(text_said, &dst, esp_spi, SA_ESP); + + memset(&sa, 0, sizeof(sa)); + sa.spi = esp_spi; + sa.src = &src; + sa.dst = &dst; + sa.text_said = text_said; + sa.authalg = alg_info_esp_aa2sadb(st->st_esp.attrs.auth); + sa.natt_sport = natt_sport; + sa.natt_dport = natt_dport; + sa.transid = st->st_esp.attrs.transid; + + return kernel_ops->add_sa(&sa, TRUE); } #endif bool update_ipsec_sa (struct state *st USED_BY_KLIPS) { #ifdef KLIPS - 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)))) + if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) { - return FALSE; + 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)) + else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) { - return FALSE; + 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; + else + { + DBG_log("assert failed at %s:%d st_state=%d", __FILE__, __LINE__, st->st_state); + return FALSE; + } + return TRUE; #else /* !KLIPS */ - DBG(DBG_CONTROL, DBG_log("if I knew how, I'd update_ipsec_sa()")); - return TRUE; + DBG(DBG_CONTROL, DBG_log("if I knew how, I'd update_ipsec_sa()")); + return TRUE; #endif /* !KLIPS */ } @@ -2890,106 +2872,105 @@ bool update_ipsec_sa (struct state *st USED_BY_KLIPS) * 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) +bool was_eroute_idle(struct state *st, time_t idle_max, time_t *idle_time) { - static const char procname[] = "/proc/net/ipsec_spi"; - FILE *f; - char buf[1024]; - u_int bytes; - int ret = TRUE; - - passert(st != NULL); - - f = fopen(procname, "r"); - if (f == NULL) - { - /* Can't open the file, perhaps were are on 26sec? */ - time_t use_time; - - if (get_sa_info(st, TRUE, &bytes, &use_time) - && use_time != UNDEFINED_TIME) - { - *idle_time = time(NULL) - use_time; - ret = *idle_time >= idle_max; - } - } - else - { - while (f != NULL) - { - char *line; - char text_said[SATOT_BUF]; - u_int8_t proto = 0; - ip_address dst; - ip_said said; - ipsec_spi_t spi = 0; - static const char idle[] = "idle="; - - dst = st->st_connection->spd.this.host_addr; /* inbound SA */ - if (st->st_ah.present) - { - proto = SA_AH; - spi = st->st_ah.our_spi; - } - if (st->st_esp.present) - { - proto = SA_ESP; - spi = st->st_esp.our_spi; - } - - if (proto == 0 && spi == 0) - { - ret = TRUE; - break; - } - - initsaid(&dst, spi, proto, &said); - satot(&said, 'x', text_said, SATOT_BUF); + static const char procname[] = "/proc/net/ipsec_spi"; + FILE *f; + char buf[1024]; + u_int bytes; + int ret = TRUE; - line = fgets(buf, sizeof(buf), f); - if (line == NULL) - { - /* Reached end of list */ - ret = TRUE; - break; - } + passert(st != NULL); - if (strncmp(line, text_said, strlen(text_said)) == 0) - { - /* we found a match, now try to find idle= */ - char *p = strstr(line, idle); + f = fopen(procname, "r"); + if (f == NULL) + { + /* Can't open the file, perhaps were are on 26sec? */ + time_t use_time; - if (p == NULL) + if (get_sa_info(st, TRUE, &bytes, &use_time) + && use_time != UNDEFINED_TIME) { - /* SAs which haven't been used yet don't have it */ - ret = TRUE; /* it didn't have traffic */ - break; + *idle_time = time(NULL) - use_time; + ret = *idle_time >= idle_max; } - p += sizeof(idle)-1; - if (*p == '\0') - { - ret = TRUE; /* be paranoid */ - break; - } - if (sscanf(p, "%d", (int *) idle_time) <= 0) - { - ret = TRUE; - break; - } - if (*idle_time >= idle_max) - { - ret = TRUE; - break; - } - else + } + else + { + while (f != NULL) { - ret = FALSE; - break; + char *line; + char text_said[SATOT_BUF]; + u_int8_t proto = 0; + ip_address dst; + ip_said said; + ipsec_spi_t spi = 0; + static const char idle[] = "idle="; + + dst = st->st_connection->spd.this.host_addr; /* inbound SA */ + if (st->st_ah.present) + { + proto = SA_AH; + spi = st->st_ah.our_spi; + } + if (st->st_esp.present) + { + proto = SA_ESP; + spi = st->st_esp.our_spi; + } + + if (proto == 0 && spi == 0) + { + ret = TRUE; + break; + } + + initsaid(&dst, spi, proto, &said); + satot(&said, 'x', text_said, SATOT_BUF); + + line = fgets(buf, sizeof(buf), f); + if (line == NULL) + { + /* Reached end of list */ + ret = TRUE; + break; + } + + if (strneq(line, text_said, strlen(text_said))) + { + /* we found a match, now try to find idle= */ + char *p = strstr(line, idle); + + if (p == NULL) + { + /* SAs which haven't been used yet don't have it */ + ret = TRUE; /* it didn't have traffic */ + break; + } + p += sizeof(idle)-1; + if (*p == '\0') + { + ret = TRUE; /* be paranoid */ + break; + } + if (sscanf(p, "%d", (int *) idle_time) <= 0) + { + ret = TRUE; + break; + } + if (*idle_time >= idle_max) + { + ret = TRUE; + break; + } + else + { + ret = FALSE; + break; + } + } } - } + fclose(f); } - fclose(f); - } - return ret; + return ret; } diff --git a/src/pluto/kernel.h b/src/pluto/kernel.h index fdc2bf0a8..06850abfd 100644 --- a/src/pluto/kernel.h +++ b/src/pluto/kernel.h @@ -10,13 +10,11 @@ * 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. - * - * RCSID $Id: kernel.h 3252 2007-10-06 21:24:50Z andreas $ */ #include "connections.h" -extern bool no_klips; /* don't actually use KLIPS */ +extern bool no_klips; /* don't actually use KLIPS */ extern bool can_do_IPcomp; /* can system actually perform IPCOMP? */ #ifdef KLIPS @@ -28,96 +26,96 @@ extern bool can_do_IPcomp; /* can system actually perform IPCOMP? */ * limited to appropriate source and destination addresses. */ -#define ERO_MASK 0xFF -#define ERO_FLAG_SHIFT 8 +#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)) -#define ERO_ADD_INBOUND (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) -#define ERO_DEL_INBOUND (SADB_X_DELFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) +#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)) +#define ERO_ADD_INBOUND (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) +#define ERO_DEL_INBOUND (SADB_X_DELFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) struct pfkey_proto_info { - int proto; - int encapsulation; - unsigned reqid; + int proto; + int encapsulation; + unsigned reqid; }; struct sadb_msg; struct kernel_sa { - const ip_address *src; - const ip_address *dst; + const ip_address *src; + const ip_address *dst; - const ip_subnet *src_client; - const ip_subnet *dst_client; + 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; + ipsec_spi_t spi; + unsigned proto; + unsigned satype; + unsigned transport_proto; + unsigned replay_window; + unsigned reqid; - unsigned authalg; - unsigned authkeylen; - char *authkey; + unsigned authalg; + unsigned authkeylen; + char *authkey; - unsigned encalg; - unsigned enckeylen; - char *enckey; + unsigned encalg; + unsigned enckeylen; + char *enckey; - unsigned compalg; + unsigned compalg; - int encapsulation; + int encapsulation; - u_int16_t natt_sport, natt_dport; - u_int8_t transid, natt_type; - ip_address *natt_oa; + u_int16_t natt_sport, natt_dport; + u_int8_t transid, natt_type; + ip_address *natt_oa; - const char *text_said; + const char *text_said; }; struct kernel_ops { - enum { - KERNEL_TYPE_NONE, - KERNEL_TYPE_KLIPS, - KERNEL_TYPE_LINUX, - } type; - bool inbound_eroute; - bool policy_lifetime; - int *async_fdp; - - void (*init)(void); - void (*pfkey_register)(void); - void (*pfkey_register_response)(const struct sadb_msg *msg); - void (*process_queue)(void); - void (*process_msg)(void); - bool (*raw_eroute)(const ip_address *this_host, - const ip_subnet *this_client, - const ip_address *that_host, - const ip_subnet *that_client, - ipsec_spi_t spi, - unsigned int satype, - unsigned int transport_proto, - const struct pfkey_proto_info *proto_info, - time_t use_lifetime, - unsigned int op, - const char *text_said); - bool (*get_policy)(const struct kernel_sa *sa, bool inbound, - time_t *use_time); - bool (*add_sa)(const struct kernel_sa *sa, bool replace); - bool (*grp_sa)(const struct kernel_sa *sa_outer, - const struct kernel_sa *sa_inner); - bool (*del_sa)(const struct kernel_sa *sa); - bool (*get_sa)(const struct kernel_sa *sa, u_int *bytes); - ipsec_spi_t (*get_spi)(const ip_address *src, - const ip_address *dst, - int proto, - bool tunnel_mode, - unsigned reqid, - ipsec_spi_t min, - ipsec_spi_t max, - const char *text_said); + enum { + KERNEL_TYPE_NONE, + KERNEL_TYPE_KLIPS, + KERNEL_TYPE_LINUX, + } type; + bool inbound_eroute; + bool policy_lifetime; + int *async_fdp; + + void (*init)(void); + void (*pfkey_register)(void); + void (*pfkey_register_response)(const struct sadb_msg *msg); + void (*process_queue)(void); + void (*process_msg)(void); + bool (*raw_eroute)(const ip_address *this_host, + const ip_subnet *this_client, + const ip_address *that_host, + const ip_subnet *that_client, + ipsec_spi_t spi, + unsigned int satype, + unsigned int transport_proto, + const struct pfkey_proto_info *proto_info, + time_t use_lifetime, + unsigned int op, + const char *text_said); + bool (*get_policy)(const struct kernel_sa *sa, bool inbound, + time_t *use_time); + bool (*add_sa)(const struct kernel_sa *sa, bool replace); + bool (*grp_sa)(const struct kernel_sa *sa_outer, + const struct kernel_sa *sa_inner); + bool (*del_sa)(const struct kernel_sa *sa); + bool (*get_sa)(const struct kernel_sa *sa, u_int *bytes); + ipsec_spi_t (*get_spi)(const ip_address *src, + const ip_address *dst, + int proto, + bool tunnel_mode, + unsigned reqid, + ipsec_spi_t min, + ipsec_spi_t max, + const char *text_said); }; @@ -126,13 +124,13 @@ extern const struct kernel_ops *kernel_ops; /* information from /proc/net/ipsec_eroute */ struct eroute_info { - unsigned long count; - ip_subnet ours; - ip_subnet his; - ip_address dst; - ip_said said; - int transport_proto; - struct eroute_info *next; + unsigned long count; + ip_subnet ours; + ip_subnet his; + ip_address dst; + ip_said said; + int transport_proto; + struct eroute_info *next; }; extern struct eroute_info *orphaned_holds; @@ -144,13 +142,13 @@ extern void show_shunt_status(void); * Is there a PF_KEY equivalent? */ #ifndef EM_MAXRELSPIS -# define EM_MAXRELSPIS 4 /* AH ESP IPCOMP IPIP */ +# 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); + , const ip_subnet * + , int transport_proto + , const char *why); extern void init_kernel(void); @@ -160,39 +158,39 @@ extern bool trap_connection(struct connection *c); extern void unroute_connection(struct connection *c); extern bool has_bare_hold(const ip_address *src, const ip_address *dst - , int transport_proto); + , int transport_proto); extern bool replace_bare_shunt(const ip_address *src, const ip_address *dst - , policy_prio_t policy_prio - , ipsec_spi_t shunt_spi /* in host order! */ - , bool repl - , unsigned int transport_proto - , const char *why); + , policy_prio_t policy_prio + , ipsec_spi_t shunt_spi /* in host order! */ + , bool repl + , unsigned int transport_proto + , const char *why); extern bool assign_hold(struct connection *c - , struct spd_route *sr - , int transport_proto - , const ip_address *src, const ip_address *dst); + , 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 */ +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); + , 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); + , struct spd_route *sr + , struct state *st); extern bool was_eroute_idle(struct state *st, time_t idle_max - , time_t *idle_time); + , time_t *idle_time); extern bool get_sa_info(struct state *st, bool inbound, u_int *bytes - , time_t *use_time); + , 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 index 571d9cc9b..1590bdf02 100644 --- a/src/pluto/kernel_alg.c +++ b/src/pluto/kernel_alg.c @@ -1,5 +1,6 @@ /* Kernel runtime algorithm handling interface - * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> + * 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 @@ -10,8 +11,6 @@ * 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. - * - * RCSID $Id: kernel_alg.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdio.h> @@ -27,7 +26,6 @@ #include <pfkey.h> #include <freeswan.h> -#include <ipsec_policy.h> #include "constants.h" #include "defs.h" @@ -38,22 +36,10 @@ #include "kernel.h" #include "kernel_alg.h" #include "alg_info.h" - -#ifndef NO_PLUTO #include "log.h" #include "whack.h" #include "db_ops.h" -#else -/* - * macros/functions for compilation without pluto (eg: spi for manual conns) - */ -extern int debug; -#include <assert.h> -#define passert(x) assert(x) -#define DBG(cond, action) { if (debug) { action ; } } -#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args); -#define plog(x, args...) fprintf(stderr, x "\n" , ##args); -#endif /* NO_PLUTO */ + /* ALG storage */ static struct sadb_alg esp_aalg[SADB_AALG_MAX+1]; static struct sadb_alg esp_ealg[SADB_EALG_MAX+1]; @@ -62,714 +48,669 @@ 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)) + 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)) + 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) +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) + struct sadb_alg *alg_p = NULL; + + switch (exttype) { - (exttype == SADB_EXT_SUPPORTED_ENCRYPT)? - esp_ealg_num++ : esp_aalg_num++; + 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; } - break; - case SADB_SATYPE_AH: - default: - return NULL; - } - - return alg_p; + + 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) +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); + return sadb_alg_ptr(satype, exttype, alg_id, 0); } /* - * Forget previous registration + * Forget previous registration */ -static void -kernel_alg_init(void) +static void kernel_alg_init(void) { - DBG(DBG_KLIPS, - 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; + DBG(DBG_KLIPS, + 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) +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_KLIPS, - 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) - { + struct sadb_alg *alg_p = NULL; + int alg_id = sadb_alg->sadb_alg_id; + DBG(DBG_KLIPS, - DBG_log("kernel_alg_add(): discarding already setup " - "satype=%d, exttype=%d, alg_id=%d", - satype, exttype, sadb_alg->sadb_alg_id) + DBG_log("kernel_alg_add(): satype=%d, exttype=%d, alg_id=%d", + satype, exttype, sadb_alg->sadb_alg_id) ) - return 0; - } - *alg_p = *sadb_alg; - return 1; + 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_KLIPS, + 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))) +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; - } + 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_KLIPS, - 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_KLIPS, - DBG_log("kernel_alg_esp_enc_ok(%d,%d): NO", alg_id, key_len); - ) - } - return ret; + if (ret) + { + DBG(DBG_KLIPS, + 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_KLIPS, + 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 */ -#ifndef NO_PLUTO -bool -kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struct alg_info_esp *alg_info) +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 algoritms (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; + int ealg_insecure; - if (alg_info) + /* + * key_len passed comes from esp_attrs read from peer + * For many older algoritms (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)) { - 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) + int i; + struct esp_info *esp_info; + + if (alg_info) { - if (ealg_insecure) - { - loglog(RC_LOG_SERIOUS - , "You should NOT use insecure ESP algorithms [%s (%d)]!" - , enum_name(&esp_transformid_names, ealg), key_len); - } - return TRUE; + 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_transformid_names, ealg), key_len); + } + return TRUE; + } + } } - } + plog("IPSec Transform [%s (%d), %s] refused due to %s", + enum_name(&esp_transformid_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; } - plog("IPSec Transform [%s (%d), %s] refused due to %s", - enum_name(&esp_transformid_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; + return TRUE; } -#endif /* NO_PLUTO */ -/* - * Load kernel_alg arrays from /proc - * used in manual mode from klips/utils/spi.c +/** + * Load kernel_alg arrays from /proc used in manual mode from klips/utils/spi.c */ -int -kernel_alg_proc_read(void) +int kernel_alg_proc_read(void) { - int satype; - int supp_exttype; - int alg_id, ivlen, minbits, maxbits; - struct sadb_alg sadb_alg; - int ret; - char buf[128]; + int satype; + int supp_exttype; + int alg_id, ivlen, minbits, maxbits; + struct sadb_alg sadb_alg; + int ret; + char buf[128]; - FILE *fp=fopen("/proc/net/pf_key_supported", "r"); + FILE *fp=fopen("/proc/net/pf_key_supported", "r"); - if (!fp) - return -1; + if (!fp) + return -1; - kernel_alg_init(); + kernel_alg_init(); - while (fgets(buf, sizeof(buf), fp)) - { - if (buf[0] != ' ') /* skip titles */ - continue; + while (fgets(buf, sizeof(buf), fp)) + { + if (buf[0] != ' ') /* skip titles */ + continue; - sscanf(buf, "%d %d %d %d %d %d" - ,&satype, &supp_exttype - , &alg_id, &ivlen - , &minbits, &maxbits); + sscanf(buf, "%d %d %d %d %d %d" + ,&satype, &supp_exttype + , &alg_id, &ivlen + , &minbits, &maxbits); - switch (satype) - { - case SADB_SATYPE_ESP: - switch(supp_exttype) - { - case SADB_EXT_SUPPORTED_AUTH: - case SADB_EXT_SUPPORTED_ENCRYPT: - sadb_alg.sadb_alg_id = alg_id; - sadb_alg.sadb_alg_ivlen = ivlen; - sadb_alg.sadb_alg_minbits = minbits; - sadb_alg.sadb_alg_maxbits = maxbits; - ret = kernel_alg_add(satype, supp_exttype, &sadb_alg); - DBG(DBG_CRYPT, - DBG_log("kernel_alg_proc_read() alg_id=%d, " - "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " - "ret=%d" - , sadb_alg.sadb_alg_id - , sadb_alg.sadb_alg_ivlen - , sadb_alg.sadb_alg_minbits - , sadb_alg.sadb_alg_maxbits - , ret) - ) - } - default: - continue; + switch (satype) + { + case SADB_SATYPE_ESP: + switch(supp_exttype) + { + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + sadb_alg.sadb_alg_id = alg_id; + sadb_alg.sadb_alg_ivlen = ivlen; + sadb_alg.sadb_alg_minbits = minbits; + sadb_alg.sadb_alg_maxbits = maxbits; + ret = kernel_alg_add(satype, supp_exttype, &sadb_alg); + DBG(DBG_CRYPT, + DBG_log("kernel_alg_proc_read() alg_id=%d, " + "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " + "ret=%d" + , sadb_alg.sadb_alg_id + , sadb_alg.sadb_alg_ivlen + , sadb_alg.sadb_alg_minbits + , sadb_alg.sadb_alg_maxbits + , ret) + ) + } + default: + continue; + } } - } - fclose(fp); - return 0; + fclose(fp); + return 0; } -/* - * Load kernel_alg arrays pluto's SADB_REGISTER - * user by pluto/kernel.c +/** + * 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) +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_KLIPS, - 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++) + /* 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 ret = kernel_alg_add(satype, supp_exttype, sadb.alg); - - DBG(DBG_KLIPS, - 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, ret=%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 - , ret) - ) + int supp_exttype = sadb.supported->sadb_supported_exttype; + int supp_len = sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN; + + DBG(DBG_KLIPS, + 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++) + { + int ret = kernel_alg_add(satype, supp_exttype, sadb.alg); + + DBG(DBG_KLIPS, + 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, ret=%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 + , ret) + ) + } } - } } -u_int -kernel_alg_esp_enc_keylen(u_int alg_id) +u_int kernel_alg_esp_enc_keylen(u_int alg_id) { - u_int keylen = 0; + u_int keylen = 0; - if (!ESP_EALG_PRESENT(alg_id)) - goto none; + if (!ESP_EALG_PRESENT(alg_id)) + goto none; - keylen = esp_ealg[alg_id].sadb_alg_maxbits/BITS_PER_BYTE; + 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_KLIPS, - DBG_log("kernel_alg_esp_enc_keylen():" - "alg_id=%d, keylen=%d", - alg_id, keylen) - ) - return keylen; + 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_KLIPS, + 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* 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_KLIPS, - DBG_log("kernel_alg_esp_sadb_alg(): alg_id=%d, sadb_alg=%p" - , alg_id, sadb_alg) - ) - return sadb_alg; + struct sadb_alg *sadb_alg = (ESP_EALG_PRESENT(alg_id)) + ? &esp_ealg[alg_id] : NULL; + + DBG(DBG_KLIPS, + DBG_log("kernel_alg_esp_sadb_alg(): alg_id=%d, sadb_alg=%p" + , alg_id, sadb_alg) + ) + return sadb_alg; } -#ifndef NO_PLUTO void kernel_alg_list(void) { - u_int sadb_id; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of registered ESP Encryption Algorithms:"); - whack_log(RC_COMMENT, " "); - - for (sadb_id = 1; sadb_id <= SADB_EALG_MAX; sadb_id++) - { - if (ESP_EALG_PRESENT(sadb_id)) + char buf[BUF_LEN]; + char *pos; + int n, len; + u_int sadb_id; + + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of registered ESP Algorithms:"); + whack_log(RC_COMMENT, " "); + + pos = buf; + *pos = '\0'; + len = BUF_LEN; + for (sadb_id = 1; sadb_id <= SADB_EALG_MAX; sadb_id++) { - struct sadb_alg *alg_p = &esp_ealg[sadb_id]; - - whack_log(RC_COMMENT, "#%-5d %s, blocksize: %d, keylen: %d-%d" - , sadb_id - , enum_name(&esp_transformid_names, sadb_id) - , alg_p->sadb_alg_ivlen - , alg_p->sadb_alg_minbits - , alg_p->sadb_alg_maxbits - ); + if (ESP_EALG_PRESENT(sadb_id)) + { + n = snprintf(pos, len, " %s", + enum_name(&esp_transformid_names, sadb_id)); + pos += n; + len -= n; + if (len <= 0) + { + break; + } + } } - } - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of registered ESP Authentication Algorithms:"); - whack_log(RC_COMMENT, " "); - - for (sadb_id = 1; sadb_id <= SADB_AALG_MAX; sadb_id++) - { - if (ESP_AALG_PRESENT(sadb_id)) + whack_log(RC_COMMENT, " encryption:%s", buf); + + pos = buf; + *pos = '\0'; + len = BUF_LEN; + for (sadb_id = 1; sadb_id <= SADB_AALG_MAX; sadb_id++) { - u_int aaid = alg_info_esp_sadb2aa(sadb_id); - struct sadb_alg *alg_p = &esp_aalg[sadb_id]; - - whack_log(RC_COMMENT, "#%-5d %s, keylen: %d-%d" - , aaid - , enum_name(&auth_alg_names, aaid) - , alg_p->sadb_alg_minbits - , alg_p->sadb_alg_maxbits - ); + if (ESP_AALG_PRESENT(sadb_id)) + { + u_int aaid = alg_info_esp_sadb2aa(sadb_id); + + n = snprintf(pos, len, " %s", enum_name(&auth_alg_names, aaid)); + pos += n; + len -= n; + if (len <= 0) + { + break; + } + } } - } + whack_log(RC_COMMENT, " integrity: %s", buf); } -void -kernel_alg_show_connection(struct connection *c, const char *instance) +void kernel_alg_show_connection(struct connection *c, const char *instance) { - char buf[256]; - struct state *st; - - if (c->alg_info_esp) - { - alg_info_snprint(buf, sizeof(buf), (struct alg_info *)c->alg_info_esp); - whack_log(RC_COMMENT - , "\"%s\"%s: ESP algorithms wanted: %s" - , c->name - , instance - , buf); - } - if (c->alg_info_esp) - { - alg_info_snprint_esp(buf, sizeof(buf), c->alg_info_esp); - whack_log(RC_COMMENT - , "\"%s\"%s: ESP algorithms loaded: %s" - , c->name - , instance - , buf); - } - st = state_with_serialno(c->newest_ipsec_sa); - if (st && st->st_esp.present) - whack_log(RC_COMMENT - , "\"%s\"%s: ESP algorithm newest: %s_%d-%s; pfsgroup=%s" - , c->name - , instance - , enum_show(&esp_transformid_names, st->st_esp.attrs.transid) - +4 /* strlen("ESP_") */ - , st->st_esp.attrs.key_len - , enum_show(&auth_alg_names, st->st_esp.attrs.auth)+ - +15 /* strlen("AUTH_ALGORITHM_") */ - , c->policy & POLICY_PFS ? - c->alg_info_esp->esp_pfsgroup ? - enum_show(&oakley_group_names, - c->alg_info_esp->esp_pfsgroup) - +13 /*strlen("OAKLEY_GROUP_")*/ - : "<Phase1>" - : "<N/A>" - ); + 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_transformid_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->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_transformid_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_transformid_names, st->st_esp.attrs.transid), + aalg_name, pfsgroup_name); + } + } } -#endif /* NO_PLUTO */ -bool -kernel_alg_esp_auth_ok(u_int auth, - struct alg_info_esp *alg_info __attribute__((unused))) +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)); + return ESP_AALG_PRESENT(alg_info_esp_aa2sadb(auth)); } -u_int -kernel_alg_esp_auth_keylen(u_int auth) +u_int kernel_alg_esp_auth_keylen(u_int auth) { - u_int sadb_aalg = alg_info_esp_aa2sadb(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; + 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; + 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) +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; + 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; + DBG(DBG_PARSING, + DBG_log("kernel_alg_esp_info():" + "transid=%d, auth=%d, ei=NULL", + transid, auth) + ) + return NULL; } -#ifndef NO_PLUTO -static void -kernel_alg_policy_algorithms(struct esp_info *esp_info) +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) + u_int ealg_id = esp_info->esp_ealg_id; + + switch(ealg_id) { - /* 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; + 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) +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; + u_int ealg_id, aalg_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 */ - { - aalg_id = alg_info_esp_aa2sadb(esp_info->esp_aalg_id); + ealg_id = esp_info->esp_ealg_id; - if (!ESP_AALG_PRESENT(aalg_id)) + if (!ESP_EALG_PRESENT(ealg_id)) { - DBG_log("kernel_alg_db_add() kernel auth " - "aalg_id=%d not present", aalg_id); - return FALSE; + 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 */ + { + aalg_id = alg_info_esp_aa2sadb(esp_info->esp_aalg_id); - /* do algo policy */ - kernel_alg_policy_algorithms(esp_info); + if (!ESP_AALG_PRESENT(aalg_id)) + { + DBG_log("kernel_alg_db_add() kernel auth " + "aalg_id=%d not present", aalg_id); + return FALSE; + } + } - /* open new transformation */ - db_trans_add(db_ctx, ealg_id); + /* do algo policy */ + kernel_alg_policy_algorithms(esp_info); - /* add ESP auth attr */ - if (!(policy & POLICY_AUTHENTICATE)) - db_attr_add_values(db_ctx, AUTH_ALGORITHM, esp_info->esp_aalg_id); + /* open new transformation */ + db_trans_add(db_ctx, ealg_id); - /* add keylegth 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; + /* add ESP auth attr */ + if (!(policy & POLICY_AUTHENTICATE)) + db_attr_add_values(db_ctx, AUTH_ALGORITHM, esp_info->esp_aalg_id); + + /* add keylegth 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 +/* + * 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) + * 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 ) +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; - struct db_trans *t; - struct db_prop *prop; - u_int trans_cnt; - int tn = 0; - - if (!(policy & POLICY_ENCRYPT)) /* not possible, I think */ - return NULL; + const struct esp_info *esp_info; + struct esp_info tmp_esp_info; + struct db_context *ctx_new = NULL; + struct db_prop *prop; + u_int trans_cnt = esp_ealg_num * esp_aalg_num; - trans_cnt = esp_ealg_num * esp_aalg_num; - DBG(DBG_EMITTING, - DBG_log("kernel_alg_db_prop_new() initial trans_cnt=%d" - , trans_cnt) - ) - - /* pass aprox. number of transforms and attributes */ - ctx_new = db_prop_new(PROTO_IPSEC_ESP, trans_cnt, trans_cnt * 2); + if (!(policy & POLICY_ENCRYPT)) /* not possible, I think */ + { + return NULL; + } - /* - * Loop: for each element (struct esp_info) of alg_info, - * if kernel support is present then build the transform (and attrs) - * if NULL alg_info, propose everything ... - */ + /* 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; + /* + * Loop: for each element (struct esp_info) of alg_info, + * if kernel support is present then build the transform (and attrs) + * if NULL alg_info, propose everything ... + */ - ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) + if (alg_info) { - tmp_esp_info = *esp_info; - kernel_alg_db_add(ctx_new, &tmp_esp_info, policy); + 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); + } } - } - else - { - u_int ealg_id; - - ESP_EALG_FOR_EACH_UPDOWN(ealg_id) + else { - u_int aalg_id; - - tmp_esp_info.esp_ealg_id = ealg_id; - tmp_esp_info.esp_ealg_keylen = 0; - - for (aalg_id = 1; aalg_id <= SADB_AALG_MAX; aalg_id++) - { - if (ESP_AALG_PRESENT(aalg_id)) + u_int ealg_id; + + ESP_EALG_FOR_EACH_UPDOWN(ealg_id) { - tmp_esp_info.esp_aalg_id = alg_info_esp_sadb2aa(aalg_id); - tmp_esp_info.esp_aalg_keylen = 0; - kernel_alg_db_add(ctx_new, &tmp_esp_info, policy); + u_int aalg_id; + + tmp_esp_info.esp_ealg_id = ealg_id; + tmp_esp_info.esp_ealg_keylen = 0; + + for (aalg_id = 1; aalg_id <= SADB_AALG_MAX; aalg_id++) + { + if (ESP_AALG_PRESENT(aalg_id)) + { + tmp_esp_info.esp_aalg_id = alg_info_esp_sadb2aa(aalg_id); + tmp_esp_info.esp_aalg_keylen = 0; + kernel_alg_db_add(ctx_new, &tmp_esp_info, policy); + } + } } - } } - } - - prop = db_prop_get(ctx_new); - - DBG(DBG_CONTROL|DBG_EMITTING, - DBG_log("kernel_alg_db_prop_new() " - "will return p_new->protoid=%d, p_new->trans_cnt=%d" - , prop->protoid, prop->trans_cnt) - ) - - for (t = prop->trans, tn = 0; tn < prop->trans_cnt; tn++) - { - DBG(DBG_CONTROL|DBG_EMITTING, - DBG_log("kernel_alg_db_prop_new() " - " trans[%d]: transid=%d, attr_cnt=%d, " - "attrs[0].type=%d, attrs[0].val=%d" - , tn - , t[tn].transid, t[tn].attr_cnt - , t[tn].attrs[0].type, t[tn].attrs[0].val) - ) - } - return ctx_new; + prop = db_prop_get(ctx_new); + return ctx_new; } -#endif /* NO_PLUTO */ + diff --git a/src/pluto/kernel_alg.h b/src/pluto/kernel_alg.h index 14c2664aa..5ce8c3003 100644 --- a/src/pluto/kernel_alg.h +++ b/src/pluto/kernel_alg.h @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: kernel_alg.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _KERNEL_ALG_H diff --git a/src/pluto/kernel_netlink.c b/src/pluto/kernel_netlink.c index 4269de66e..b4b4774c7 100644 --- a/src/pluto/kernel_netlink.c +++ b/src/pluto/kernel_netlink.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: kernel_netlink.c 3850 2008-04-18 20:01:49Z andreas $ */ #if defined(linux) && defined(KERNEL26_SUPPORT) @@ -39,7 +37,7 @@ #include "kernel_netlink.h" #include "kernel_pfkey.h" #include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ +#include "whack.h" /* for RC_LOG_SERIOUS */ #include "kernel_alg.h" /* Minimum priority number in SPD used by pluto. */ @@ -48,72 +46,72 @@ static int netlinkfd = NULL_FD; static int netlink_bcast_fd = NULL_FD; -#define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */ +#define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */ static sparse_names xfrm_type_names = { - NE(NLMSG_NOOP), - NE(NLMSG_ERROR), - NE(NLMSG_DONE), - NE(NLMSG_OVERRUN), + NE(NLMSG_NOOP), + NE(NLMSG_ERROR), + NE(NLMSG_DONE), + NE(NLMSG_OVERRUN), - NE(XFRM_MSG_NEWSA), - NE(XFRM_MSG_DELSA), - NE(XFRM_MSG_GETSA), + NE(XFRM_MSG_NEWSA), + NE(XFRM_MSG_DELSA), + NE(XFRM_MSG_GETSA), - NE(XFRM_MSG_NEWPOLICY), - NE(XFRM_MSG_DELPOLICY), - NE(XFRM_MSG_GETPOLICY), + NE(XFRM_MSG_NEWPOLICY), + NE(XFRM_MSG_DELPOLICY), + NE(XFRM_MSG_GETPOLICY), - NE(XFRM_MSG_ALLOCSPI), - NE(XFRM_MSG_ACQUIRE), - NE(XFRM_MSG_EXPIRE), + NE(XFRM_MSG_ALLOCSPI), + NE(XFRM_MSG_ACQUIRE), + NE(XFRM_MSG_EXPIRE), - NE(XFRM_MSG_UPDPOLICY), - NE(XFRM_MSG_UPDSA), + NE(XFRM_MSG_UPDPOLICY), + NE(XFRM_MSG_UPDSA), - NE(XFRM_MSG_POLEXPIRE), + NE(XFRM_MSG_POLEXPIRE), - NE(XFRM_MSG_MAX), + NE(XFRM_MSG_MAX), - { 0, sparse_end } + { 0, sparse_end } }; #undef NE /* Authentication algorithms */ static sparse_names aalg_list = { - { SADB_X_AALG_NULL, "digest_null" }, - { SADB_AALG_MD5HMAC, "md5" }, - { SADB_AALG_SHA1HMAC, "sha1" }, - { SADB_X_AALG_SHA2_256HMAC, "sha256" }, - { SADB_X_AALG_SHA2_384HMAC, "sha384" }, - { SADB_X_AALG_SHA2_512HMAC, "sha512" }, - { SADB_X_AALG_RIPEMD160HMAC, "ripemd160" }, - { SADB_X_AALG_AES_XCBC_MAC, "xcbc(aes)"}, - { SADB_X_AALG_NULL, "null" }, - { 0, sparse_end } + { SADB_X_AALG_NULL, "digest_null" }, + { SADB_AALG_MD5HMAC, "md5" }, + { SADB_AALG_SHA1HMAC, "sha1" }, + { SADB_X_AALG_SHA2_256HMAC, "sha256" }, + { SADB_X_AALG_SHA2_384HMAC, "sha384" }, + { SADB_X_AALG_SHA2_512HMAC, "sha512" }, + { SADB_X_AALG_RIPEMD160HMAC, "ripemd160" }, + { SADB_X_AALG_AES_XCBC_MAC, "xcbc(aes)"}, + { SADB_X_AALG_NULL, "null" }, + { 0, sparse_end } }; /* Encryption algorithms */ static sparse_names ealg_list = { - { SADB_EALG_NULL, "cipher_null" }, - { SADB_EALG_DESCBC, "des" }, - { SADB_EALG_3DESCBC, "des3_ede" }, - { SADB_X_EALG_CASTCBC, "cast128" }, - { SADB_X_EALG_BLOWFISHCBC, "blowfish" }, - { SADB_X_EALG_AESCBC, "aes" }, - { SADB_X_EALG_CAMELLIACBC, "cbc(camellia)" }, - { SADB_X_EALG_SERPENTCBC, "serpent" }, - { SADB_X_EALG_TWOFISHCBC, "twofish" }, - { 0, sparse_end } + { SADB_EALG_NULL, "cipher_null" }, + { SADB_EALG_DESCBC, "des" }, + { SADB_EALG_3DESCBC, "des3_ede" }, + { SADB_X_EALG_CASTCBC, "cast128" }, + { SADB_X_EALG_BLOWFISHCBC, "blowfish" }, + { SADB_X_EALG_AESCBC, "aes" }, + { SADB_X_EALG_CAMELLIACBC, "cbc(camellia)" }, + { SADB_X_EALG_SERPENTCBC, "serpent" }, + { SADB_X_EALG_TWOFISHCBC, "twofish" }, + { 0, sparse_end } }; /* Compression algorithms */ static sparse_names calg_list = { - { SADB_X_CALG_DEFLATE, "deflate" }, - { SADB_X_CALG_LZS, "lzs" }, - { SADB_X_CALG_LZJH, "lzjh" }, - { 0, sparse_end } + { SADB_X_CALG_DEFLATE, "deflate" }, + { SADB_X_CALG_LZS, "lzs" }, + { SADB_X_CALG_LZJH, "lzjh" }, + { 0, sparse_end } }; /** ip2xfrm - Take an IP address and convert to an xfrm. @@ -124,14 +122,14 @@ static sparse_names calg_list = { static void ip2xfrm(const ip_address *addr, xfrm_address_t *xaddr) { - if (addr->u.v4.sin_family == AF_INET) - { - xaddr->a4 = addr->u.v4.sin_addr.s_addr; - } - else - { - memcpy(xaddr->a6, &addr->u.v6.sin6_addr, sizeof(xaddr->a6)); - } + if (addr->u.v4.sin_family == AF_INET) + { + xaddr->a4 = addr->u.v4.sin_addr.s_addr; + } + else + { + memcpy(xaddr->a6, &addr->u.v6.sin6_addr, sizeof(xaddr->a6)); + } } /** init_netlink - Initialize the netlink inferface. Opens the sockets and @@ -140,32 +138,32 @@ ip2xfrm(const ip_address *addr, xfrm_address_t *xaddr) static void init_netlink(void) { - struct sockaddr_nl addr; + struct sockaddr_nl addr; - netlinkfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM); + netlinkfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM); - if (netlinkfd < 0) - exit_log_errno((e, "socket() in init_netlink()")); + if (netlinkfd < 0) + exit_log_errno((e, "socket() in init_netlink()")); - if (fcntl(netlinkfd, F_SETFD, FD_CLOEXEC) != 0) - exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_netlink()")); + if (fcntl(netlinkfd, F_SETFD, FD_CLOEXEC) != 0) + exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_netlink()")); - netlink_bcast_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM); + netlink_bcast_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_XFRM); - if (netlink_bcast_fd < 0) - exit_log_errno((e, "socket() for bcast in init_netlink()")); + if (netlink_bcast_fd < 0) + exit_log_errno((e, "socket() for bcast in init_netlink()")); - if (fcntl(netlink_bcast_fd, F_SETFD, FD_CLOEXEC) != 0) - exit_log_errno((e, "fcntl(FD_CLOEXEC) for bcast in init_netlink()")); + if (fcntl(netlink_bcast_fd, F_SETFD, FD_CLOEXEC) != 0) + exit_log_errno((e, "fcntl(FD_CLOEXEC) for bcast in init_netlink()")); - if (fcntl(netlink_bcast_fd, F_SETFL, O_NONBLOCK) != 0) - exit_log_errno((e, "fcntl(O_NONBLOCK) for bcast in init_netlink()")); + if (fcntl(netlink_bcast_fd, F_SETFL, O_NONBLOCK) != 0) + exit_log_errno((e, "fcntl(O_NONBLOCK) for bcast in init_netlink()")); - addr.nl_family = AF_NETLINK; - addr.nl_pid = getpid(); - addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE; - if (bind(netlink_bcast_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) - exit_log_errno((e, "Failed to bind bcast socket in init_netlink()")); + addr.nl_family = AF_NETLINK; + addr.nl_pid = getpid(); + addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE; + if (bind(netlink_bcast_fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) + exit_log_errno((e, "Failed to bind bcast socket in init_netlink()")); } /** send_netlink_msg @@ -182,139 +180,139 @@ static bool send_netlink_msg(struct nlmsghdr *hdr, struct nlmsghdr *rbuf, size_t rbuf_len , const char *description, const char *text_said) { - struct { - struct nlmsghdr n; - struct nlmsgerr e; - char data[1024]; - } rsp; - - size_t len; - ssize_t r; - struct sockaddr_nl addr; - static uint32_t seq; - - if (no_klips) - { - return TRUE; - } - - hdr->nlmsg_seq = ++seq; - len = hdr->nlmsg_len; - do { - r = write(netlinkfd, hdr, len); - } while (r < 0 && errno == EINTR); - if (r < 0) - { - log_errno((e - , "netlink write() of %s message" - " for %s %s failed" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said)); - return FALSE; - } - else if ((size_t)r != len) - { - loglog(RC_LOG_SERIOUS - , "ERROR: netlink write() of %s message" - " for %s %s truncated: %ld instead of %lu" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said - , (long)r, (unsigned long)len); - return FALSE; - } - - for (;;) { - socklen_t alen; + struct { + struct nlmsghdr n; + struct nlmsgerr e; + char data[1024]; + } rsp; + + size_t len; + ssize_t r; + struct sockaddr_nl addr; + static uint32_t seq; + + if (no_klips) + { + return TRUE; + } - alen = sizeof(addr); - r = recvfrom(netlinkfd, &rsp, sizeof(rsp), 0 - , (struct sockaddr *)&addr, &alen); + hdr->nlmsg_seq = ++seq; + len = hdr->nlmsg_len; + do { + r = write(netlinkfd, hdr, len); + } while (r < 0 && errno == EINTR); if (r < 0) { - if (errno == EINTR) - { - continue; - } - log_errno((e - , "netlink recvfrom() of response to our %s message" - " for %s %s failed" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said)); - return FALSE; + log_errno((e + , "netlink write() of %s message" + " for %s %s failed" + , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) + , description, text_said)); + return FALSE; } - else if ((size_t) r < sizeof(rsp.n)) + else if ((size_t)r != len) { - plog("netlink read truncated message: %ld bytes; ignore message" - , (long) r); - continue; + loglog(RC_LOG_SERIOUS + , "ERROR: netlink write() of %s message" + " for %s %s truncated: %ld instead of %lu" + , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) + , description, text_said + , (long)r, (unsigned long)len); + return FALSE; } - else if (addr.nl_pid != 0) + + for (;;) { + socklen_t alen; + + alen = sizeof(addr); + r = recvfrom(netlinkfd, &rsp, sizeof(rsp), 0 + , (struct sockaddr *)&addr, &alen); + if (r < 0) + { + if (errno == EINTR) + { + continue; + } + log_errno((e + , "netlink recvfrom() of response to our %s message" + " for %s %s failed" + , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) + , description, text_said)); + return FALSE; + } + else if ((size_t) r < sizeof(rsp.n)) + { + plog("netlink read truncated message: %ld bytes; ignore message" + , (long) r); + continue; + } + else if (addr.nl_pid != 0) + { + /* not for us: ignore */ + DBG(DBG_KLIPS, + DBG_log("netlink: ignoring %s message from process %u" + , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type) + , addr.nl_pid)); + continue; + } + else if (rsp.n.nlmsg_seq != seq) + { + DBG(DBG_KLIPS, + DBG_log("netlink: ignoring out of sequence (%u/%u) message %s" + , rsp.n.nlmsg_seq, seq + , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type))); + continue; + } + break; + } + + if (rsp.n.nlmsg_len > (size_t) r) { - /* not for us: ignore */ - DBG(DBG_KLIPS, - DBG_log("netlink: ignoring %s message from process %u" - , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type) - , addr.nl_pid)); - continue; + loglog(RC_LOG_SERIOUS + , "netlink recvfrom() of response to our %s message" + " for %s %s was truncated: %ld instead of %lu" + , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) + , description, text_said + , (long) len, (unsigned long) rsp.n.nlmsg_len); + return FALSE; } - else if (rsp.n.nlmsg_seq != seq) + else if (rsp.n.nlmsg_type != NLMSG_ERROR + && (rbuf && rsp.n.nlmsg_type != rbuf->nlmsg_type)) { - DBG(DBG_KLIPS, - DBG_log("netlink: ignoring out of sequence (%u/%u) message %s" - , rsp.n.nlmsg_seq, seq - , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type))); - continue; + loglog(RC_LOG_SERIOUS + , "netlink recvfrom() of response to our %s message" + " for %s %s was of wrong type (%s)" + , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) + , description, text_said + , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)); + return FALSE; } - break; - } - - if (rsp.n.nlmsg_len > (size_t) r) - { - loglog(RC_LOG_SERIOUS - , "netlink recvfrom() of response to our %s message" - " for %s %s was truncated: %ld instead of %lu" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said - , (long) len, (unsigned long) rsp.n.nlmsg_len); - return FALSE; - } - else if (rsp.n.nlmsg_type != NLMSG_ERROR - && (rbuf && rsp.n.nlmsg_type != rbuf->nlmsg_type)) - { - loglog(RC_LOG_SERIOUS - , "netlink recvfrom() of response to our %s message" - " for %s %s was of wrong type (%s)" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said - , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)); - return FALSE; - } - else if (rbuf) - { - if ((size_t) r > rbuf_len) + else if (rbuf) { - loglog(RC_LOG_SERIOUS - , "netlink recvfrom() of response to our %s message" - " for %s %s was too long: %ld > %lu" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , description, text_said - , (long)r, (unsigned long)rbuf_len); - return FALSE; + if ((size_t) r > rbuf_len) + { + loglog(RC_LOG_SERIOUS + , "netlink recvfrom() of response to our %s message" + " for %s %s was too long: %ld > %lu" + , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) + , description, text_said + , (long)r, (unsigned long)rbuf_len); + return FALSE; + } + memcpy(rbuf, &rsp, r); + return TRUE; + } + else if (rsp.n.nlmsg_type == NLMSG_ERROR && rsp.e.error) + { + loglog(RC_LOG_SERIOUS + , "ERROR: netlink response for %s %s included errno %d: %s" + , description, text_said + , -rsp.e.error + , strerror(-rsp.e.error)); + return FALSE; } - memcpy(rbuf, &rsp, r); - return TRUE; - } - else if (rsp.n.nlmsg_type == NLMSG_ERROR && rsp.e.error) - { - loglog(RC_LOG_SERIOUS - , "ERROR: netlink response for %s %s included errno %d: %s" - , description, text_said - , -rsp.e.error - , strerror(-rsp.e.error)); - return FALSE; - } - return TRUE; + return TRUE; } /** netlink_policy - @@ -327,36 +325,36 @@ send_netlink_msg(struct nlmsghdr *hdr, struct nlmsghdr *rbuf, size_t rbuf_len static bool netlink_policy(struct nlmsghdr *hdr, bool enoent_ok, const char *text_said) { - struct { - struct nlmsghdr n; - struct nlmsgerr e; - } rsp; - int error; - - rsp.n.nlmsg_type = NLMSG_ERROR; - if (!send_netlink_msg(hdr, &rsp.n, sizeof(rsp), "policy", text_said)) - { - return FALSE; - } + struct { + struct nlmsghdr n; + struct nlmsgerr e; + } rsp; + int error; + + rsp.n.nlmsg_type = NLMSG_ERROR; + if (!send_netlink_msg(hdr, &rsp.n, sizeof(rsp), "policy", text_said)) + { + return FALSE; + } - error = -rsp.e.error; - if (!error) - { - return TRUE; - } + error = -rsp.e.error; + if (!error) + { + return TRUE; + } - if (error == ENOENT && enoent_ok) - { - return TRUE; - } - - loglog(RC_LOG_SERIOUS - , "ERROR: netlink %s response for flow %s included errno %d: %s" - , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) - , text_said - , error - , strerror(error)); - return FALSE; + if (error == ENOENT && enoent_ok) + { + return TRUE; + } + + loglog(RC_LOG_SERIOUS + , "ERROR: netlink %s response for flow %s included errno %d: %s" + , sparse_val_show(xfrm_type_names, hdr->nlmsg_type) + , text_said + , error + , strerror(error)); + return FALSE; } /** netlink_raw_eroute @@ -376,192 +374,192 @@ netlink_policy(struct nlmsghdr *hdr, bool enoent_ok, const char *text_said) */ static bool netlink_raw_eroute(const ip_address *this_host - , const ip_subnet *this_client - , const ip_address *that_host - , const ip_subnet *that_client - , ipsec_spi_t spi - , unsigned int satype - , unsigned int transport_proto - , const struct pfkey_proto_info *proto_info - , time_t use_lifetime UNUSED - , unsigned int op - , const char *text_said) + , const ip_subnet *this_client + , const ip_address *that_host + , const ip_subnet *that_client + , ipsec_spi_t spi + , unsigned int satype + , unsigned int transport_proto + , const struct pfkey_proto_info *proto_info + , time_t use_lifetime UNUSED + , unsigned int op + , const char *text_said) { - struct { - struct nlmsghdr n; - union { - struct xfrm_userpolicy_info p; - struct xfrm_userpolicy_id id; - } u; - char data[1024]; - } req; - int shift; - int dir; - int family; - int policy; - bool ok; - bool enoent_ok; - - policy = IPSEC_POLICY_IPSEC; - - if (satype == SADB_X_SATYPE_INT) - { - /* shunt route */ - switch (ntohl(spi)) + struct { + struct nlmsghdr n; + union { + struct xfrm_userpolicy_info p; + struct xfrm_userpolicy_id id; + } u; + char data[1024]; + } req; + int shift; + int dir; + int family; + int policy; + bool ok; + bool enoent_ok; + + policy = IPSEC_POLICY_IPSEC; + + if (satype == SADB_X_SATYPE_INT) { - case SPI_PASS: - policy = IPSEC_POLICY_NONE; - break; - case SPI_DROP: - case SPI_REJECT: - default: - policy = IPSEC_POLICY_DISCARD; - break; - case SPI_TRAP: - case SPI_TRAPSUBNET: - case SPI_HOLD: - if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) - { - return TRUE; - } - break; - } - } - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - - family = that_client->addr.u.v4.sin_family; - shift = (family == AF_INET) ? 5 : 7; - - req.u.p.sel.sport = portof(&this_client->addr); - req.u.p.sel.dport = portof(&that_client->addr); - req.u.p.sel.sport_mask = (req.u.p.sel.sport) ? ~0:0; - req.u.p.sel.dport_mask = (req.u.p.sel.dport) ? ~0:0; - ip2xfrm(&this_client->addr, &req.u.p.sel.saddr); - ip2xfrm(&that_client->addr, &req.u.p.sel.daddr); - req.u.p.sel.prefixlen_s = this_client->maskbits; - req.u.p.sel.prefixlen_d = that_client->maskbits; - req.u.p.sel.proto = transport_proto; - req.u.p.sel.family = family; - - dir = XFRM_POLICY_OUT; - if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) - { - dir = XFRM_POLICY_IN; - } - - if ((op & ERO_MASK) == ERO_DELETE) - { - req.u.id.dir = dir; - req.n.nlmsg_type = XFRM_MSG_DELPOLICY; - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.id))); - } - else - { - int src, dst; - - req.u.p.dir = dir; - - src = req.u.p.sel.prefixlen_s; - dst = req.u.p.sel.prefixlen_d; - if (dir != XFRM_POLICY_OUT) { - src = req.u.p.sel.prefixlen_d; - dst = req.u.p.sel.prefixlen_s; + /* shunt route */ + switch (ntohl(spi)) + { + case SPI_PASS: + policy = IPSEC_POLICY_NONE; + break; + case SPI_DROP: + case SPI_REJECT: + default: + policy = IPSEC_POLICY_DISCARD; + break; + case SPI_TRAP: + case SPI_TRAPSUBNET: + case SPI_HOLD: + if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) + { + return TRUE; + } + break; + } } - req.u.p.priority = MIN_SPD_PRIORITY - + (((2 << shift) - src) << shift) - + (2 << shift) - dst; - req.u.p.action = XFRM_POLICY_ALLOW; - if (policy == IPSEC_POLICY_DISCARD) + memset(&req, 0, sizeof(req)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + + family = that_client->addr.u.v4.sin_family; + shift = (family == AF_INET) ? 5 : 7; + + req.u.p.sel.sport = portof(&this_client->addr); + req.u.p.sel.dport = portof(&that_client->addr); + req.u.p.sel.sport_mask = (req.u.p.sel.sport) ? ~0:0; + req.u.p.sel.dport_mask = (req.u.p.sel.dport) ? ~0:0; + ip2xfrm(&this_client->addr, &req.u.p.sel.saddr); + ip2xfrm(&that_client->addr, &req.u.p.sel.daddr); + req.u.p.sel.prefixlen_s = this_client->maskbits; + req.u.p.sel.prefixlen_d = that_client->maskbits; + req.u.p.sel.proto = transport_proto; + req.u.p.sel.family = family; + + dir = XFRM_POLICY_OUT; + if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) { - req.u.p.action = XFRM_POLICY_BLOCK; + dir = XFRM_POLICY_IN; } - req.u.p.lft.soft_use_expires_seconds = use_lifetime; - req.u.p.lft.soft_byte_limit = XFRM_INF; - req.u.p.lft.soft_packet_limit = XFRM_INF; - req.u.p.lft.hard_byte_limit = XFRM_INF; - req.u.p.lft.hard_packet_limit = XFRM_INF; - - req.n.nlmsg_type = XFRM_MSG_NEWPOLICY; - if (op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT)) + + if ((op & ERO_MASK) == ERO_DELETE) { - req.n.nlmsg_type = XFRM_MSG_UPDPOLICY; + req.u.id.dir = dir; + req.n.nlmsg_type = XFRM_MSG_DELPOLICY; + req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.id))); } - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.p))); - } - - if (policy == IPSEC_POLICY_IPSEC && (op & ERO_MASK) != ERO_DELETE) - { - struct rtattr *attr; - struct xfrm_user_tmpl tmpl[4]; - int i; - - memset(tmpl, 0, sizeof(tmpl)); - for (i = 0; proto_info[i].proto; i++) + else { - tmpl[i].reqid = proto_info[i].reqid; - tmpl[i].id.proto = proto_info[i].proto; - tmpl[i].optional = - proto_info[i].proto == IPPROTO_COMP && dir != XFRM_POLICY_OUT; - tmpl[i].aalgos = tmpl[i].ealgos = tmpl[i].calgos = ~0; - tmpl[i].mode = - proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; - - if (!tmpl[i].mode) - { - continue; - } - - ip2xfrm(this_host, &tmpl[i].saddr); - ip2xfrm(that_host, &tmpl[i].id.daddr); + int src, dst; + + req.u.p.dir = dir; + + src = req.u.p.sel.prefixlen_s; + dst = req.u.p.sel.prefixlen_d; + if (dir != XFRM_POLICY_OUT) { + src = req.u.p.sel.prefixlen_d; + dst = req.u.p.sel.prefixlen_s; + } + req.u.p.priority = MIN_SPD_PRIORITY + + (((2 << shift) - src) << shift) + + (2 << shift) - dst; + + req.u.p.action = XFRM_POLICY_ALLOW; + if (policy == IPSEC_POLICY_DISCARD) + { + req.u.p.action = XFRM_POLICY_BLOCK; + } + req.u.p.lft.soft_use_expires_seconds = use_lifetime; + req.u.p.lft.soft_byte_limit = XFRM_INF; + req.u.p.lft.soft_packet_limit = XFRM_INF; + req.u.p.lft.hard_byte_limit = XFRM_INF; + req.u.p.lft.hard_packet_limit = XFRM_INF; + + req.n.nlmsg_type = XFRM_MSG_NEWPOLICY; + if (op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT)) + { + req.n.nlmsg_type = XFRM_MSG_UPDPOLICY; + } + req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.u.p))); } - attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); - attr->rta_type = XFRMA_TMPL; - attr->rta_len = i * sizeof(tmpl[0]); - memcpy(RTA_DATA(attr), tmpl, attr->rta_len); - attr->rta_len = RTA_LENGTH(attr->rta_len); - req.n.nlmsg_len += attr->rta_len; - } - - enoent_ok = FALSE; - if (op == ERO_DEL_INBOUND) - { - enoent_ok = TRUE; - } - else if (op == ERO_DELETE && ntohl(spi) == SPI_HOLD) - { - enoent_ok = TRUE; - } - - ok = netlink_policy(&req.n, enoent_ok, text_said); - switch (dir) - { - case XFRM_POLICY_IN: - if (req.n.nlmsg_type == XFRM_MSG_DELPOLICY) + if (policy == IPSEC_POLICY_IPSEC && (op & ERO_MASK) != ERO_DELETE) { - req.u.id.dir = XFRM_POLICY_FWD; + struct rtattr *attr; + struct xfrm_user_tmpl tmpl[4]; + int i; + + memset(tmpl, 0, sizeof(tmpl)); + for (i = 0; proto_info[i].proto; i++) + { + tmpl[i].reqid = proto_info[i].reqid; + tmpl[i].id.proto = proto_info[i].proto; + tmpl[i].optional = + proto_info[i].proto == IPPROTO_COMP && dir != XFRM_POLICY_OUT; + tmpl[i].aalgos = tmpl[i].ealgos = tmpl[i].calgos = ~0; + tmpl[i].mode = + proto_info[i].encapsulation == ENCAPSULATION_MODE_TUNNEL; + + if (!tmpl[i].mode) + { + continue; + } + + ip2xfrm(this_host, &tmpl[i].saddr); + ip2xfrm(that_host, &tmpl[i].id.daddr); + } + + attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); + attr->rta_type = XFRMA_TMPL; + attr->rta_len = i * sizeof(tmpl[0]); + memcpy(RTA_DATA(attr), tmpl, attr->rta_len); + attr->rta_len = RTA_LENGTH(attr->rta_len); + req.n.nlmsg_len += attr->rta_len; } - else if (!ok) + + enoent_ok = FALSE; + if (op == ERO_DEL_INBOUND) { - break; + enoent_ok = TRUE; } - else if (proto_info[0].encapsulation != ENCAPSULATION_MODE_TUNNEL - && satype != SADB_X_SATYPE_INT) + else if (op == ERO_DELETE && ntohl(spi) == SPI_HOLD) { - break; + enoent_ok = TRUE; } - else + + ok = netlink_policy(&req.n, enoent_ok, text_said); + switch (dir) { - req.u.p.dir = XFRM_POLICY_FWD; + case XFRM_POLICY_IN: + if (req.n.nlmsg_type == XFRM_MSG_DELPOLICY) + { + req.u.id.dir = XFRM_POLICY_FWD; + } + else if (!ok) + { + break; + } + else if (proto_info[0].encapsulation != ENCAPSULATION_MODE_TUNNEL + && satype != SADB_X_SATYPE_INT) + { + break; + } + else + { + req.u.p.dir = XFRM_POLICY_FWD; + } + ok &= netlink_policy(&req.n, enoent_ok, text_said); + break; } - ok &= netlink_policy(&req.n, enoent_ok, text_said); - break; - } - return ok; + return ok; } /** netlink_add_sa - Add an SA into the kernel SPDB via netlink @@ -573,130 +571,130 @@ netlink_raw_eroute(const ip_address *this_host static bool netlink_add_sa(const struct kernel_sa *sa, bool replace) { - struct { - struct nlmsghdr n; - struct xfrm_usersa_info p; - char data[1024]; - } req; - struct rtattr *attr; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - req.n.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; - - ip2xfrm(sa->src, &req.p.saddr); - ip2xfrm(sa->dst, &req.p.id.daddr); - - req.p.id.spi = sa->spi; - req.p.id.proto = satype2proto(sa->satype); - req.p.family = sa->src->u.v4.sin_family; - req.p.mode = (sa->encapsulation == ENCAPSULATION_MODE_TUNNEL); - req.p.replay_window = sa->replay_window; - req.p.reqid = sa->reqid; - req.p.lft.soft_byte_limit = XFRM_INF; - req.p.lft.soft_packet_limit = XFRM_INF; - req.p.lft.hard_byte_limit = XFRM_INF; - req.p.lft.hard_packet_limit = XFRM_INF; - - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.p))); - - attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); - - if (sa->authalg) - { - struct xfrm_algo algo; - const char *name; - - name = sparse_name(aalg_list, sa->authalg); - if (!name) { - loglog(RC_LOG_SERIOUS, "unknown authentication algorithm: %u" - , sa->authalg); - return FALSE; - } + struct { + struct nlmsghdr n; + struct xfrm_usersa_info p; + char data[1024]; + } req; + struct rtattr *attr; + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.n.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; - strcpy(algo.alg_name, name); - algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE; + ip2xfrm(sa->src, &req.p.saddr); + ip2xfrm(sa->dst, &req.p.id.daddr); - attr->rta_type = XFRMA_ALG_AUTH; - attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen); + req.p.id.spi = sa->spi; + req.p.id.proto = satype2proto(sa->satype); + req.p.family = sa->src->u.v4.sin_family; + req.p.mode = (sa->encapsulation == ENCAPSULATION_MODE_TUNNEL); + req.p.replay_window = sa->replay_window; + req.p.reqid = sa->reqid; + req.p.lft.soft_byte_limit = XFRM_INF; + req.p.lft.soft_packet_limit = XFRM_INF; + req.p.lft.hard_byte_limit = XFRM_INF; + req.p.lft.hard_packet_limit = XFRM_INF; - memcpy(RTA_DATA(attr), &algo, sizeof(algo)); - memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->authkey - , sa->authkeylen); + req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.p))); - req.n.nlmsg_len += attr->rta_len; - attr = (struct rtattr *)((char *)attr + attr->rta_len); - } + attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); + + if (sa->authalg) + { + struct xfrm_algo algo; + const char *name; - if (sa->encalg) - { - struct xfrm_algo algo; - const char *name; + name = sparse_name(aalg_list, sa->authalg); + if (!name) { + loglog(RC_LOG_SERIOUS, "unknown authentication algorithm: %u" + , sa->authalg); + return FALSE; + } - name = sparse_name(ealg_list, sa->encalg); - if (!name) { - loglog(RC_LOG_SERIOUS, "unknown encryption algorithm: %u" - , sa->encalg); - return FALSE; + strcpy(algo.alg_name, name); + algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE; + + attr->rta_type = XFRMA_ALG_AUTH; + attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen); + + memcpy(RTA_DATA(attr), &algo, sizeof(algo)); + memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->authkey + , sa->authkeylen); + + req.n.nlmsg_len += attr->rta_len; + attr = (struct rtattr *)((char *)attr + attr->rta_len); } - strcpy(algo.alg_name, name); - algo.alg_key_len = sa->enckeylen * BITS_PER_BYTE; + if (sa->encalg) + { + struct xfrm_algo algo; + const char *name; - attr->rta_type = XFRMA_ALG_CRYPT; - attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->enckeylen); + name = sparse_name(ealg_list, sa->encalg); + if (!name) { + loglog(RC_LOG_SERIOUS, "unknown encryption algorithm: %u" + , sa->encalg); + return FALSE; + } - memcpy(RTA_DATA(attr), &algo, sizeof(algo)); - memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->enckey - , sa->enckeylen); + strcpy(algo.alg_name, name); + algo.alg_key_len = sa->enckeylen * BITS_PER_BYTE; - req.n.nlmsg_len += attr->rta_len; - attr = (struct rtattr *)((char *)attr + attr->rta_len); - } + attr->rta_type = XFRMA_ALG_CRYPT; + attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->enckeylen); - if (sa->compalg) - { - struct xfrm_algo algo; - const char *name; + memcpy(RTA_DATA(attr), &algo, sizeof(algo)); + memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->enckey + , sa->enckeylen); - name = sparse_name(calg_list, sa->compalg); - if (!name) { - loglog(RC_LOG_SERIOUS, "unknown compression algorithm: %u" - , sa->compalg); - return FALSE; + req.n.nlmsg_len += attr->rta_len; + attr = (struct rtattr *)((char *)attr + attr->rta_len); } - strcpy(algo.alg_name, name); - algo.alg_key_len = 0; + if (sa->compalg) + { + struct xfrm_algo algo; + const char *name; - attr->rta_type = XFRMA_ALG_COMP; - attr->rta_len = RTA_LENGTH(sizeof(algo)); + name = sparse_name(calg_list, sa->compalg); + if (!name) { + loglog(RC_LOG_SERIOUS, "unknown compression algorithm: %u" + , sa->compalg); + return FALSE; + } - memcpy(RTA_DATA(attr), &algo, sizeof(algo)); + strcpy(algo.alg_name, name); + algo.alg_key_len = 0; - req.n.nlmsg_len += attr->rta_len; - attr = (struct rtattr *)((char *)attr + attr->rta_len); - } + attr->rta_type = XFRMA_ALG_COMP; + attr->rta_len = RTA_LENGTH(sizeof(algo)); - if (sa->natt_type) - { - struct xfrm_encap_tmpl natt; + memcpy(RTA_DATA(attr), &algo, sizeof(algo)); - natt.encap_type = sa->natt_type; - natt.encap_sport = ntohs(sa->natt_sport); - natt.encap_dport = ntohs(sa->natt_dport); - memset (&natt.encap_oa, 0, sizeof (natt.encap_oa)); + req.n.nlmsg_len += attr->rta_len; + attr = (struct rtattr *)((char *)attr + attr->rta_len); + } - attr->rta_type = XFRMA_ENCAP; - attr->rta_len = RTA_LENGTH(sizeof(natt)); + if (sa->natt_type) + { + struct xfrm_encap_tmpl natt; + + natt.encap_type = sa->natt_type; + natt.encap_sport = ntohs(sa->natt_sport); + natt.encap_dport = ntohs(sa->natt_dport); + memset (&natt.encap_oa, 0, sizeof (natt.encap_oa)); - memcpy(RTA_DATA(attr), &natt, sizeof(natt)); + attr->rta_type = XFRMA_ENCAP; + attr->rta_len = RTA_LENGTH(sizeof(natt)); - req.n.nlmsg_len += attr->rta_len; - attr = (struct rtattr *)((char *)attr + attr->rta_len); - } + memcpy(RTA_DATA(attr), &natt, sizeof(natt)); - return send_netlink_msg(&req.n, NULL, 0, "Add SA", sa->text_said); + req.n.nlmsg_len += attr->rta_len; + attr = (struct rtattr *)((char *)attr + attr->rta_len); + } + + return send_netlink_msg(&req.n, NULL, 0, "Add SA", sa->text_said); } /** netlink_del_sa - Delete an SA from the Kernel @@ -707,113 +705,113 @@ netlink_add_sa(const struct kernel_sa *sa, bool replace) static bool netlink_del_sa(const struct kernel_sa *sa) { - struct { - struct nlmsghdr n; - struct xfrm_usersa_id id; - char data[1024]; - } req; + struct { + struct nlmsghdr n; + struct xfrm_usersa_id id; + char data[1024]; + } req; - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - req.n.nlmsg_type = XFRM_MSG_DELSA; + memset(&req, 0, sizeof(req)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.n.nlmsg_type = XFRM_MSG_DELSA; - ip2xfrm(sa->dst, &req.id.daddr); + ip2xfrm(sa->dst, &req.id.daddr); - req.id.spi = sa->spi; - req.id.family = sa->src->u.v4.sin_family; - req.id.proto = sa->proto; + req.id.spi = sa->spi; + req.id.family = sa->src->u.v4.sin_family; + req.id.proto = sa->proto; - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); + req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); - return send_netlink_msg(&req.n, NULL, 0, "Del SA", sa->text_said); + return send_netlink_msg(&req.n, NULL, 0, "Del SA", sa->text_said); } static bool netlink_error(const char *req_type, const struct nlmsghdr *n , const struct nlmsgerr *e, int rsp_size) { - if (n->nlmsg_type == NLMSG_ERROR) - { - DBG(DBG_KLIPS, - DBG_log("%s returned with errno %d: %s" - , req_type - , -e->error - , strerror(-e->error)) - ) - return TRUE; - } - if (n->nlmsg_len < NLMSG_LENGTH(rsp_size)) - { - plog("%s returned message with length %lu < %lu bytes" - , req_type - , (unsigned long) n->nlmsg_len - , (unsigned long) rsp_size); - return TRUE; - } - return FALSE; + if (n->nlmsg_type == NLMSG_ERROR) + { + DBG(DBG_KLIPS, + DBG_log("%s returned with errno %d: %s" + , req_type + , -e->error + , strerror(-e->error)) + ) + return TRUE; + } + if (n->nlmsg_len < NLMSG_LENGTH(rsp_size)) + { + plog("%s returned message with length %lu < %lu bytes" + , req_type + , (unsigned long) n->nlmsg_len + , (unsigned long) rsp_size); + return TRUE; + } + return FALSE; } static bool netlink_get_policy(const struct kernel_sa *sa, bool inbound, time_t *use_time) { - struct { - struct nlmsghdr n; - struct xfrm_userpolicy_id id; - } req; - - struct { - struct nlmsghdr n; - union { - struct nlmsgerr e; - struct xfrm_userpolicy_info info; - } u; - char data[1024]; - } rsp; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_GETPOLICY; - - req.id.sel.sport = portof(&sa->src_client->addr); - req.id.sel.dport = portof(&sa->dst_client->addr); - req.id.sel.sport_mask = (req.id.sel.sport) ? ~0:0; - req.id.sel.dport_mask = (req.id.sel.dport) ? ~0:0; - ip2xfrm(&sa->src_client->addr, &req.id.sel.saddr); - ip2xfrm(&sa->dst_client->addr, &req.id.sel.daddr); - req.id.sel.prefixlen_s = sa->src_client->maskbits; - req.id.sel.prefixlen_d = sa->dst_client->maskbits; - req.id.sel.proto = sa->transport_proto; - req.id.sel.family = sa->dst_client->addr.u.v4.sin_family; - - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); - rsp.n.nlmsg_type = XFRM_MSG_NEWPOLICY; - - req.id.dir = (inbound)? XFRM_POLICY_IN:XFRM_POLICY_OUT; - - if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?")) - return FALSE; + struct { + struct nlmsghdr n; + struct xfrm_userpolicy_id id; + } req; + + struct { + struct nlmsghdr n; + union { + struct nlmsgerr e; + struct xfrm_userpolicy_info info; + } u; + char data[1024]; + } rsp; + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = XFRM_MSG_GETPOLICY; + + req.id.sel.sport = portof(&sa->src_client->addr); + req.id.sel.dport = portof(&sa->dst_client->addr); + req.id.sel.sport_mask = (req.id.sel.sport) ? ~0:0; + req.id.sel.dport_mask = (req.id.sel.dport) ? ~0:0; + ip2xfrm(&sa->src_client->addr, &req.id.sel.saddr); + ip2xfrm(&sa->dst_client->addr, &req.id.sel.daddr); + req.id.sel.prefixlen_s = sa->src_client->maskbits; + req.id.sel.prefixlen_d = sa->dst_client->maskbits; + req.id.sel.proto = sa->transport_proto; + req.id.sel.family = sa->dst_client->addr.u.v4.sin_family; + + req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); + rsp.n.nlmsg_type = XFRM_MSG_NEWPOLICY; + + req.id.dir = (inbound)? XFRM_POLICY_IN:XFRM_POLICY_OUT; - if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.info))) - return FALSE; + if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?")) + return FALSE; + + if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.info))) + return FALSE; - *use_time = (time_t)rsp.u.info.curlft.use_time; + *use_time = (time_t)rsp.u.info.curlft.use_time; - if (inbound && sa->encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - time_t use_time_fwd; + if (inbound && sa->encapsulation == ENCAPSULATION_MODE_TUNNEL) + { + time_t use_time_fwd; - req.id.dir = XFRM_POLICY_FWD; + req.id.dir = XFRM_POLICY_FWD; - if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?")) - return FALSE; + if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?")) + return FALSE; - if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.info))) - return FALSE; + if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.info))) + return FALSE; - use_time_fwd = (time_t)rsp.u.info.curlft.use_time; - *use_time = (*use_time > use_time_fwd)? *use_time : use_time_fwd; - } - return TRUE; + use_time_fwd = (time_t)rsp.u.info.curlft.use_time; + *use_time = (*use_time > use_time_fwd)? *use_time : use_time_fwd; + } + return TRUE; } @@ -825,60 +823,60 @@ netlink_get_policy(const struct kernel_sa *sa, bool inbound, time_t *use_time) static bool netlink_get_sa(const struct kernel_sa *sa, u_int *bytes) { - struct { - struct nlmsghdr n; - struct xfrm_usersa_id id; - } req; - - struct { - struct nlmsghdr n; - union { - struct nlmsgerr e; - struct xfrm_usersa_info info; - } u; - char data[1024]; - } rsp; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_GETSA; - - ip2xfrm(sa->dst, &req.id.daddr); - - req.id.spi = sa->spi; - req.id.family = sa->src->u.v4.sin_family; - req.id.proto = sa->proto; - - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); - rsp.n.nlmsg_type = XFRM_MSG_NEWSA; - - if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get SA", sa->text_said)) - return FALSE; + struct { + struct nlmsghdr n; + struct xfrm_usersa_id id; + } req; - if (netlink_error("XFRM_MSG_GETSA", &rsp.n, &rsp.u.e, sizeof(rsp.u.info))) - return FALSE; + struct { + struct nlmsghdr n; + union { + struct nlmsgerr e; + struct xfrm_usersa_info info; + } u; + char data[1024]; + } rsp; + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = XFRM_MSG_GETSA; + + ip2xfrm(sa->dst, &req.id.daddr); - *bytes = (u_int) rsp.u.info.curlft.bytes; + req.id.spi = sa->spi; + req.id.family = sa->src->u.v4.sin_family; + req.id.proto = sa->proto; - return TRUE; + req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); + rsp.n.nlmsg_type = XFRM_MSG_NEWSA; + + if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get SA", sa->text_said)) + return FALSE; + + if (netlink_error("XFRM_MSG_GETSA", &rsp.n, &rsp.u.e, sizeof(rsp.u.info))) + return FALSE; + + *bytes = (u_int) rsp.u.info.curlft.bytes; + + return TRUE; } static void linux_pfkey_register_response(const struct sadb_msg *msg) { - switch (msg->sadb_msg_satype) - { - case SADB_SATYPE_ESP: + switch (msg->sadb_msg_satype) + { + case SADB_SATYPE_ESP: #ifndef NO_KERNEL_ALG - kernel_alg_register_pfkey(msg, msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN); + kernel_alg_register_pfkey(msg, msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN); #endif - break; - case SADB_X_SATYPE_IPCOMP: - can_do_IPcomp = TRUE; - break; - default: - break; - } + break; + case SADB_X_SATYPE_IPCOMP: + can_do_IPcomp = TRUE; + break; + default: + break; + } } /** linux_pfkey_register - Register via PFKEY our capabilities @@ -887,10 +885,10 @@ linux_pfkey_register_response(const struct sadb_msg *msg) static void linux_pfkey_register(void) { - pfkey_register_proto(SADB_SATYPE_AH, "AH"); - pfkey_register_proto(SADB_SATYPE_ESP, "ESP"); - pfkey_register_proto(SADB_X_SATYPE_IPCOMP, "IPCOMP"); - pfkey_close(); + pfkey_register_proto(SADB_SATYPE_AH, "AH"); + pfkey_register_proto(SADB_SATYPE_ESP, "ESP"); + pfkey_register_proto(SADB_X_SATYPE_IPCOMP, "IPCOMP"); + pfkey_close(); } /** Create ip_address out of xfrm_address_t. @@ -903,18 +901,18 @@ linux_pfkey_register(void) static err_t xfrm_to_ip_address(unsigned family, const xfrm_address_t *src, ip_address *dst) { - switch (family) - { - case AF_INET: /* IPv4 */ - case AF_UNSPEC: /* Unspecified, we assume IPv4 */ - initaddr((const void *) &src->a4, sizeof(src->a4), AF_INET, dst); - return NULL; - case AF_INET6: /* IPv6 */ - initaddr((const void *) &src->a6, sizeof(src->a6), AF_INET6, dst); - return NULL; - default: - return "unknown address family"; - } + switch (family) + { + case AF_INET: /* IPv4 */ + case AF_UNSPEC: /* Unspecified, we assume IPv4 */ + initaddr((const void *) &src->a4, sizeof(src->a4), AF_INET, dst); + return NULL; + case AF_INET6: /* IPv6 */ + initaddr((const void *) &src->a6, sizeof(src->a6), AF_INET6, dst); + return NULL; + default: + return "unknown address family"; + } } /* Create a pair of ip_address's out of xfrm_sel. @@ -926,29 +924,29 @@ xfrm_to_ip_address(unsigned family, const xfrm_address_t *src, ip_address *dst) */ static err_t xfrm_sel_to_ip_pair(const struct xfrm_selector *sel - , ip_address *src - , ip_address *dst) + , ip_address *src + , ip_address *dst) { - int family; - err_t ugh; - - family = sel->family; - - if ((ugh = xfrm_to_ip_address(family, &sel->saddr, src)) - || (ugh = xfrm_to_ip_address(family, &sel->daddr, dst))) - return ugh; - - /* family has been verified in xfrm_to_ip_address. */ - if (family == AF_INET) - { - src->u.v4.sin_port = sel->sport; - dst->u.v4.sin_port = sel->dport; - } - else - { - src->u.v6.sin6_port = sel->sport; - dst->u.v6.sin6_port = sel->dport; - } + int family; + err_t ugh; + + family = sel->family; + + if ((ugh = xfrm_to_ip_address(family, &sel->saddr, src)) + || (ugh = xfrm_to_ip_address(family, &sel->daddr, dst))) + return ugh; + + /* family has been verified in xfrm_to_ip_address. */ + if (family == AF_INET) + { + src->u.v4.sin_port = sel->sport; + dst->u.v4.sin_port = sel->dport; + } + else + { + src->u.v6.sin6_port = sel->sport; + dst->u.v6.sin6_port = sel->dport; + } return NULL; } @@ -956,194 +954,194 @@ xfrm_sel_to_ip_pair(const struct xfrm_selector *sel static void netlink_acquire(struct nlmsghdr *n) { - struct xfrm_user_acquire *acquire; - ip_address src, dst; - ip_subnet ours, his; - unsigned transport_proto; - err_t ugh = NULL; - - if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*acquire))) - { - plog("netlink_acquire got message with length %lu < %lu bytes; ignore message" - , (unsigned long) n->nlmsg_len - , (unsigned long) sizeof(*acquire)); - return; - } - - acquire = NLMSG_DATA(n); - transport_proto = acquire->sel.proto; - - /* XXX also the type of src/dst should be checked to make sure - * that they aren't v4 to v6 or something goofy - */ - - if (!(ugh = xfrm_sel_to_ip_pair(&acquire->sel, &src, &dst)) - && !(ugh = addrtosubnet(&src, &ours)) - && !(ugh = addrtosubnet(&dst, &his))) - record_and_initiate_opportunistic(&ours, &his, transport_proto - , "%acquire-netlink"); - - if (ugh != NULL) - plog("XFRM_MSG_ACQUIRE message from kernel malformed: %s", ugh); + struct xfrm_user_acquire *acquire; + ip_address src, dst; + ip_subnet ours, his; + unsigned transport_proto; + err_t ugh = NULL; + + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*acquire))) + { + plog("netlink_acquire got message with length %lu < %lu bytes; ignore message" + , (unsigned long) n->nlmsg_len + , (unsigned long) sizeof(*acquire)); + return; + } + + acquire = NLMSG_DATA(n); + transport_proto = acquire->sel.proto; + + /* XXX also the type of src/dst should be checked to make sure + * that they aren't v4 to v6 or something goofy + */ + + if (!(ugh = xfrm_sel_to_ip_pair(&acquire->sel, &src, &dst)) + && !(ugh = addrtosubnet(&src, &ours)) + && !(ugh = addrtosubnet(&dst, &his))) + record_and_initiate_opportunistic(&ours, &his, transport_proto + , "%acquire-netlink"); + + if (ugh != NULL) + plog("XFRM_MSG_ACQUIRE message from kernel malformed: %s", ugh); } static void netlink_shunt_expire(struct xfrm_userpolicy_info *pol) { - ip_address src, dst; - unsigned transport_proto; - err_t ugh = NULL; - - transport_proto = pol->sel.proto; - - if (!(ugh = xfrm_sel_to_ip_pair(&pol->sel, &src, &dst))) - { - plog("XFRM_MSG_POLEXPIRE message from kernel malformed: %s", ugh); - return; - } - - replace_bare_shunt(&src, &dst, BOTTOM_PRIO, SPI_PASS, FALSE, transport_proto - , "delete expired bare shunt"); + ip_address src, dst; + unsigned transport_proto; + err_t ugh = NULL; + + transport_proto = pol->sel.proto; + + if (!(ugh = xfrm_sel_to_ip_pair(&pol->sel, &src, &dst))) + { + plog("XFRM_MSG_POLEXPIRE message from kernel malformed: %s", ugh); + return; + } + + replace_bare_shunt(&src, &dst, BOTTOM_PRIO, SPI_PASS, FALSE, transport_proto + , "delete expired bare shunt"); } static void netlink_policy_expire(struct nlmsghdr *n) { - struct xfrm_user_polexpire *upe; - struct { - struct nlmsghdr n; - struct xfrm_userpolicy_id id; - } req; - - struct { - struct nlmsghdr n; - union { - struct nlmsgerr e; - struct xfrm_userpolicy_info pol; - } u; - char data[1024]; - } rsp; - - if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*upe))) - { - plog("netlink_policy_expire got message with length %lu < %lu bytes; ignore message" - , (unsigned long) n->nlmsg_len - , (unsigned long) sizeof(*upe)); - return; - } - - upe = NLMSG_DATA(n); - req.id.dir = upe->pol.dir; - req.id.index = upe->pol.index; - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_GETPOLICY; - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); - - rsp.n.nlmsg_type = XFRM_MSG_NEWPOLICY; - - if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?")) - return; - - if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.pol))) - return; - - if (req.id.index != rsp.u.pol.index) - { - DBG(DBG_KLIPS, - DBG_log("netlink_policy_expire: policy was replaced: " - "dir=%d, oldindex=%d, newindex=%d" - , req.id.dir, req.id.index, rsp.u.pol.index)); - return; - } - - if (upe->pol.curlft.add_time != rsp.u.pol.curlft.add_time) - { - DBG(DBG_KLIPS, - DBG_log("netlink_policy_expire: policy was replaced " - " and you have won the lottery: " - "dir=%d, index=%d" - , req.id.dir, req.id.index)); - return; - } - - switch (upe->pol.dir) - { - case XFRM_POLICY_OUT: - netlink_shunt_expire(&rsp.u.pol); - break; - } + struct xfrm_user_polexpire *upe; + struct { + struct nlmsghdr n; + struct xfrm_userpolicy_id id; + } req; + + struct { + struct nlmsghdr n; + union { + struct nlmsgerr e; + struct xfrm_userpolicy_info pol; + } u; + char data[1024]; + } rsp; + + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*upe))) + { + plog("netlink_policy_expire got message with length %lu < %lu bytes; ignore message" + , (unsigned long) n->nlmsg_len + , (unsigned long) sizeof(*upe)); + return; + } + + upe = NLMSG_DATA(n); + req.id.dir = upe->pol.dir; + req.id.index = upe->pol.index; + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = XFRM_MSG_GETPOLICY; + req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); + + rsp.n.nlmsg_type = XFRM_MSG_NEWPOLICY; + + if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?")) + return; + + if (netlink_error("XFRM_MSG_GETPOLICY", &rsp.n, &rsp.u.e, sizeof(rsp.u.pol))) + return; + + if (req.id.index != rsp.u.pol.index) + { + DBG(DBG_KLIPS, + DBG_log("netlink_policy_expire: policy was replaced: " + "dir=%d, oldindex=%d, newindex=%d" + , req.id.dir, req.id.index, rsp.u.pol.index)); + return; + } + + if (upe->pol.curlft.add_time != rsp.u.pol.curlft.add_time) + { + DBG(DBG_KLIPS, + DBG_log("netlink_policy_expire: policy was replaced " + " and you have won the lottery: " + "dir=%d, index=%d" + , req.id.dir, req.id.index)); + return; + } + + switch (upe->pol.dir) + { + case XFRM_POLICY_OUT: + netlink_shunt_expire(&rsp.u.pol); + break; + } } static bool netlink_get(void) { - struct { - struct nlmsghdr n; - char data[1024]; - } rsp; - ssize_t r; - struct sockaddr_nl addr; - socklen_t alen; - - alen = sizeof(addr); - r = recvfrom(netlink_bcast_fd, &rsp, sizeof(rsp), 0 - , (struct sockaddr *)&addr, &alen); - if (r < 0) - { - if (errno == EAGAIN) - return FALSE; - if (errno != EINTR) - log_errno((e, "recvfrom() failed in netlink_get")); - return TRUE; - } - else if ((size_t) r < sizeof(rsp.n)) - { - plog("netlink_get read truncated message: %ld bytes; ignore message" - , (long) r); - return TRUE; - } - else if (addr.nl_pid != 0) - { - /* not for us: ignore */ + struct { + struct nlmsghdr n; + char data[1024]; + } rsp; + ssize_t r; + struct sockaddr_nl addr; + socklen_t alen; + + alen = sizeof(addr); + r = recvfrom(netlink_bcast_fd, &rsp, sizeof(rsp), 0 + , (struct sockaddr *)&addr, &alen); + if (r < 0) + { + if (errno == EAGAIN) + return FALSE; + if (errno != EINTR) + log_errno((e, "recvfrom() failed in netlink_get")); + return TRUE; + } + else if ((size_t) r < sizeof(rsp.n)) + { + plog("netlink_get read truncated message: %ld bytes; ignore message" + , (long) r); + return TRUE; + } + else if (addr.nl_pid != 0) + { + /* not for us: ignore */ + DBG(DBG_KLIPS, + DBG_log("netlink_get: ignoring %s message from process %u" + , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type) + , addr.nl_pid)); + return TRUE; + } + else if ((size_t) r != rsp.n.nlmsg_len) + { + plog("netlink_get read message with length %ld that doesn't equal nlmsg_len %lu bytes; ignore message" + , (long) r + , (unsigned long) rsp.n.nlmsg_len); + return TRUE; + } + DBG(DBG_KLIPS, - DBG_log("netlink_get: ignoring %s message from process %u" - , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type) - , addr.nl_pid)); - return TRUE; - } - else if ((size_t) r != rsp.n.nlmsg_len) - { - plog("netlink_get read message with length %ld that doesn't equal nlmsg_len %lu bytes; ignore message" - , (long) r - , (unsigned long) rsp.n.nlmsg_len); + DBG_log("netlink_get: %s message" + , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type))); + + switch (rsp.n.nlmsg_type) + { + case XFRM_MSG_ACQUIRE: + netlink_acquire(&rsp.n); + break; + case XFRM_MSG_POLEXPIRE: + netlink_policy_expire(&rsp.n); + break; + default: + /* ignored */ + break; + } + return TRUE; - } - - DBG(DBG_KLIPS, - DBG_log("netlink_get: %s message" - , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type))); - - switch (rsp.n.nlmsg_type) - { - case XFRM_MSG_ACQUIRE: - netlink_acquire(&rsp.n); - break; - case XFRM_MSG_POLEXPIRE: - netlink_policy_expire(&rsp.n); - break; - default: - /* ignored */ - break; - } - - return TRUE; } static void netlink_process_msg(void) { - while (netlink_get()) - ; + while (netlink_get()) + ; } static ipsec_spi_t @@ -1156,65 +1154,65 @@ netlink_get_spi(const ip_address *src , ipsec_spi_t max , const char *text_said) { - struct { - struct nlmsghdr n; - struct xfrm_userspi_info spi; - } req; - - struct { - struct nlmsghdr n; - union { - struct nlmsgerr e; - struct xfrm_usersa_info sa; - } u; - char data[1024]; - } rsp; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_ALLOCSPI; - - ip2xfrm(src, &req.spi.info.saddr); - ip2xfrm(dst, &req.spi.info.id.daddr); - req.spi.info.mode = tunnel_mode; - req.spi.info.reqid = reqid; - req.spi.info.id.proto = proto; - req.spi.info.family = src->u.v4.sin_family; - req.spi.min = min; - req.spi.max = max; - - req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.spi))); - rsp.n.nlmsg_type = XFRM_MSG_NEWSA; - - if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get SPI", text_said)) - return 0; - - if (netlink_error("XFRM_MSG_ALLOCSPI", &rsp.n, &rsp.u.e, sizeof(rsp.u.sa))) - return 0; - - DBG(DBG_KLIPS, - DBG_log("netlink_get_spi: allocated 0x%x for %s" - , ntohl(rsp.u.sa.id.spi), text_said)); - return rsp.u.sa.id.spi; + struct { + struct nlmsghdr n; + struct xfrm_userspi_info spi; + } req; + + struct { + struct nlmsghdr n; + union { + struct nlmsgerr e; + struct xfrm_usersa_info sa; + } u; + char data[1024]; + } rsp; + + memset(&req, 0, sizeof(req)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = XFRM_MSG_ALLOCSPI; + + ip2xfrm(src, &req.spi.info.saddr); + ip2xfrm(dst, &req.spi.info.id.daddr); + req.spi.info.mode = tunnel_mode; + req.spi.info.reqid = reqid; + req.spi.info.id.proto = proto; + req.spi.info.family = src->u.v4.sin_family; + req.spi.min = min; + req.spi.max = max; + + req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.spi))); + rsp.n.nlmsg_type = XFRM_MSG_NEWSA; + + if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get SPI", text_said)) + return 0; + + if (netlink_error("XFRM_MSG_ALLOCSPI", &rsp.n, &rsp.u.e, sizeof(rsp.u.sa))) + return 0; + + DBG(DBG_KLIPS, + DBG_log("netlink_get_spi: allocated 0x%x for %s" + , ntohl(rsp.u.sa.id.spi), text_said)); + return rsp.u.sa.id.spi; } const struct kernel_ops linux_kernel_ops = { - type: KERNEL_TYPE_LINUX, - inbound_eroute: 1, - policy_lifetime: 1, - async_fdp: &netlink_bcast_fd, - - init: init_netlink, - pfkey_register: linux_pfkey_register, - pfkey_register_response: linux_pfkey_register_response, - process_msg: netlink_process_msg, - raw_eroute: netlink_raw_eroute, - get_policy: netlink_get_policy, - add_sa: netlink_add_sa, - del_sa: netlink_del_sa, - get_sa: netlink_get_sa, - process_queue: NULL, - grp_sa: NULL, - get_spi: netlink_get_spi, + type: KERNEL_TYPE_LINUX, + inbound_eroute: 1, + policy_lifetime: 1, + async_fdp: &netlink_bcast_fd, + + init: init_netlink, + pfkey_register: linux_pfkey_register, + pfkey_register_response: linux_pfkey_register_response, + process_msg: netlink_process_msg, + raw_eroute: netlink_raw_eroute, + get_policy: netlink_get_policy, + add_sa: netlink_add_sa, + del_sa: netlink_del_sa, + get_sa: netlink_get_sa, + process_queue: NULL, + grp_sa: NULL, + get_spi: netlink_get_spi, }; #endif /* linux && KLIPS */ diff --git a/src/pluto/kernel_netlink.h b/src/pluto/kernel_netlink.h index 91ba71c5c..65163c966 100644 --- a/src/pluto/kernel_netlink.h +++ b/src/pluto/kernel_netlink.h @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: kernel_netlink.h 3252 2007-10-06 21:24:50Z andreas $ */ #if defined(KLIPS) && defined(linux) diff --git a/src/pluto/kernel_noklips.c b/src/pluto/kernel_noklips.c index 4ac3eb153..82a6ab648 100644 --- a/src/pluto/kernel_noklips.c +++ b/src/pluto/kernel_noklips.c @@ -13,8 +13,6 @@ * 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. - * - * RCSID $Id: kernel_noklips.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <errno.h> @@ -39,7 +37,7 @@ #include "kernel.h" #include "kernel_noklips.h" #include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ +#include "whack.h" /* for RC_LOG_SERIOUS */ void init_noklips(void) @@ -71,30 +69,30 @@ noklips_register(void) static bool noklips_raw_eroute(const ip_address *this_host UNUSED - , const ip_subnet *this_client UNUSED - , const ip_address *that_host UNUSED - , const ip_subnet *that_client UNUSED - , ipsec_spi_t spi UNUSED - , unsigned int satype UNUSED - , unsigned int transport_proto UNUSED - , const struct pfkey_proto_info *proto_info UNUSED - , time_t use_lifetime UNUSED - , unsigned int op UNUSED - , const char *text_said UNUSED) + , const ip_subnet *this_client UNUSED + , const ip_address *that_host UNUSED + , const ip_subnet *that_client UNUSED + , ipsec_spi_t spi UNUSED + , unsigned int satype UNUSED + , unsigned int transport_proto UNUSED + , const struct pfkey_proto_info *proto_info UNUSED + , time_t use_lifetime UNUSED + , unsigned int op UNUSED + , const char *text_said UNUSED) { return TRUE; } static bool noklips_add_sa(const struct kernel_sa *sa UNUSED - , bool replace UNUSED) + , bool replace UNUSED) { return TRUE; } static bool noklips_grp_sa(const struct kernel_sa *sa0 UNUSED - , const struct kernel_sa *sa1 UNUSED) + , const struct kernel_sa *sa1 UNUSED) { return TRUE; } @@ -107,20 +105,20 @@ noklips_del_sa(const struct kernel_sa *sa UNUSED) const struct kernel_ops noklips_kernel_ops = { - type: KERNEL_TYPE_NONE, - async_fdp: NULL, - - init: init_noklips, - pfkey_register: noklips_register, - pfkey_register_response: noklips_register_response, - process_queue: noklips_dequeue, - process_msg: noklips_event, - raw_eroute: noklips_raw_eroute, - add_sa: noklips_add_sa, - grp_sa: noklips_grp_sa, - del_sa: noklips_del_sa, - get_sa: NULL, - get_spi: NULL, - inbound_eroute: FALSE, - policy_lifetime: FALSE + type: KERNEL_TYPE_NONE, + async_fdp: NULL, + + init: init_noklips, + pfkey_register: noklips_register, + pfkey_register_response: noklips_register_response, + process_queue: noklips_dequeue, + process_msg: noklips_event, + raw_eroute: noklips_raw_eroute, + add_sa: noklips_add_sa, + grp_sa: noklips_grp_sa, + del_sa: noklips_del_sa, + get_sa: NULL, + get_spi: NULL, + inbound_eroute: FALSE, + policy_lifetime: FALSE }; diff --git a/src/pluto/kernel_noklips.h b/src/pluto/kernel_noklips.h index db819eed7..3da55d80b 100644 --- a/src/pluto/kernel_noklips.h +++ b/src/pluto/kernel_noklips.h @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: kernel_noklips.h 3252 2007-10-06 21:24:50Z andreas $ */ extern void init_noklips(void); diff --git a/src/pluto/kernel_pfkey.c b/src/pluto/kernel_pfkey.c index 742afaf52..7ac405fd4 100644 --- a/src/pluto/kernel_pfkey.c +++ b/src/pluto/kernel_pfkey.c @@ -12,8 +12,6 @@ * 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. - * - * RCSID $Id: kernel_pfkey.c 3252 2007-10-06 21:24:50Z andreas $ */ #ifdef KLIPS @@ -40,7 +38,7 @@ #include "kernel.h" #include "kernel_pfkey.h" #include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ +#include "whack.h" /* for RC_LOG_SERIOUS */ #include "demux.h" #include "nat_traversal.h" #include "alg_info.h" @@ -50,64 +48,64 @@ 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 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 */ +#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 } + 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 } }; #ifdef NEVER /* not needed yet */ static sparse_names pfkey_ext_names = { - NE(SADB_EXT_RESERVED), - NE(SADB_EXT_SA), - NE(SADB_EXT_LIFETIME_CURRENT), - NE(SADB_EXT_LIFETIME_HARD), - NE(SADB_EXT_LIFETIME_SOFT), - NE(SADB_EXT_ADDRESS_SRC), - NE(SADB_EXT_ADDRESS_DST), - NE(SADB_EXT_ADDRESS_PROXY), - NE(SADB_EXT_KEY_AUTH), - NE(SADB_EXT_KEY_ENCRYPT), - NE(SADB_EXT_IDENTITY_SRC), - NE(SADB_EXT_IDENTITY_DST), - NE(SADB_EXT_SENSITIVITY), - NE(SADB_EXT_PROPOSAL), - NE(SADB_EXT_SUPPORTED_AUTH), - NE(SADB_EXT_SUPPORTED_ENCRYPT), - NE(SADB_EXT_SPIRANGE), - NE(SADB_X_EXT_KMPRIVATE), - NE(SADB_X_EXT_SATYPE2), - NE(SADB_X_EXT_SA2), - NE(SADB_X_EXT_ADDRESS_DST2), - NE(SADB_X_EXT_ADDRESS_SRC_FLOW), - NE(SADB_X_EXT_ADDRESS_DST_FLOW), - NE(SADB_X_EXT_ADDRESS_SRC_MASK), - NE(SADB_X_EXT_ADDRESS_DST_MASK), - NE(SADB_X_EXT_DEBUG), - { 0, sparse_end } + NE(SADB_EXT_RESERVED), + NE(SADB_EXT_SA), + NE(SADB_EXT_LIFETIME_CURRENT), + NE(SADB_EXT_LIFETIME_HARD), + NE(SADB_EXT_LIFETIME_SOFT), + NE(SADB_EXT_ADDRESS_SRC), + NE(SADB_EXT_ADDRESS_DST), + NE(SADB_EXT_ADDRESS_PROXY), + NE(SADB_EXT_KEY_AUTH), + NE(SADB_EXT_KEY_ENCRYPT), + NE(SADB_EXT_IDENTITY_SRC), + NE(SADB_EXT_IDENTITY_DST), + NE(SADB_EXT_SENSITIVITY), + NE(SADB_EXT_PROPOSAL), + NE(SADB_EXT_SUPPORTED_AUTH), + NE(SADB_EXT_SUPPORTED_ENCRYPT), + NE(SADB_EXT_SPIRANGE), + NE(SADB_X_EXT_KMPRIVATE), + NE(SADB_X_EXT_SATYPE2), + NE(SADB_X_EXT_SA2), + NE(SADB_X_EXT_ADDRESS_DST2), + NE(SADB_X_EXT_ADDRESS_SRC_FLOW), + NE(SADB_X_EXT_ADDRESS_DST_FLOW), + NE(SADB_X_EXT_ADDRESS_SRC_MASK), + NE(SADB_X_EXT_ADDRESS_DST_MASK), + NE(SADB_X_EXT_DEBUG), + { 0, sparse_end } }; #endif /* NEVER */ @@ -116,24 +114,24 @@ static sparse_names pfkey_ext_names = { void init_pfkey(void) { - pid = getpid(); + pid = getpid(); - /* open PF_KEY socket */ + /* open PF_KEY socket */ - pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); + pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); - if (pfkeyfd == -1) - exit_log_errno((e, "socket() in init_pfkeyfd()")); + if (pfkeyfd == -1) + exit_log_errno((e, "socket() in init_pfkeyfd()")); -#ifdef NEVER /* apparently unsupported! */ - if (fcntl(pfkeyfd, F_SETFL, O_NONBLOCK) != 0) - exit_log_errno((e, "fcntl(O_NONBLOCK) in init_pfkeyfd()")); +#ifdef NEVER /* apparently unsupported! */ + if (fcntl(pfkeyfd, F_SETFL, O_NONBLOCK) != 0) + exit_log_errno((e, "fcntl(O_NONBLOCK) in init_pfkeyfd()")); #endif - if (fcntl(pfkeyfd, F_SETFD, FD_CLOEXEC) != 0) - exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_pfkeyfd()")); + if (fcntl(pfkeyfd, F_SETFD, FD_CLOEXEC) != 0) + exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_pfkeyfd()")); - DBG(DBG_KLIPS, - DBG_log("process %u listening for PF_KEY_V2 on file descriptor %d", (unsigned)pid, pfkeyfd)); + DBG(DBG_KLIPS, + DBG_log("process %u listening for PF_KEY_V2 on file descriptor %d", (unsigned)pid, pfkeyfd)); } /* Kinds of PF_KEY message from the kernel: @@ -153,9 +151,9 @@ init_pfkey(void) */ typedef union { - unsigned char bytes[PFKEYv2_MAX_MSGSIZE]; - struct sadb_msg msg; - } pfkey_buf; + unsigned char bytes[PFKEYv2_MAX_MSGSIZE]; + struct sadb_msg msg; + } pfkey_buf; /* queue of unprocessed PF_KEY messages input from kernel * Note that the pfkey_buf may be partly allocated, reflecting @@ -163,41 +161,41 @@ typedef union { * must come first. */ typedef struct pfkey_item { - struct pfkey_item *next; - pfkey_buf buf; - } pfkey_item; + struct pfkey_item *next; + pfkey_buf buf; + } pfkey_item; -static pfkey_item *pfkey_iq_head = NULL; /* oldest */ -static pfkey_item *pfkey_iq_tail; /* youngest */ +static pfkey_item *pfkey_iq_head = NULL; /* oldest */ +static pfkey_item *pfkey_iq_tail; /* youngest */ static bool pfkey_input_ready(void) { - fd_set readfds; - int ndes; - struct timeval tm; + fd_set readfds; + int ndes; + struct timeval tm; - tm.tv_sec = 0; /* don't wait at all */ - tm.tv_usec = 0; + tm.tv_sec = 0; /* don't wait at all */ + tm.tv_usec = 0; - FD_ZERO(&readfds); /* we only care about pfkeyfd */ - FD_SET(pfkeyfd, &readfds); + 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); + 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; - } + if (ndes < 0) + { + log_errno((e, "select() failed in pfkey_get()")); + return FALSE; + } - if (ndes == 0) - return FALSE; /* nothing to read */ + if (ndes == 0) + return FALSE; /* nothing to read */ - passert(ndes == 1 && FD_ISSET(pfkeyfd, &readfds)); - return TRUE; + passert(ndes == 1 && FD_ISSET(pfkeyfd, &readfds)); + return TRUE; } /* get a PF_KEY message from kernel. @@ -210,93 +208,93 @@ pfkey_input_ready(void) 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; + 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; + if (!pfkey_input_ready()) + return FALSE; - len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes)); + len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes)); - if (len < 0) - { - if (errno == EAGAIN) - return FALSE; + 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 message" - , (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 - || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE) - || (buf->msg.sadb_msg_type == SADB_REGISTER) - || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING))) - { - /* not for us: ignore */ - DBG(DBG_KLIPS, - 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_KLIPS, - 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; + 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 message" + , (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 + || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE) + || (buf->msg.sadb_msg_type == SADB_REGISTER) + || (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING))) + { + /* not for us: ignore */ + DBG(DBG_KLIPS, + 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_KLIPS, + 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_pid == (unsigned)pid - && buf->msg.sadb_msg_seq == seq) + while (pfkey_get(buf)) { - return TRUE; - } - else - { - /* Not for us: queue it. */ - size_t bl = buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN; - pfkey_item *it = alloc_bytes(offsetof(pfkey_item, buf) + bl, "pfkey_item"); - - memcpy(&it->buf, buf, bl); - - it->next = NULL; - if (pfkey_iq_head == NULL) - { - pfkey_iq_head = it; - } - else - { - pfkey_iq_tail->next = it; - } - pfkey_iq_tail = it; + if (buf->msg.sadb_msg_pid == (unsigned)pid + && buf->msg.sadb_msg_seq == seq) + { + return TRUE; + } + else + { + /* Not for us: queue it. */ + size_t bl = buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN; + pfkey_item *it = malloc(offsetof(pfkey_item, buf) + bl); + + memcpy(&it->buf, buf, bl); + + it->next = NULL; + if (pfkey_iq_head == NULL) + { + pfkey_iq_head = it; + } + else + { + pfkey_iq_tail->next = it; + } + pfkey_iq_tail = it; + } } - } - return FALSE; + return FALSE; } /* Process a SADB_REGISTER message from the kernel. @@ -307,34 +305,34 @@ pfkey_get_response(pfkey_buf *buf, pfkey_seq_t seq) static void klips_pfkey_register_response(const struct sadb_msg *msg) { - /* Find out what the kernel can support. - * In fact, the only question at the moment - * is whether it can support IPcomp. - * So we ignore the rest. - * ??? we really should pay attention to what transforms are supported. - */ - switch (msg->sadb_msg_satype) - { - case SADB_SATYPE_AH: - break; - case SADB_SATYPE_ESP: + /* Find out what the kernel can support. + * In fact, the only question at the moment + * is whether it can support IPcomp. + * So we ignore the rest. + * ??? we really should pay attention to what transforms are supported. + */ + switch (msg->sadb_msg_satype) + { + case SADB_SATYPE_AH: + break; + case SADB_SATYPE_ESP: #ifndef NO_KERNEL_ALG - kernel_alg_register_pfkey(msg, sizeof (pfkey_buf)); + kernel_alg_register_pfkey(msg, sizeof (pfkey_buf)); #endif - break; - case SADB_X_SATYPE_COMP: - /* ??? There ought to be an extension to list the - * supported algorithms, but RFC 2367 doesn't - * list one for IPcomp. KLIPS uses SADB_X_CALG_DEFLATE. - * Since we only implement deflate, we'll assume this. - */ - can_do_IPcomp = TRUE; - break; - case SADB_X_SATYPE_IPIP: - break; - default: - break; - } + break; + case SADB_X_SATYPE_COMP: + /* ??? There ought to be an extension to list the + * supported algorithms, but RFC 2367 doesn't + * list one for IPcomp. KLIPS uses SADB_X_CALG_DEFLATE. + * Since we only implement deflate, we'll assume this. + */ + can_do_IPcomp = TRUE; + break; + case SADB_X_SATYPE_IPIP: + break; + default: + break; + } } /* Processs a SADB_ACQUIRE message from KLIPS. @@ -357,33 +355,33 @@ klips_pfkey_register_response(const struct sadb_msg *msg) static void process_pfkey_acquire(pfkey_buf *buf, struct sadb_ext *extensions[SADB_EXT_MAX + 1]) { - struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC]; - struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST]; - int src_proto = srcx->sadb_address_proto; - int dst_proto = dstx->sadb_address_proto; - ip_address *src = (ip_address*)&srcx[1]; - ip_address *dst = (ip_address*)&dstx[1]; - ip_subnet ours, his; - err_t ugh = NULL; - - /* assumption: we're only catching our own outgoing packets - * so source is our end and destination is the other end. - * Verifying this is not actually convenient. - * - * This stylized control structure yields a complaint or - * desired results. For compactness, a pointer value is - * treated as a boolean. Logically, the structure is: - * keep going as long as things are OK. - */ - if (buf->msg.sadb_msg_pid == 0 /* we only wish to hear from kernel */ - && !(ugh = src_proto == dst_proto? NULL : "src and dst protocols differ") - && !(ugh = addrtypeof(src) == addrtypeof(dst)? NULL : "conflicting address types") - && !(ugh = addrtosubnet(src, &ours)) - && !(ugh = addrtosubnet(dst, &his))) - record_and_initiate_opportunistic(&ours, &his, src_proto, "%acquire"); - - if (ugh != NULL) - plog("SADB_ACQUIRE message from KLIPS malformed: %s", ugh); + struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC]; + struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST]; + int src_proto = srcx->sadb_address_proto; + int dst_proto = dstx->sadb_address_proto; + ip_address *src = (ip_address*)&srcx[1]; + ip_address *dst = (ip_address*)&dstx[1]; + ip_subnet ours, his; + err_t ugh = NULL; + + /* assumption: we're only catching our own outgoing packets + * so source is our end and destination is the other end. + * Verifying this is not actually convenient. + * + * This stylized control structure yields a complaint or + * desired results. For compactness, a pointer value is + * treated as a boolean. Logically, the structure is: + * keep going as long as things are OK. + */ + if (buf->msg.sadb_msg_pid == 0 /* we only wish to hear from kernel */ + && !(ugh = src_proto == dst_proto? NULL : "src and dst protocols differ") + && !(ugh = addrtypeof(src) == addrtypeof(dst)? NULL : "conflicting address types") + && !(ugh = addrtosubnet(src, &ours)) + && !(ugh = addrtosubnet(dst, &his))) + record_and_initiate_opportunistic(&ours, &his, src_proto, "%acquire"); + + if (ugh != NULL) + plog("SADB_ACQUIRE message from KLIPS malformed: %s", ugh); } @@ -394,73 +392,73 @@ process_pfkey_acquire(pfkey_buf *buf, struct sadb_ext *extensions[SADB_EXT_MAX + static void pfkey_async(pfkey_buf *buf) { - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - - if (pfkey_msg_parse(&buf->msg, NULL, extensions, EXT_BITS_OUT)) - { - plog("pfkey_async:" - " unparseable PF_KEY message:" - " %s len=%d, errno=%d, seq=%d, pid=%d; message ignored" - , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type) - , buf->msg.sadb_msg_len - , buf->msg.sadb_msg_errno - , buf->msg.sadb_msg_seq - , buf->msg.sadb_msg_pid); - } - else - { - DBG(DBG_CONTROL | DBG_KLIPS, DBG_log("pfkey_async:" - " %s len=%u, errno=%u, satype=%u, seq=%u, pid=%u" - , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type) - , buf->msg.sadb_msg_len - , buf->msg.sadb_msg_errno - , buf->msg.sadb_msg_satype - , buf->msg.sadb_msg_seq - , buf->msg.sadb_msg_pid)); - - switch (buf->msg.sadb_msg_type) + struct sadb_ext *extensions[SADB_EXT_MAX + 1]; + + if (pfkey_msg_parse(&buf->msg, NULL, extensions, EXT_BITS_OUT)) { - case SADB_REGISTER: - kernel_ops->pfkey_register_response(&buf->msg); - break; - case SADB_ACQUIRE: - /* to simulate loss of ACQUIRE, delete this call */ - process_pfkey_acquire(buf, extensions); - break; - case SADB_X_NAT_T_NEW_MAPPING: - process_pfkey_nat_t_new_mapping(&(buf->msg), extensions); - break; - default: - /* ignored */ - break; + plog("pfkey_async:" + " unparseable PF_KEY message:" + " %s len=%d, errno=%d, seq=%d, pid=%d; message ignored" + , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type) + , buf->msg.sadb_msg_len + , buf->msg.sadb_msg_errno + , buf->msg.sadb_msg_seq + , buf->msg.sadb_msg_pid); + } + else + { + DBG(DBG_CONTROL | DBG_KLIPS, DBG_log("pfkey_async:" + " %s len=%u, errno=%u, satype=%u, seq=%u, pid=%u" + , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type) + , buf->msg.sadb_msg_len + , buf->msg.sadb_msg_errno + , buf->msg.sadb_msg_satype + , buf->msg.sadb_msg_seq + , buf->msg.sadb_msg_pid)); + + switch (buf->msg.sadb_msg_type) + { + case SADB_REGISTER: + kernel_ops->pfkey_register_response(&buf->msg); + break; + case SADB_ACQUIRE: + /* to simulate loss of ACQUIRE, delete this call */ + process_pfkey_acquire(buf, extensions); + break; + case SADB_X_NAT_T_NEW_MAPPING: + process_pfkey_nat_t_new_mapping(&(buf->msg), extensions); + break; + default: + /* ignored */ + break; + } } - } } /* asynchronous messages from our queue */ static void pfkey_dequeue(void) { - while (pfkey_iq_head != NULL) - { - pfkey_item *it = pfkey_iq_head; - - pfkey_async(&it->buf); - pfkey_iq_head = it->next; - pfree(it); - } - - /* Handle any orphaned holds, but only if no pfkey input is pending. - * For each, we initiate Opportunistic. - * note: we don't need to advance the pointer because - * record_and_initiate_opportunistic will remove the current - * record each time we call it. - */ - while (orphaned_holds != NULL && !pfkey_input_ready()) - record_and_initiate_opportunistic(&orphaned_holds->ours - , &orphaned_holds->his - , orphaned_holds->transport_proto - , "%hold found-pfkey"); + while (pfkey_iq_head != NULL) + { + pfkey_item *it = pfkey_iq_head; + + pfkey_async(&it->buf); + pfkey_iq_head = it->next; + free(it); + } + + /* Handle any orphaned holds, but only if no pfkey input is pending. + * For each, we initiate Opportunistic. + * note: we don't need to advance the pointer because + * record_and_initiate_opportunistic will remove the current + * record each time we call it. + */ + while (orphaned_holds != NULL && !pfkey_input_ready()) + record_and_initiate_opportunistic(&orphaned_holds->ours + , &orphaned_holds->his + , orphaned_holds->transport_proto + , "%hold found-pfkey"); } @@ -468,10 +466,10 @@ pfkey_dequeue(void) static void pfkey_event(void) { - pfkey_buf buf; + pfkey_buf buf; - if (pfkey_get(&buf)) - pfkey_async(&buf); + if (pfkey_get(&buf)) + pfkey_async(&buf); } static bool @@ -480,17 +478,17 @@ pfkey_build(int error , const char *text_said , struct sadb_ext *extensions[SADB_EXT_MAX + 1]) { - if (error == 0) - { - return TRUE; - } - else - { - loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d" - , description, text_said, error); - pfkey_extensions_free(extensions); - return FALSE; - } + if (error == 0) + { + return TRUE; + } + else + { + loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d" + , description, text_said, error); + pfkey_extensions_free(extensions); + return FALSE; + } } /* pfkey_extensions_init + pfkey_build + pfkey_msg_hdr_build */ @@ -501,10 +499,10 @@ pfkey_msg_start(u_int8_t msg_type , 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); + pfkey_extensions_init(extensions); + return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type + , satype, 0, ++pfkey_seq, pid) + , description, text_said, extensions); } /* pfkey_build + pfkey_address_build */ @@ -515,15 +513,15 @@ pfkeyext_address(u_int16_t exttype , const char *text_said , struct sadb_ext *extensions[SADB_EXT_MAX + 1]) { - /* the following variable is only needed to silence - * a warning caused by the fact that the argument - * to sockaddrof is NOT pointer to const! - */ - ip_address t = *address; - - return pfkey_build(pfkey_address_build(extensions + exttype - , exttype, 0, 0, sockaddrof(&t)) - , description, text_said, extensions); + /* the following variable is only needed to silence + * a warning caused by the fact that the argument + * to sockaddrof is NOT pointer to const! + */ + ip_address t = *address; + + return pfkey_build(pfkey_address_build(extensions + exttype + , exttype, 0, 0, sockaddrof(&t)) + , description, text_said, extensions); } /* pfkey_build + pfkey_x_protocol_build */ @@ -533,10 +531,10 @@ pfkeyext_protocol(int transport_proto , const char *text_said , struct sadb_ext *extensions[SADB_EXT_MAX + 1]) { - return (transport_proto == 0)? TRUE - : pfkey_build( - pfkey_x_protocol_build(extensions + SADB_X_EXT_PROTOCOL, transport_proto) - , description, text_said, extensions); + return (transport_proto == 0)? TRUE + : pfkey_build( + pfkey_x_protocol_build(extensions + SADB_X_EXT_PROTOCOL, transport_proto) + , description, text_said, extensions); } @@ -551,376 +549,376 @@ finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1] , 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; + struct sadb_msg *pfkey_msg; + bool success = TRUE; + int error; - DBG(DBG_KLIPS, - 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)); + error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN); - if (!no_klips) + if (error != 0) { - 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); - } + 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; - /* if we were compiled with debugging, but we haven't already - * dumped the KLIPS command, do so. - */ -#ifdef DEBUG - if ((cur_debugging & DBG_KLIPS) == 0) - DBG_dump(NULL, (void *) pfkey_msg, len); -#endif - } - else - { - /* Check response from KLIPS. - * 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; + DBG(DBG_KLIPS, + 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)); - 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 - , "FreeS/WAN 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) + if (!no_klips) { - /* KLIPS 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; + 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 KLIPS command, do so. + */ +#ifdef DEBUG + if ((cur_debugging & DBG_KLIPS) == 0) + DBG_dump(NULL, (void *) pfkey_msg, len); +#endif + } + else + { + /* Check response from KLIPS. + * 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 + , "FreeS/WAN 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) + { + /* KLIPS 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; + } + } } - } } - } - /* all paths must exit this way to free resources */ - pfkey_extensions_free(extensions); - pfkey_msg_free(&pfkey_msg); - return success; + /* all paths must exit this way to free resources */ + pfkey_extensions_free(extensions); + pfkey_msg_free(&pfkey_msg); + return success; } /* register SA types that can be negotiated */ 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 KLIPS support for %s", satypename); - } - else - { - kernel_ops->pfkey_register_response(&pfb.msg); - DBG(DBG_KLIPS, - DBG_log("%s registered with kernel.", 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 KLIPS support for %s", satypename); + } + else + { + kernel_ops->pfkey_register_response(&pfb.msg); + DBG(DBG_KLIPS, + DBG_log("%s registered with kernel.", satypename)); + } } static void klips_pfkey_register(void) { - pfkey_register_proto(SADB_SATYPE_AH, "AH"); - pfkey_register_proto(SADB_SATYPE_ESP, "ESP"); - can_do_IPcomp = FALSE; /* until we get a response from KLIPS */ - pfkey_register_proto(SADB_X_SATYPE_COMP, "IPCOMP"); - pfkey_register_proto(SADB_X_SATYPE_IPIP, "IPIP"); + pfkey_register_proto(SADB_SATYPE_AH, "AH"); + pfkey_register_proto(SADB_SATYPE_ESP, "ESP"); + can_do_IPcomp = FALSE; /* until we get a response from KLIPS */ + pfkey_register_proto(SADB_X_SATYPE_COMP, "IPCOMP"); + pfkey_register_proto(SADB_X_SATYPE_IPIP, "IPIP"); } static bool pfkey_raw_eroute(const ip_address *this_host - , const ip_subnet *this_client - , const ip_address *that_host - , const ip_subnet *that_client - , ipsec_spi_t spi - , unsigned int satype - , unsigned int transport_proto - , const struct pfkey_proto_info *proto_info UNUSED - , time_t use_lifetime UNUSED - , unsigned int op - , const char *text_said) + , const ip_subnet *this_client + , const ip_address *that_host + , const ip_subnet *that_client + , ipsec_spi_t spi + , unsigned int satype + , unsigned int transport_proto + , const struct pfkey_proto_info *proto_info UNUSED + , time_t use_lifetime UNUSED + , unsigned int op + , const char *text_said) { - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - ip_address - sflow_ska, - dflow_ska, - smask_ska, - dmask_ska; - int sport = ntohs(portof(&this_client->addr)); - int dport = ntohs(portof(&that_client->addr)); - - networkof(this_client, &sflow_ska); - maskof(this_client, &smask_ska); - setportof(sport ? ~0:0, &smask_ska); - - networkof(that_client, &dflow_ska); - maskof(that_client, &dmask_ska); - setportof(dport ? ~0:0, &dmask_ska); - - if (!pfkey_msg_start(op & ERO_MASK, satype - , "pfkey_msg_hdr flow", text_said, extensions)) - { - return FALSE; - } - - if (op != ERO_DELETE) - { - if (!(pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] - , SADB_EXT_SA - , spi /* in network order */ - , 0, 0, 0, 0, op >> ERO_FLAG_SHIFT) - , "pfkey_sa add flow", text_said, extensions) - - && pfkeyext_address(SADB_EXT_ADDRESS_SRC, this_host - , "pfkey_addr_s add flow", text_said, extensions) - - && pfkeyext_address(SADB_EXT_ADDRESS_DST, that_host - , "pfkey_addr_d add flow", text_said - , extensions))) + struct sadb_ext *extensions[SADB_EXT_MAX + 1]; + ip_address + sflow_ska, + dflow_ska, + smask_ska, + dmask_ska; + int sport = ntohs(portof(&this_client->addr)); + int dport = ntohs(portof(&that_client->addr)); + + networkof(this_client, &sflow_ska); + maskof(this_client, &smask_ska); + setportof(sport ? ~0:0, &smask_ska); + + networkof(that_client, &dflow_ska); + maskof(that_client, &dmask_ska); + setportof(dport ? ~0:0, &dmask_ska); + + if (!pfkey_msg_start(op & ERO_MASK, satype + , "pfkey_msg_hdr flow", text_said, extensions)) { - return FALSE; + return FALSE; } - } - if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_FLOW, &sflow_ska - , "pfkey_addr_sflow", text_said, extensions)) - { - return FALSE; - } + if (op != ERO_DELETE) + { + if (!(pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] + , SADB_EXT_SA + , spi /* in network order */ + , 0, 0, 0, 0, op >> ERO_FLAG_SHIFT) + , "pfkey_sa add flow", text_said, extensions) + + && pfkeyext_address(SADB_EXT_ADDRESS_SRC, this_host + , "pfkey_addr_s add flow", text_said, extensions) + + && pfkeyext_address(SADB_EXT_ADDRESS_DST, that_host + , "pfkey_addr_d add flow", text_said + , extensions))) + { + return FALSE; + } + } - if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_FLOW, &dflow_ska - , "pfkey_addr_dflow", text_said, extensions)) - { - return FALSE; - } + if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_FLOW, &sflow_ska + , "pfkey_addr_sflow", text_said, extensions)) + { + return FALSE; + } - if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_MASK, &smask_ska - , "pfkey_addr_smask", text_said, extensions)) - { - return FALSE; - } + if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_FLOW, &dflow_ska + , "pfkey_addr_dflow", text_said, extensions)) + { + return FALSE; + } - if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_MASK, &dmask_ska - , "pfkey_addr_dmask", text_said, extensions)) - { - return FALSE; - } + if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_MASK, &smask_ska + , "pfkey_addr_smask", text_said, extensions)) + { + return FALSE; + } - if (!pfkeyext_protocol(transport_proto - , "pfkey_x_protocol", text_said, extensions)) - { - return FALSE; - } + if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_MASK, &dmask_ska + , "pfkey_addr_dmask", text_said, extensions)) + { + return FALSE; + } + + if (!pfkeyext_protocol(transport_proto + , "pfkey_x_protocol", text_said, extensions)) + { + return FALSE; + } - return finish_pfkey_msg(extensions, "flow", text_said, NULL); + return finish_pfkey_msg(extensions, "flow", text_said, NULL); } static bool pfkey_add_sa(const struct kernel_sa *sa, bool replace) { - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - - return pfkey_msg_start(replace ? SADB_UPDATE : SADB_ADD, sa->satype - , "pfkey_msg_hdr Add SA", sa->text_said, extensions) - - && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] - , SADB_EXT_SA - , sa->spi /* in network order */ - , sa->replay_window, SADB_SASTATE_MATURE - , sa->authalg, sa->encalg ? sa->encalg: sa->compalg, 0) - , "pfkey_sa Add SA", sa->text_said, extensions) - - && pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src - , "pfkey_addr_s Add SA", sa->text_said, extensions) - - && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst - , "pfkey_addr_d Add SA", sa->text_said, extensions) - - && (sa->authkeylen == 0 - || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_AUTH] - , SADB_EXT_KEY_AUTH, sa->authkeylen * BITS_PER_BYTE - , sa->authkey) - , "pfkey_key_a Add SA", sa->text_said, extensions)) - - && (sa->enckeylen == 0 - || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_ENCRYPT] - , SADB_EXT_KEY_ENCRYPT, sa->enckeylen * BITS_PER_BYTE - , sa->enckey) - , "pfkey_key_e Add SA", sa->text_said, extensions)) - - && (sa->natt_type == 0 - || pfkey_build(pfkey_x_nat_t_type_build( - &extensions[SADB_X_EXT_NAT_T_TYPE], sa->natt_type), - "pfkey_nat_t_type Add ESP SA", sa->text_said, extensions)) - && (sa->natt_sport == 0 - || pfkey_build(pfkey_x_nat_t_port_build( - &extensions[SADB_X_EXT_NAT_T_SPORT], SADB_X_EXT_NAT_T_SPORT, - sa->natt_sport), "pfkey_nat_t_sport Add ESP SA", sa->text_said, - extensions)) - && (sa->natt_dport == 0 - || pfkey_build(pfkey_x_nat_t_port_build( - &extensions[SADB_X_EXT_NAT_T_DPORT], SADB_X_EXT_NAT_T_DPORT, - sa->natt_dport), "pfkey_nat_t_dport Add ESP SA", sa->text_said, - extensions)) - && (sa->natt_type == 0 || isanyaddr(sa->natt_oa) - || pfkeyext_address(SADB_X_EXT_NAT_T_OA, sa->natt_oa - , "pfkey_nat_t_oa Add ESP SA", sa->text_said, extensions)) - - && finish_pfkey_msg(extensions, "Add SA", sa->text_said, NULL); + struct sadb_ext *extensions[SADB_EXT_MAX + 1]; + + return pfkey_msg_start(replace ? SADB_UPDATE : SADB_ADD, sa->satype + , "pfkey_msg_hdr Add SA", sa->text_said, extensions) + + && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] + , SADB_EXT_SA + , sa->spi /* in network order */ + , sa->replay_window, SADB_SASTATE_MATURE + , sa->authalg, sa->encalg ? sa->encalg: sa->compalg, 0) + , "pfkey_sa Add SA", sa->text_said, extensions) + + && pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src + , "pfkey_addr_s Add SA", sa->text_said, extensions) + + && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst + , "pfkey_addr_d Add SA", sa->text_said, extensions) + + && (sa->authkeylen == 0 + || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_AUTH] + , SADB_EXT_KEY_AUTH, sa->authkeylen * BITS_PER_BYTE + , sa->authkey) + , "pfkey_key_a Add SA", sa->text_said, extensions)) + + && (sa->enckeylen == 0 + || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_ENCRYPT] + , SADB_EXT_KEY_ENCRYPT, sa->enckeylen * BITS_PER_BYTE + , sa->enckey) + , "pfkey_key_e Add SA", sa->text_said, extensions)) + + && (sa->natt_type == 0 + || pfkey_build(pfkey_x_nat_t_type_build( + &extensions[SADB_X_EXT_NAT_T_TYPE], sa->natt_type), + "pfkey_nat_t_type Add ESP SA", sa->text_said, extensions)) + && (sa->natt_sport == 0 + || pfkey_build(pfkey_x_nat_t_port_build( + &extensions[SADB_X_EXT_NAT_T_SPORT], SADB_X_EXT_NAT_T_SPORT, + sa->natt_sport), "pfkey_nat_t_sport Add ESP SA", sa->text_said, + extensions)) + && (sa->natt_dport == 0 + || pfkey_build(pfkey_x_nat_t_port_build( + &extensions[SADB_X_EXT_NAT_T_DPORT], SADB_X_EXT_NAT_T_DPORT, + sa->natt_dport), "pfkey_nat_t_dport Add ESP SA", sa->text_said, + extensions)) + && (sa->natt_type == 0 || isanyaddr(sa->natt_oa) + || pfkeyext_address(SADB_X_EXT_NAT_T_OA, sa->natt_oa + , "pfkey_nat_t_oa Add ESP SA", sa->text_said, extensions)) + + && finish_pfkey_msg(extensions, "Add SA", sa->text_said, NULL); } static bool pfkey_grp_sa(const struct kernel_sa *sa0, const struct kernel_sa *sa1) { - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; + struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - return pfkey_msg_start(SADB_X_GRPSA, sa1->satype - , "pfkey_msg_hdr group", sa1->text_said, extensions) + return pfkey_msg_start(SADB_X_GRPSA, sa1->satype + , "pfkey_msg_hdr group", sa1->text_said, extensions) - && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] - , SADB_EXT_SA - , sa1->spi /* in network order */ - , 0, 0, 0, 0, 0) - , "pfkey_sa group", sa1->text_said, extensions) + && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] + , SADB_EXT_SA + , sa1->spi /* in network order */ + , 0, 0, 0, 0, 0) + , "pfkey_sa group", sa1->text_said, extensions) - && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa1->dst - , "pfkey_addr_d group", sa1->text_said, extensions) + && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa1->dst + , "pfkey_addr_d group", sa1->text_said, extensions) - && pfkey_build(pfkey_x_satype_build(&extensions[SADB_X_EXT_SATYPE2] - , sa0->satype) - , "pfkey_satype group", sa0->text_said, extensions) + && pfkey_build(pfkey_x_satype_build(&extensions[SADB_X_EXT_SATYPE2] + , sa0->satype) + , "pfkey_satype group", sa0->text_said, extensions) - && pfkey_build(pfkey_sa_build(&extensions[SADB_X_EXT_SA2] - , SADB_X_EXT_SA2 - , sa0->spi /* in network order */ - , 0, 0, 0, 0, 0) - , "pfkey_sa2 group", sa0->text_said, extensions) + && pfkey_build(pfkey_sa_build(&extensions[SADB_X_EXT_SA2] + , SADB_X_EXT_SA2 + , sa0->spi /* in network order */ + , 0, 0, 0, 0, 0) + , "pfkey_sa2 group", sa0->text_said, extensions) - && pfkeyext_address(SADB_X_EXT_ADDRESS_DST2, sa0->dst - , "pfkey_addr_d2 group", sa0->text_said, extensions) + && pfkeyext_address(SADB_X_EXT_ADDRESS_DST2, sa0->dst + , "pfkey_addr_d2 group", sa0->text_said, extensions) - && finish_pfkey_msg(extensions, "group", sa1->text_said, NULL); + && finish_pfkey_msg(extensions, "group", sa1->text_said, NULL); } static bool pfkey_del_sa(const struct kernel_sa *sa) { - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; + struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - return pfkey_msg_start(SADB_DELETE, proto2satype(sa->proto) - , "pfkey_msg_hdr delete SA", sa->text_said, extensions) + return pfkey_msg_start(SADB_DELETE, proto2satype(sa->proto) + , "pfkey_msg_hdr delete SA", sa->text_said, extensions) - && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] - , SADB_EXT_SA - , sa->spi /* in host order */ - , 0, SADB_SASTATE_MATURE, 0, 0, 0) - , "pfkey_sa delete SA", sa->text_said, extensions) + && pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA] + , SADB_EXT_SA + , sa->spi /* in host order */ + , 0, SADB_SASTATE_MATURE, 0, 0, 0) + , "pfkey_sa delete SA", sa->text_said, extensions) - && pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src - , "pfkey_addr_s delete SA", sa->text_said, extensions) + && pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src + , "pfkey_addr_s delete SA", sa->text_said, extensions) - && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst - , "pfkey_addr_d delete SA", sa->text_said, extensions) + && pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst + , "pfkey_addr_d delete SA", sa->text_said, extensions) - && finish_pfkey_msg(extensions, "Delete SA", sa->text_said, NULL); + && finish_pfkey_msg(extensions, "Delete SA", sa->text_said, NULL); } void pfkey_close(void) { - while (pfkey_iq_head != NULL) - { - pfkey_item *it = pfkey_iq_head; + while (pfkey_iq_head != NULL) + { + pfkey_item *it = pfkey_iq_head; - pfkey_iq_head = it->next; - pfree(it); - } + pfkey_iq_head = it->next; + free(it); + } - close(pfkeyfd); - pfkeyfd = NULL_FD; + close(pfkeyfd); + pfkeyfd = NULL_FD; } const struct kernel_ops klips_kernel_ops = { - type: KERNEL_TYPE_KLIPS, - async_fdp: &pfkeyfd, - - pfkey_register: klips_pfkey_register, - pfkey_register_response: klips_pfkey_register_response, - process_queue: pfkey_dequeue, - process_msg: pfkey_event, - raw_eroute: pfkey_raw_eroute, - add_sa: pfkey_add_sa, - grp_sa: pfkey_grp_sa, - del_sa: pfkey_del_sa, - get_sa: NULL, - get_spi: NULL, - inbound_eroute: FALSE, - policy_lifetime: FALSE, - init: NULL + type: KERNEL_TYPE_KLIPS, + async_fdp: &pfkeyfd, + + pfkey_register: klips_pfkey_register, + pfkey_register_response: klips_pfkey_register_response, + process_queue: pfkey_dequeue, + process_msg: pfkey_event, + raw_eroute: pfkey_raw_eroute, + add_sa: pfkey_add_sa, + grp_sa: pfkey_grp_sa, + del_sa: pfkey_del_sa, + get_sa: NULL, + get_spi: NULL, + inbound_eroute: FALSE, + policy_lifetime: FALSE, + init: NULL }; #endif /* KLIPS */ diff --git a/src/pluto/kernel_pfkey.h b/src/pluto/kernel_pfkey.h index 23ac982e8..ad20a5888 100644 --- a/src/pluto/kernel_pfkey.h +++ b/src/pluto/kernel_pfkey.h @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: kernel_pfkey.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifdef KLIPS diff --git a/src/pluto/keys.c b/src/pluto/keys.c index 1aed7a63f..6dfbd6732 100644 --- a/src/pluto/keys.c +++ b/src/pluto/keys.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: keys.c 3738 2008-04-02 19:04:45Z andreas $ */ #include <stddef.h> @@ -25,33 +23,34 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ +#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ #include <sys/queue.h> #include <glob.h> #ifndef GLOB_ABORTED -# define GLOB_ABORTED GLOB_ABEND /* fix for old versions */ +# define GLOB_ABORTED GLOB_ABEND /* fix for old versions */ #endif #include <freeswan.h> -#include <ipsec_policy.h> + +#include <library.h> +#include <asn1/asn1.h> #include "constants.h" #include "defs.h" -#include "mp_defs.h" #include "id.h" #include "x509.h" -#include "pgp.h" +#include "pgpcert.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 "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 "whack.h" /* for RC_LOG_SERIOUS */ #include "timer.h" #include "fetch.h" #include "xauth.h" @@ -61,77 +60,34 @@ const char *shared_secrets_file = SHARED_SECRETS_FILE; typedef struct id_list id_list_t; struct id_list { - struct id id; - id_list_t *next; + struct id id; + id_list_t *next; }; typedef struct secret secret_t; struct secret { - id_list_t *ids; - enum PrivateKeyKind kind; - union { - chunk_t preshared_secret; - RSA_private_key_t RSA_private_key; - xauth_t xauth_secret; - smartcard_t *smartcard; - } u; - secret_t *next; + id_list_t *ids; + enum PrivateKeyKind kind; + union { + chunk_t preshared_secret; + xauth_t xauth_secret; + private_key_t *private_key; + smartcard_t *smartcard; + } u; + secret_t *next; }; -static pubkey_t* -allocate_RSA_public_key(const cert_t cert) -{ - pubkey_t *pk = alloc_thing(pubkey_t, "pubkey"); - chunk_t e = empty_chunk, n = empty_chunk; - - switch (cert.type) - { - case CERT_PGP: - e = cert.u.pgp->publicExponent; - n = cert.u.pgp->modulus; - break; - case CERT_X509_SIGNATURE: - e = cert.u.x509->publicExponent; - n = cert.u.x509->modulus; - break; - default: - plog("RSA public key allocation error"); - } - - init_RSA_public_key(&pk->u.rsa, e, n); - DBG(DBG_RAW, - RSA_show_public_key(&pk->u.rsa) - ) - - pk->alg = PUBKEY_ALG_RSA; - pk->id = empty_id; - pk->issuer = empty_chunk; - pk->serial = empty_chunk; - - return pk; -} - /* * free a public key struct */ -static void -free_public_key(pubkey_t *pk) +static void free_public_key(pubkey_t *pk) { - free_id_content(&pk->id); - freeanychunk(pk->issuer); - freeanychunk(pk->serial); - - /* algorithm-specific freeing */ - switch (pk->alg) - { - case PUBKEY_ALG_RSA: - free_RSA_public_content(&pk->u.rsa); - break; - default: - bad_case(pk->alg); - } - pfree(pk); + DESTROY_IF(pk->public_key); + free_id_content(&pk->id); + free(pk->issuer.ptr); + free(pk->serial.ptr); + free(pk); } secret_t *secrets = NULL; @@ -140,227 +96,215 @@ secret_t *secrets = NULL; * me and the peer. We match the Id (if none, the IP address). * Failure is indicated by a NULL. */ -static const secret_t * -get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym) +static const secret_t* get_secret(const struct connection *c, + enum PrivateKeyKind kind, bool asym) { - enum { /* bits */ - match_default = 01, - match_him = 02, - match_me = 04 - }; - - unsigned int best_match = 0; - secret_t *best = NULL; - secret_t *s; - const struct id *my_id = &c->spd.this.id - , *his_id = &c->spd.that.id; - struct id rw_id; - - /* is there a certificate assigned to this connection? */ - if (kind == PPK_RSA && c->spd.this.cert.type != CERT_NONE) - { - pubkey_t *my_public_key = allocate_RSA_public_key(c->spd.this.cert); - - for (s = secrets; s != NULL; s = s->next) + enum { /* bits */ + match_default = 0x01, + match_him = 0x02, + match_me = 0x04 + }; + + unsigned int best_match = 0; + secret_t *best = NULL; + secret_t *s; + const struct id *my_id = &c->spd.this.id + , *his_id = &c->spd.that.id; + struct id rw_id; + + /* is there a certificate assigned to this connection? */ + if (kind == PPK_PUBKEY && c->spd.this.cert.type != CERT_NONE) { - if (s->kind == kind && - same_RSA_public_key(&s->u.RSA_private_key.pub, &my_public_key->u.rsa)) - { - best = s; - break; /* we have found the private key - no sense in searching further */ - } - } - free_public_key(my_public_key); - return best; - } - - if (his_id_was_instantiated(c)) - { - /* roadwarrior: replace him with 0.0.0.0 */ - rw_id.kind = c->spd.that.id.kind; - rw_id.name = empty_chunk; - happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr)); - his_id = &rw_id; - } - else if (kind == PPK_PSK - && (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK)) - && ((c->kind == CK_TEMPLATE && c->spd.that.id.kind == ID_NONE) || - (c->kind == CK_INSTANCE && id_is_ipaddr(&c->spd.that.id)))) - { - /* roadwarrior: replace him with 0.0.0.0 */ - rw_id.kind = ID_IPV4_ADDR; - happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr)); - his_id = &rw_id; - } - - for (s = secrets; s != NULL; s = s->next) - { - if (s->kind == kind) - { - unsigned int match = 0; + public_key_t *pub_key = cert_get_public_key(c->spd.this.cert); - if (s->ids == NULL) - { - /* a default (signified by lack of ids): - * accept if no more specific match found - */ - match = match_default; - } - else - { - /* check if both ends match ids */ - id_list_t *i; - - for (i = s->ids; i != NULL; i = i->next) + for (s = secrets; s != NULL; s = s->next) { - if (same_id(my_id, &i->id)) - match |= match_me; - - if (same_id(his_id, &i->id)) - match |= match_him; + if (s->kind == kind && + s->u.private_key->belongs_to(s->u.private_key, pub_key)) + { + best = s; + break; /* we have found the private key - no sense in searching further */ + } } + return best; + } - /* 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->next == NULL) - 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 (!asym) - 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 PPK_PSK: - same = s->u.preshared_secret.len == best->u.preshared_secret.len - && memcmp(s->u.preshared_secret.ptr, best->u.preshared_secret.ptr, s->u.preshared_secret.len) == 0; - break; - case PPK_RSA: - /* Dirty trick: since we have code to compare - * RSA public keys, but not private keys, we - * make the assumption that equal public keys - * mean equal private keys. This ought to work. - */ - same = same_RSA_public_key(&s->u.RSA_private_key.pub - , &best->u.RSA_private_key.pub); - 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) + if (his_id_was_instantiated(c)) + { + /* roadwarrior: replace him with 0.0.0.0 */ + rw_id.kind = c->spd.that.id.kind; + rw_id.name = chunk_empty; + happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr)); + his_id = &rw_id; + } + else if (kind == PPK_PSK + && (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK)) + && ((c->kind == CK_TEMPLATE && c->spd.that.id.kind == ID_ANY) || + (c->kind == CK_INSTANCE && id_is_ipaddr(&c->spd.that.id)))) + { + /* roadwarrior: replace him with 0.0.0.0 */ + rw_id.kind = ID_IPV4_ADDR; + happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr)); + his_id = &rw_id; + } + + for (s = secrets; s != NULL; s = s->next) + { + if (s->kind == kind) { - /* this is the best match so far */ - best_match = match; - best = s; + unsigned int match = 0; + + if (s->ids == NULL) + { + /* a default (signified by lack of ids): + * accept if no more specific match found + */ + match = match_default; + } + else + { + /* check if both ends match ids */ + id_list_t *i; + + for (i = s->ids; i != NULL; i = i->next) + { + if (same_id(my_id, &i->id)) + { + match |= match_me; + } + if (same_id(his_id, &i->id)) + { + match |= match_him; + } + } + + /* 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->next == NULL) + { + 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 (!asym) + { + 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 PPK_PSK: + same = s->u.preshared_secret.len == best->u.preshared_secret.len + && memeq(s->u.preshared_secret.ptr, best->u.preshared_secret.ptr, s->u.preshared_secret.len); + break; + case PPK_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; + 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 struct connection *c) +const chunk_t* get_preshared_secret(const struct connection *c) { - const secret_t *s = get_secret(c, PPK_PSK, FALSE); + const secret_t *s = get_secret(c, PPK_PSK, FALSE); - 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; + 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 an RSA private key matching an RSA public - * key contained in an X.509 or OpenPGP certificate +/* 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) +bool has_private_key(cert_t cert) { - secret_t *s; - bool has_key = FALSE; - pubkey_t *pubkey = allocate_RSA_public_key(cert); - - for (s = secrets; s != NULL; s = s->next) - { - if (s->kind == PPK_RSA && - same_RSA_public_key(&s->u.RSA_private_key.pub, &pubkey->u.rsa)) + secret_t *s; + bool has_key = FALSE; + public_key_t *pub_key = cert_get_public_key(cert); + + for (s = secrets; s != NULL; s = s->next) { - has_key = TRUE; - break; + if (s->kind == PPK_PUBKEY && + s->u.private_key->belongs_to(s->u.private_key, pub_key)) + { + has_key = TRUE; + break; + } } - } - free_public_key(pubkey); - return has_key; + return has_key; } /* - * get the matching RSA private key belonging to a given X.509 certificate + * get the matching private key belonging to a given X.509 certificate */ -const RSA_private_key_t* -get_x509_private_key(const x509cert_t *cert) +private_key_t* get_x509_private_key(const x509cert_t *cert) { - secret_t *s; - const RSA_private_key_t *pri = NULL; - const cert_t c = {CERT_X509_SIGNATURE, {(x509cert_t*)cert}}; - - pubkey_t *pubkey = allocate_RSA_public_key(c); + secret_t *s; - for (s = secrets; s != NULL; s = s->next) - { - if (s->kind == PPK_RSA && - same_RSA_public_key(&s->u.RSA_private_key.pub, &pubkey->u.rsa)) + for (s = secrets; s != NULL; s = s->next) { - pri = &s->u.RSA_private_key; - break; + if (s->kind == PPK_PUBKEY && + s->u.private_key->belongs_to(s->u.private_key, cert->public_key)) + { + return s->u.private_key; + } } - } - free_public_key(pubkey); - return pri; + return NULL; } -/* find the appropriate RSA private key (see get_secret). +/* find the appropriate private key (see get_secret). * Failure is indicated by a NULL pointer. */ -const RSA_private_key_t * -get_RSA_private_key(const struct connection *c) +private_key_t* get_private_key(const struct connection *c) { - const secret_t *s = get_secret(c, PPK_RSA, TRUE); + const secret_t *s = get_secret(c, PPK_PUBKEY, TRUE); - return s == NULL? NULL : &s->u.RSA_private_key; + return s == NULL? NULL : s->u.private_key; } /* digest a secrets file @@ -403,1100 +347,1071 @@ get_RSA_private_key(const struct connection *c) */ /* parse PSK from file */ -static err_t -process_psk_secret(chunk_t *psk) +static err_t process_psk_secret(chunk_t *psk) { - err_t ugh = NULL; - - if (*tok == '"' || *tok == '\'') - { - clonetochunk(*psk, tok+1, flp->cur - tok - 2, "PSK"); - (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) + err_t ugh = NULL; + + if (*tok == '"' || *tok == '\'') { - /* ttodata didn't like PSK data */ - ugh = builddiag("PSK data malformed (%s): %s", ugh, tok); + chunk_t secret = { tok + 1, flp->cur - tok -2 }; + + *psk = chunk_clone(secret); + (void) shift(); } else { - clonetochunk(*psk, buf, sz, "PSK"); - (void) shift(); + 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; + return ugh; } -/* Parse fields of RSA private key. - * A braced list of keyword and value pairs. - * At the moment, each field is required, in order. - * The fields come from BIND 8.2's representation +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. + * Conversion into ASN.1 DER encoded PKCS#1 representation. */ -static err_t -process_rsa_secret(RSA_private_key_t *rsak) +static err_t process_rsa_secret(private_key_t **key) { - char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */ - const struct fld *p; - - /* save bytes of Modulus and PublicExponent for keyid calculation */ - unsigned char ebytes[sizeof(buf)]; - unsigned char *eb_next = ebytes; - chunk_t pub_bytes[2]; - chunk_t *pb_next = &pub_bytes[0]; - - for (p = RSA_private_field; p < &RSA_private_field[RSA_PRIVATE_FIELD_ELEMENTS]; p++) - { - size_t sz; + chunk_t asn1_chunk[countof(rsa_private_key_part_names)]; + chunk_t pkcs1_chunk; + 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, len = 0; err_t ugh; - if (!shift()) + for (part = RSA_PART_MODULUS; part <= RSA_PART_COEFFICIENT; part++) { - return "premature end of RSA key"; + chunk_t rsa_private_key_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); + part++; + goto end; + } + rsa_private_key_part = chunk_create(buf, sz); + asn1_chunk[part] = asn1_integer("c", rsa_private_key_part); + len += asn1_chunk[part].len; } - else if (!tokeqword(p->name)) + + /* 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("}")) { - return builddiag("%s keyword not found where expected in RSA key" - , p->name); + ugh = "malformed end of RSA private key -- indented '}' required"; + goto end; } - else if (!(shift() - && (!tokeq(":") || shift()))) /* ignore optional ":" */ + if (shift()) { - return "premature end of RSA key"; + ugh = "malformed end of RSA private key -- unexpected token after '}'"; + goto end; } - else if (NULL != (ugh = ttodatav(tok, flp->cur - tok - , 0, buf, sizeof(buf), &sz, diag_space, sizeof(diag_space) - , TTODATAV_SPACECOUNTS))) + + pkcs1_chunk = asn1_wrap(ASN1_SEQUENCE, "ccccccccc", + ASN1_INTEGER_0, + asn1_chunk[RSA_PART_MODULUS], + asn1_chunk[RSA_PART_PUBLIC_EXPONENT], + asn1_chunk[RSA_PART_PRIVATE_EXPONENT], + asn1_chunk[RSA_PART_PRIME1], + asn1_chunk[RSA_PART_PRIME2], + asn1_chunk[RSA_PART_EXPONENT1], + asn1_chunk[RSA_PART_EXPONENT2], + asn1_chunk[RSA_PART_COEFFICIENT]); + + *key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + BUILD_BLOB_ASN1_DER, pkcs1_chunk, + BUILD_END); + free(pkcs1_chunk.ptr); + if (*key == NULL) { - /* in RSA key, ttodata didn't like */ - return builddiag("RSA data malformed (%s): %s", ugh, tok); + ugh = "parsing of RSA private key failed"; } - else + +end: + /* clean up and return */ + for (p = RSA_PART_MODULUS ; p < part; p++) { - MP_INT *n = (MP_INT *) ((char *)rsak + p->offset); - - n_to_mpz(n, buf, sz); - if (pb_next < &pub_bytes[elemsof(pub_bytes)]) - { - if (eb_next - ebytes + sz > sizeof(ebytes)) - return "public key takes too many bytes"; - - setchunk(*pb_next, eb_next, sz); - memcpy(eb_next, buf, sz); - eb_next += sz; - pb_next++; - } -#if 0 /* debugging info that compromises security */ - { - size_t sz = mpz_sizeinbase(n, 16); - char buf[RSA_MAX_OCTETS * 2 + 2]; /* ought to be big enough */ - - passert(sz <= sizeof(buf)); - mpz_get_str(buf, 16, n); - - loglog(RC_LOG_SERIOUS, "%s: %s", p->name, buf); - } -#endif + free(asn1_chunk[p].ptr); } - } - - /* 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("}")) - { - return "malformed end of RSA private key -- indented '}' required"; - } - else if (shift()) - { - return "malformed end of RSA private key -- unexpected token after '}'"; - } - else - { - unsigned bits = mpz_sizeinbase(&rsak->pub.n, 2); - - rsak->pub.k = (bits + BITS_PER_BYTE - 1) / BITS_PER_BYTE; - rsak->pub.keyid[0] = '\0'; /* in case of splitkeytoid failure */ - splitkeytoid(pub_bytes[1].ptr, pub_bytes[1].len - , pub_bytes[0].ptr, pub_bytes[0].len - , rsak->pub.keyid, sizeof(rsak->pub.keyid)); - return RSA_private_key_sanity(rsak); - } + return ugh; } -/* process rsa key file protected with optional passphrase which can either be +/** + * 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_rsa_keyfile(RSA_private_key_t *rsak, int whackfd) +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; + char filename[BUF_LEN]; + prompt_pass_t pass; - /* we expect the filename of a PKCS#1 private key file */ + memset(filename,'\0', BUF_LEN); + memset(pass.secret,'\0', sizeof(pass.secret)); + pass.prompt = FALSE; + pass.fd = whackfd; - if (*tok == '"' || *tok == '\'') /* quoted filename */ - memcpy(filename, tok+1, flp->cur - tok - 2); - else - memcpy(filename, tok, flp->cur - tok); + /* we expect the filename of a PKCS#1 private key file */ - if (shift()) - { - /* we expect an appended passphrase or passphrase prompt*/ - if (tokeqword("%prompt")) - { - if (pass.fd == NULL_FD) - return "RSA private key file -- enter passphrase using 'ipsec secrets'"; - pass.prompt = TRUE; - } + if (*tok == '"' || *tok == '\'') /* quoted filename */ + memcpy(filename, tok+1, flp->cur - tok - 2); else + memcpy(filename, tok, flp->cur - tok); + + if (shift()) { - char *passphrase = tok; - size_t len = flp->cur - passphrase; - - if (*tok == '"' || *tok == '\'') /* quoted passphrase */ - { - passphrase++; - len -= 2; - } - if (len > PROMPT_PASS_LEN) - return "RSA private key file -- passphrase exceeds 64 characters"; - - memcpy(pass.secret, passphrase, len); + /* 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"; + } } - if (shift()) - return "RSA private key file -- unexpected token after passphrase"; - } - return load_rsa_private_key(filename, &pass, rsak); + *key = load_private_key(filename, &pass, type); + + return key ? NULL : "Private key file -- could not be loaded"; } -/* - * process xauth secret read from ipsec.secrets +/** + * Process xauth secret read from ipsec.secrets */ -static err_t -process_xauth(secret_t *s) +static err_t process_xauth(secret_t *s) { - chunk_t user_name; - - s->kind = PPK_XAUTH; - - if (!shift()) - return "missing xauth user name"; - if (*tok == '"' || *tok == '\'') /* quoted user name */ - { - user_name.ptr = tok + 1; - user_name.len = flp->cur - tok - 2; - } - else - { - user_name.ptr = tok; - user_name.len = flp->cur - tok; - } - plog(" loaded xauth credentials of user '%.*s'" - , user_name.len - , user_name.ptr); - clonetochunk(s->u.xauth_secret.user_name - , user_name.ptr, user_name.len, "xauth user name"); - - if (!shift()) - return "missing xauth user password"; - return process_psk_secret(&s->u.xauth_secret.user_password); + chunk_t user_name; + + s->kind = PPK_XAUTH; + + if (!shift()) + return "missing xauth user name"; + if (*tok == '"' || *tok == '\'') /* quoted user name */ + { + user_name.ptr = tok + 1; + user_name.len = flp->cur - tok - 2; + } + else + { + user_name.ptr = tok; + user_name.len = flp->cur - tok; + } + plog(" loaded xauth credentials of user '%.*s'" + , user_name.len + , user_name.ptr); + s->u.xauth_secret.user_name = chunk_clone(user_name); + + if (!shift()) + return "missing xauth user password"; + return process_psk_secret(&s->u.xauth_secret.user_password); } -/* get XAUTH secret from chained secrets lists +/** + * Get XAUTH secret from chained secrets lists * only one entry is currently supported */ -static bool -xauth_get_secret(xauth_t *xauth_secret) +static bool xauth_get_secret(xauth_t *xauth_secret) { - secret_t *s; - bool found = FALSE; + secret_t *s; + bool found = FALSE; - for (s = secrets; s != NULL; s = s->next) - { - if (s->kind == PPK_XAUTH) + for (s = secrets; s != NULL; s = s->next) { - if (found) - { - plog("found multiple xauth secrets - first selected"); - } - else - { - found = TRUE; - *xauth_secret = s->u.xauth_secret; - } + if (s->kind == PPK_XAUTH) + { + if (found) + { + plog("found multiple xauth secrets - first selected"); + } + else + { + found = TRUE; + *xauth_secret = s->u.xauth_secret; + } + } } - } - return found; + return found; } -/* +/** * find a matching secret */ -static bool -xauth_verify_secret(const xauth_peer_t *peer, const xauth_t *xauth_secret) +static bool xauth_verify_secret(const xauth_peer_t *peer, + const xauth_t *xauth_secret) { - bool found = FALSE; - secret_t *s; + bool found = FALSE; + secret_t *s; - for (s = secrets; s != NULL; s = s->next) - { - if (s->kind == PPK_XAUTH) + for (s = secrets; s != NULL; s = s->next) { - if (!same_chunk(xauth_secret->user_name, s->u.xauth_secret.user_name)) - continue; - found = TRUE; - if (same_chunk(xauth_secret->user_password, s->u.xauth_secret.user_password)) - return TRUE; + if (s->kind == PPK_XAUTH) + { + if (!chunk_equals(xauth_secret->user_name, s->u.xauth_secret.user_name)) + { + continue; + } + found = TRUE; + if (chunk_equals(xauth_secret->user_password, s->u.xauth_secret.user_password)) + { + return TRUE; + } + } } - } - plog("xauth user '%.*s' %s" - , xauth_secret->user_name.len, xauth_secret->user_name.ptr - , found? "sent wrong password":"not found"); - return FALSE; + plog("xauth user '%.*s' %s" + , xauth_secret->user_name.len, xauth_secret->user_name.ptr + , found? "sent wrong password":"not found"); + return FALSE; } -/* +/** * the global xauth_module struct is defined here */ xauth_module_t xauth_module; -/* - * assign the default xauth functions to any null function pointers +/** + * Assign the default xauth functions to any null function pointers */ -void -xauth_defaults(void) +void xauth_defaults(void) { - if (xauth_module.get_secret == NULL) - { - DBG(DBG_CONTROL, - DBG_log("xauth module: using default get_secret() function") - ) - xauth_module.get_secret = xauth_get_secret; - } - if (xauth_module.verify_secret == NULL) - { - DBG(DBG_CONTROL, - DBG_log("xauth module: using default verify_secret() function") - ) - xauth_module.verify_secret = xauth_verify_secret; - } + if (xauth_module.get_secret == NULL) + { + DBG(DBG_CONTROL, + DBG_log("xauth module: using default get_secret() function") + ) + xauth_module.get_secret = xauth_get_secret; + } + if (xauth_module.verify_secret == NULL) + { + DBG(DBG_CONTROL, + DBG_log("xauth module: using default verify_secret() function") + ) + xauth_module.verify_secret = xauth_verify_secret; + } }; -/* - * process pin read from ipsec.secrets or prompted for it using whack +/** + * Process pin read from ipsec.secrets or prompted for it using whack */ -static err_t -process_pin(secret_t *s, int whackfd) +static err_t process_pin(secret_t *s, int whackfd) { - smartcard_t *sc; - const char *pin_status = "no pin"; - - s->kind = PPK_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"; + smartcard_t *sc; + const char *pin_status = "no pin"; + + s->kind = PPK_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 - pin_status = "pin entry via prompt"; - } - else if (tokeqword("%pinpad")) - { - shift(); - /* pin will be entered via pin pad during verification */ - clonetochunk(sc->pin, "", 0, "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"; - } + { + /* 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]; + { + char buf[BUF_LEN]; - if (sc->any_slot) - snprintf(buf, BUF_LEN, "any slot"); - else - snprintf(buf, BUF_LEN, "slot: %lu", sc->slot); + 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); - } + 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!"); + plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!"); #endif - return NULL; + return NULL; } -static void -log_psk(secret_t *s) +static void log_psk(secret_t *s) { - int n = 0; - char buf[BUF_LEN]; - id_list_t *id_list = s->ids; - - if (id_list == NULL) - { - n = snprintf(buf, BUF_LEN, "%%any"); - } - else - { - do + int n = 0; + char buf[BUF_LEN]; + id_list_t *id_list = s->ids; + + if (id_list == NULL) { - n += idtoa(&id_list->id, buf + n, BUF_LEN - n); - if (n >= BUF_LEN) - { - n = BUF_LEN - 1; - break; - } - else if (n < BUF_LEN - 1) - { - n += snprintf(buf + n, BUF_LEN - n, " "); - } - id_list = id_list->next; + n = snprintf(buf, BUF_LEN, "%%any"); } - while (id_list); - } - plog(" loaded shared key for %.*s", n, buf); + else + { + do + { + n += idtoa(&id_list->id, buf + n, BUF_LEN - n); + if (n >= BUF_LEN) + { + n = BUF_LEN - 1; + break; + } + else if (n < BUF_LEN - 1) + { + n += snprintf(buf + n, BUF_LEN - n, " "); + } + id_list = id_list->next; + } + while (id_list); + } + plog(" loaded shared key for %.*s", n, buf); } -static void -process_secret(secret_t *s, int whackfd) +static void process_secret(secret_t *s, int whackfd) { - err_t ugh = NULL; - - s->kind = PPK_PSK; /* default */ - if (*tok == '"' || *tok == '\'') - { - /* old PSK format: just a string */ - log_psk(s); - ugh = process_psk_secret(&s->u.preshared_secret); - } - else if (tokeqword("psk")) - { - /* preshared key: quoted string or ttodata format */ - log_psk(s); - ugh = !shift()? "unexpected end of record in PSK" - : 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 = PPK_RSA; - if (!shift()) + err_t ugh = NULL; + + s->kind = PPK_PSK; /* default */ + if (*tok == '"' || *tok == '\'') + { + /* old PSK format: just a string */ + log_psk(s); + ugh = process_psk_secret(&s->u.preshared_secret); + } + else if (tokeqword("psk")) + { + /* preshared key: quoted string or ttodata format */ + log_psk(s); + ugh = !shift()? "unexpected end of record in PSK" + : 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 = PPK_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 = PPK_PUBKEY; + if (!shift()) + { + ugh = "bad ECDSA key syntax"; + } + else + { + ugh = process_keyfile(&s->u.private_key, KEY_ECDSA, whackfd); + } + } + else if (tokeqword("xauth")) { - ugh = "bad RSA key syntax"; + ugh = process_xauth(s); } - else if (tokeq("{")) + else if (tokeqword("pin")) { - ugh = process_rsa_secret(&s->u.RSA_private_key); + ugh = process_pin(s, whackfd); } else { - ugh = process_rsa_keyfile(&s->u.RSA_private_key, whackfd); + ugh = builddiag("unrecognized key format: %s", tok); } - } - else if (tokeqword("xauth")) - { - ugh = process_xauth(s); - } - 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); - pfree(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")) + if (ugh != NULL) { - /* 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 */ - } + loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s" + , flp->filename, flp->lino, ugh); + free(s); } - else + else if (flushline("expected record boundary in key")) { - /* expecting a list of indices and then the key info */ - secret_t *s = alloc_thing(secret_t, "secret"); + /* gauntlet has been run: install new secret */ + lock_certs_and_keys("process_secret"); + s->next = secrets; + secrets = s; + unlock_certs_and_keys("process_secrets"); + } +} - s->ids = NULL; - s->kind = PPK_PSK; /* default */ - setchunk(s->u.preshared_secret, NULL, 0); - s->next = NULL; +static void process_secrets_file(const char *file_pat, int whackfd); /* forward declaration */ - for (;;) - { - if (tok[0] == '"' || tok[0] == '\'') +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) { - /* found key part */ - process_secret(s, whackfd); - break; + break; } - else if (tokeq(":")) + flp->bdry = B_none; /* eat the Record Boundary */ + (void)shift(); /* get real first token */ + + if (tokeqword("include")) { - /* found key part */ - shift(); /* discard explicit separator */ - process_secret(s, whackfd); - break; + /* 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 { - /* an id - * See RFC2407 IPsec Domain of Interpretation 4.6.2 - */ - struct id id; - err_t ugh; - - if (tokeq("%any")) - { - id = empty_id; - id.kind = ID_IPV4_ADDR; - ugh = anyaddr(AF_INET, &id.ip_addr); - } - else if (tokeq("%any6")) - { - id = empty_id; - id.kind = ID_IPV6_ADDR; - ugh = anyaddr(AF_INET6, &id.ip_addr); - } - else - { - ugh = atoid(tok, &id, FALSE); - } - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS - , "ERROR \"%s\" line %d: index \"%s\" %s" - , flp->filename, flp->lino, tok, ugh); - } - else - { - id_list_t *i = alloc_thing(id_list_t - , "id_list"); - - i->id = id; - unshare_id_content(&i->id); - i->next = s->ids; - s->ids = i; - /* DBG_log("id type %d: %s %.*s", i->kind, ip_str(&i->ip_addr), (int)i->name.len, i->name.ptr); */ - } - if (!shift()) - { - /* unexpected Record Boundary or EOF */ - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end of id list" - , flp->filename, flp->lino); - break; - } + /* expecting a list of indices and then the key info */ + secret_t *s = malloc_thing(secret_t); + + zero(s); + s->ids = NULL; + s->kind = PPK_PSK; /* default */ + s->u.preshared_secret = chunk_empty; + s->next = NULL; + + for (;;) + { + if (tok[0] == '"' || tok[0] == '\'') + { + /* found key part */ + process_secret(s, whackfd); + break; + } + else if (tokeq(":")) + { + /* found key part */ + shift(); /* discard explicit separator */ + process_secret(s, whackfd); + break; + } + else + { + /* an id + * See RFC2407 IPsec Domain of Interpretation 4.6.2 + */ + struct id id; + err_t ugh; + + if (tokeq("%any")) + { + id = empty_id; + id.kind = ID_IPV4_ADDR; + ugh = anyaddr(AF_INET, &id.ip_addr); + } + else if (tokeq("%any6")) + { + id = empty_id; + id.kind = ID_IPV6_ADDR; + ugh = anyaddr(AF_INET6, &id.ip_addr); + } + else + { + ugh = atoid(tok, &id, FALSE); + } + + if (ugh != NULL) + { + loglog(RC_LOG_SERIOUS + , "ERROR \"%s\" line %d: index \"%s\" %s" + , flp->filename, flp->lino, tok, ugh); + } + else + { + id_list_t *i = malloc_thing(id_list_t); + + i->id = id; + unshare_id_content(&i->id); + i->next = s->ids; + s->ids = i; + /* DBG_log("id type %d: %s %.*s", i->kind, ip_str(&i->ip_addr), (int)i->name.len, i->name.ptr); */ + } + if (!shift()) + { + /* unexpected Record Boundary or EOF */ + loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end of id list" + , flp->filename, flp->lino); + break; + } + } + } } - } } - } } -static int -globugh(const char *epath, int eerrno) +static int globugh(const char *epath, int eerrno) { - log_errno_routine(eerrno, "problem with secrets file \"%s\"", epath); - return 1; /* stop glob */ + 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) +static void process_secrets_file(const char *file_pat, int whackfd) { - struct file_lex_position pos; - char **fnp; - glob_t globbuf; - - pos.depth = flp == NULL? 0 : flp->depth + 1; + struct file_lex_position pos; + char **fnp; + glob_t globbuf; - if (pos.depth > 10) - { - loglog(RC_LOG_SERIOUS, "preshared secrets file \"%s\" nested too deeply", file_pat); - return; - } + pos.depth = flp == NULL? 0 : flp->depth + 1; - /* do globbing */ - { - int r = glob(file_pat, GLOB_ERR, globugh, &globbuf); + if (pos.depth > 10) + { + loglog(RC_LOG_SERIOUS, "preshared secrets file \"%s\" nested too deeply", file_pat); + return; + } - if (r != 0) + /* do globbing */ { - 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; + 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)) + /* for each file... */ + for (fnp = globbuf.gl_pathv; *fnp != NULL; fnp++) { - plog("loading secrets from \"%s\"", *fnp); - (void) flushline("file starts with indentation (continuation notation)"); - process_secret_records(whackfd); - lexclose(); + if (lexopen(&pos, *fnp, FALSE)) + { + plog("loading secrets from \"%s\"", *fnp); + (void) flushline("file starts with indentation (continuation notation)"); + process_secret_records(whackfd); + lexclose(); + } } - } - globfree(&globbuf); + globfree(&globbuf); } -void -free_preshared_secrets(void) +void free_preshared_secrets(void) { - lock_certs_and_keys("free_preshared_secrets"); + lock_certs_and_keys("free_preshared_secrets"); - if (secrets != NULL) - { - secret_t *s, *ns; + if (secrets != NULL) + { + secret_t *s, *ns; - plog("forgetting secrets"); + plog("forgetting secrets"); - for (s = secrets; s != NULL; s = ns) - { - id_list_t *i, *ni; - - ns = s->next; /* grab before freeing s */ - for (i = s->ids; i != NULL; i = ni) - { - ni = i->next; /* grab before freeing i */ - free_id_content(&i->id); - pfree(i); - } - switch (s->kind) - { - case PPK_PSK: - pfree(s->u.preshared_secret.ptr); - break; - case PPK_RSA: - free_RSA_private_content(&s->u.RSA_private_key); - break; - case PPK_XAUTH: - pfree(s->u.xauth_secret.user_name.ptr); - pfree(s->u.xauth_secret.user_password.ptr); - break; - case PPK_PIN: - scx_release(s->u.smartcard); - break; - default: - bad_case(s->kind); - } - pfree(s); + for (s = secrets; s != NULL; s = ns) + { + id_list_t *i, *ni; + + ns = s->next; /* grab before freeing s */ + for (i = s->ids; i != NULL; i = ni) + { + ni = i->next; /* grab before freeing i */ + free_id_content(&i->id); + free(i); + } + switch (s->kind) + { + case PPK_PSK: + free(s->u.preshared_secret.ptr); + break; + case PPK_PUBKEY: + DESTROY_IF(s->u.private_key); + break; + case PPK_XAUTH: + free(s->u.xauth_secret.user_name.ptr); + free(s->u.xauth_secret.user_password.ptr); + break; + case PPK_PIN: + scx_release(s->u.smartcard); + break; + default: + bad_case(s->kind); + } + free(s); + } + secrets = NULL; } - secrets = NULL; - } - unlock_certs_and_keys("free_preshard_secrets"); + unlock_certs_and_keys("free_preshard_secrets"); } -void -load_preshared_secrets(int whackfd) +void load_preshared_secrets(int whackfd) { - free_preshared_secrets(); - (void) process_secrets_file(shared_secrets_file, 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(const RSA_public_key_t *k) +pubkey_t* public_key_from_rsa(public_key_t *key) { - pubkey_t *p = alloc_thing(pubkey_t, "pubkey"); - - p->id = empty_id; /* don't know, doesn't matter */ - p->issuer = empty_chunk; - p->serial = empty_chunk; - p->alg = PUBKEY_ALG_RSA; - - memcpy(p->u.rsa.keyid, k->keyid, sizeof(p->u.rsa.keyid)); - p->u.rsa.k = k->k; - mpz_init_set(&p->u.rsa.e, &k->e); - mpz_init_set(&p->u.rsa.n, &k->n); - - /* note that we return a 1 reference count upon creation: - * invariant: recount > 0. - */ - p->refcnt = 1; - time(&p->installed_time); - return p; + pubkey_t *p = malloc_thing(pubkey_t); + + zero(p); + p->id = empty_id; /* don't know, doesn't matter */ + p->issuer = chunk_empty; + p->serial = chunk_empty; + p->public_key = key; + + /* note that we return a 1 reference count upon creation: + * invariant: recount > 0. + */ + p->refcnt = 1; + time(&p->installed_time); + 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* free_public_keyentry(pubkey_list_t *p) { - pubkey_list_t *nxt = p->next; + pubkey_list_t *nxt = p->next; - if (p->key != NULL) - unreference_key(&p->key); - pfree(p); - return nxt; + if (p->key != NULL) + { + unreference_key(&p->key); + } + free(p); + return nxt; } -void -free_public_keys(pubkey_list_t **keys) +void free_public_keys(pubkey_list_t **keys) { - while (*keys != NULL) - *keys = free_public_keyentry(*keys); + while (*keys != NULL) + { + *keys = free_public_keyentry(*keys); + } } /* root of chained public key list */ -pubkey_list_t *pubkeys = NULL; /* keys from ipsec.conf */ +pubkey_list_t *pubkeys = NULL; /* keys from ipsec.conf */ -void -free_remembered_public_keys(void) +void free_remembered_public_keys(void) { - free_public_keys(&pubkeys); + 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 +/** + * 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 = alloc_thing(pubkey_list_t, "from TXT"); + struct gw_info *gwp; - pl->key = gwp->key; /* note: this is a transfer */ - gwp->key = NULL; /* really, it is! */ - pl->next = pubkeys; - pubkeys = pl; + 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; - } + { + pubkey_list_t **pp = keys; + + while (*pp != NULL) + { + pp = &(*pp)->next; + } + *pp = pubkeys; + pubkeys = *keys; + *keys = NULL; + } #endif /* USE_KEYRR */ } -/* decode of RSA pubkey chunk - * - format specified in RFC 2537 RSA/MD5 Keys and SIGs in the DNS - * - exponent length in bytes (1 or 3 octets) - * + 1 byte if in [1, 255] - * + otherwise 0x00 followed by 2 bytes of length - * - exponent - * - modulus - */ -err_t -unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey) -{ - chunk_t exp; - chunk_t mod; - - if (pubkey->len < 3) - return "RSA public key blob way to short"; /* not even room for length! */ - - if (pubkey->ptr[0] != 0x00) - { - setchunk(exp, pubkey->ptr + 1, pubkey->ptr[0]); - } - else - { - setchunk(exp, pubkey->ptr + 3 - , (pubkey->ptr[1] << BITS_PER_BYTE) + pubkey->ptr[2]); - } - - if (pubkey->len - (exp.ptr - pubkey->ptr) < exp.len + RSA_MIN_OCTETS_RFC) - return "RSA public key blob too short"; - - mod.ptr = exp.ptr + exp.len; - mod.len = &pubkey->ptr[pubkey->len] - mod.ptr; - - if (mod.len < RSA_MIN_OCTETS) - return RSA_MIN_OCTETS_UGH; - - if (mod.len > RSA_MAX_OCTETS) - return RSA_MAX_OCTETS_UGH; - - init_RSA_public_key(rsa, exp, mod); - rsa->k = mpz_sizeinbase(&rsa->n, 2); /* size in bits, for a start */ - rsa->k = (rsa->k + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* now octets */ - DBG(DBG_RAW, - RSA_show_public_key(rsa) - ) - - if (rsa->k != mod.len) - { - mpz_clear(&rsa->e); - mpz_clear(&rsa->n); - return "RSA modulus shorter than specified"; - } - - return NULL; -} -static void -install_public_key(pubkey_t *pk, pubkey_list_t **head) +static void install_public_key(pubkey_t *pk, pubkey_list_t **head) { - pubkey_list_t *p = alloc_thing(pubkey_list_t, "pubkey entry"); + pubkey_list_t *p = malloc_thing(pubkey_list_t); - unshare_id_content(&pk->id); + unshare_id_content(&pk->id); - /* copy issuer dn */ - if (pk->issuer.ptr != NULL) - pk->issuer.ptr = clone_bytes(pk->issuer.ptr, pk->issuer.len, "issuer dn"); + /* copy issuer dn */ + pk->issuer = chunk_clone(pk->issuer); - /* copy serial number */ - if (pk->serial.ptr != NULL) - pk->serial.ptr = clone_bytes(pk->serial.ptr, pk->serial.len, "serialNumber"); + /* copy serial number */ + pk->serial = chunk_clone(pk->serial); - /* store the time the public key was installed */ - time(&pk->installed_time); + /* store the time the public key was installed */ + time(&pk->installed_time); - /* install new key at front */ - p->key = reference_key(pk); - p->next = *head; - *head = p; + /* install new key at front */ + p->key = reference_key(pk); + p->next = *head; + *head = p; } - -void -delete_public_keys(const struct id *id, enum pubkey_alg alg -, chunk_t issuer, chunk_t serial) +void delete_public_keys(const struct id *id, key_type_t type, + chunk_t issuer, chunk_t serial) { - pubkey_list_t **pp, *p; - pubkey_t *pk; - - for (pp = &pubkeys; (p = *pp) != NULL; ) - { - pk = p->key; - - if (same_id(id, &pk->id) && pk->alg == alg - && (issuer.ptr == NULL || pk->issuer.ptr == NULL - || same_dn(issuer, pk->issuer)) - && same_serial(serial, pk->serial)) - *pp = free_public_keyentry(p); - else - pp = &p->next; - } + 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 (same_id(id, &pk->id) && pk_type == type + && (issuer.ptr == NULL || pk->issuer.ptr == NULL + || same_dn(issuer, pk->issuer)) + && same_serial(serial, pk->serial)) + { + *pp = free_public_keyentry(p); + } + else + { + pp = &p->next; + } + } } -pubkey_t * -reference_key(pubkey_t *pk) +pubkey_t* reference_key(pubkey_t *pk) { - pk->refcnt++; - return pk; + pk->refcnt++; + return pk; } void unreference_key(pubkey_t **pkp) { - pubkey_t *pk = *pkp; - char b[BUF_LEN]; + pubkey_t *pk = *pkp; + char b[BUF_LEN]; - if (pk == NULL) - return; + if (pk == NULL) + { + return; + } - /* print stuff */ - DBG(DBG_CONTROLMORE, - idtoa(&pk->id, b, sizeof(b)); - DBG_log("unreference key: %p %s cnt %d--", pk, b, pk->refcnt) - ) + /* print stuff */ + DBG(DBG_CONTROLMORE, + idtoa(&pk->id, b, sizeof(b)); + DBG_log("unreference key: %p %s cnt %d--", pk, b, pk->refcnt) + ) - /* cancel out the pointer */ - *pkp = NULL; + /* cancel out the pointer */ + *pkp = NULL; - passert(pk->refcnt != 0); - pk->refcnt--; - if (pk->refcnt == 0) - free_public_key(pk); + passert(pk->refcnt != 0); + pk->refcnt--; + if (pk->refcnt == 0) + { + free_public_key(pk); + } } -err_t -add_public_key(const struct id *id -, enum dns_auth_level dns_auth_level -, enum pubkey_alg alg -, const chunk_t *key -, pubkey_list_t **head) +bool add_public_key(const struct id *id, enum dns_auth_level dns_auth_level, + enum pubkey_alg alg, chunk_t rfc3110_key, + pubkey_list_t **head) { - pubkey_t *pk = alloc_thing(pubkey_t, "pubkey"); + public_key_t *key = NULL; + pubkey_t *pk; - /* first: algorithm-specific decoding of key chunk */ - switch (alg) - { - case PUBKEY_ALG_RSA: + /* first: algorithm-specific decoding of key chunk */ + switch (alg) { - err_t ugh = unpack_RSA_public_key(&pk->u.rsa, key); - - if (ugh != NULL) - { - pfree(pk); - return ugh; - } + case PUBKEY_ALG_RSA: + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + BUILD_BLOB_RFC_3110, rfc3110_key, + BUILD_END); + if (key == NULL) + { + return FALSE; + } + break; + default: + bad_case(alg); } - break; - default: - bad_case(alg); - } - - pk->id = *id; - pk->dns_auth_level = dns_auth_level; - pk->alg = alg; - pk->until_time = UNDEFINED_TIME; - pk->issuer = empty_chunk; - pk->serial = empty_chunk; - - install_public_key(pk, head); - return NULL; + + pk = malloc_thing(pubkey_t); + zero(pk); + pk->public_key = key; + pk->id = *id; + pk->dns_auth_level = dns_auth_level; + pk->until_time = UNDEFINED_TIME; + pk->issuer = chunk_empty; + pk->serial = chunk_empty; + install_public_key(pk, head); + return TRUE; } /* extract id and public key from x.509 certificate and * insert it into a pubkeyrec */ -void -add_x509_public_key(x509cert_t *cert , time_t until - , enum dns_auth_level dns_auth_level) +void add_x509_public_key(x509cert_t *cert , time_t until, + enum dns_auth_level dns_auth_level) { - generalName_t *gn; - pubkey_t *pk; - cert_t c = { CERT_X509_SIGNATURE, {cert} }; - - /* we support RSA only */ - if (cert->subjectPublicKeyAlgorithm != PUBKEY_ALG_RSA) - return; - - /* ID type: ID_DER_ASN1_DN (X.509 subject field) */ - pk = allocate_RSA_public_key(c); - pk->id.kind = ID_DER_ASN1_DN; - pk->id.name = cert->subject; - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - pk->issuer = cert->issuer; - pk->serial = cert->serialNumber; - delete_public_keys(&pk->id, pk->alg, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); - - gn = cert->subjectAltName; - - while (gn != NULL) /* insert all subjectAltNames */ - { - struct id id = empty_id; - - gntoid(&id, gn); - if (id.kind != ID_NONE) + generalName_t *gn; + 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 = cert->public_key->get_ref(cert->public_key); + pk->id.kind = ID_DER_ASN1_DN; + pk->id.name = cert->subject; + pk->dns_auth_level = dns_auth_level; + pk->until_time = until; + pk->issuer = cert->issuer; + pk->serial = cert->serialNumber; + pk_type = pk->public_key->get_type(pk->public_key); + delete_public_keys(&pk->id, pk_type, pk->issuer, pk->serial); + install_public_key(pk, &pubkeys); + + gn = cert->subjectAltName; + + while (gn != NULL) /* insert all subjectAltNames */ { - pk = allocate_RSA_public_key(c); - pk->id = id; - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - pk->issuer = cert->issuer; - pk->serial = cert->serialNumber; - delete_public_keys(&pk->id, pk->alg, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); + struct id id = empty_id; + + gntoid(&id, gn); + if (id.kind != ID_ANY) + { + pk = malloc_thing(pubkey_t); + zero(pk); + pk->public_key = cert->public_key->get_ref(cert->public_key); + pk->id = id; + pk->dns_auth_level = dns_auth_level; + pk->until_time = until; + pk->issuer = cert->issuer; + pk->serial = cert->serialNumber; + delete_public_keys(&pk->id, pk_type, pk->issuer, pk->serial); + install_public_key(pk, &pubkeys); + } + gn = gn->next; } - gn = gn->next; - } } /* extract id and public key from OpenPGP certificate and * insert it into a pubkeyrec */ -void -add_pgp_public_key(pgpcert_t *cert , time_t until - , enum dns_auth_level dns_auth_level) +void add_pgp_public_key(pgpcert_t *cert , time_t until, + enum dns_auth_level dns_auth_level) { - pubkey_t *pk; - cert_t c; - - c.type = CERT_PGP; - c.u.pgp = cert; - - /* we support RSA only */ - if (cert->pubkeyAlg != PUBKEY_ALG_RSA) - { - plog(" RSA public keys supported only"); - return; - } - - pk = allocate_RSA_public_key(c); - pk->id.kind = ID_KEY_ID; - pk->id.name.ptr = cert->fingerprint; - pk->id.name.len = PGP_FINGERPRINT_SIZE; - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - delete_public_keys(&pk->id, pk->alg, empty_chunk, empty_chunk); - install_public_key(pk, &pubkeys); + pubkey_t *pk; + key_type_t pk_type; + + pk = malloc_thing(pubkey_t); + zero(pk); + pk->public_key = cert->public_key->get_ref(cert->public_key); + pk->id.kind = ID_KEY_ID; + pk->id.name = cert->fingerprint->get_encoding(cert->fingerprint); + pk->dns_auth_level = dns_auth_level; + pk->until_time = until; + pk_type = pk->public_key->get_type(pk->public_key); + delete_public_keys(&pk->id, pk_type, chunk_empty, chunk_empty); + 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 x509cert_t *cert) +void remove_x509_public_key(const x509cert_t *cert) { - const cert_t c = {CERT_X509_SIGNATURE, {(x509cert_t*)cert}}; - pubkey_list_t *p, **pp; - pubkey_t *revoked_pk; + public_key_t *revoked_key = cert->public_key; + pubkey_list_t *p, **pp; - revoked_pk = allocate_RSA_public_key(c); - p = pubkeys; - pp = &pubkeys; + p = pubkeys; + pp = &pubkeys; - while(p != NULL) - { - if (same_RSA_public_key(&p->key->u.rsa, &revoked_pk->u.rsa)) - { - /* remove p from list and free memory */ - *pp = free_public_keyentry(p); - loglog(RC_LOG_SERIOUS, - "invalid RSA public key deleted"); - } - else + while(p != NULL) { - pp = &p->next; + 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; } - p =*pp; - } - free_public_key(revoked_pk); } /* @@ -1504,45 +1419,41 @@ remove_x509_public_key(const x509cert_t *cert) */ void list_public_keys(bool utc) { - pubkey_list_t *p = pubkeys; - - if (p != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of Public Keys:"); - whack_log(RC_COMMENT, " "); - } + pubkey_list_t *p = pubkeys; - while (p != NULL) - { - pubkey_t *key = p->key; + if (p != NULL) + { + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of Public Keys:"); + whack_log(RC_COMMENT, " "); + } - if (key->alg == PUBKEY_ALG_RSA) + while (p != NULL) { - char buf[BUF_LEN]; - char expires_buf[TIMETOA_BUF]; - - idtoa(&key->id, buf, BUF_LEN); - strcpy(expires_buf, timetoa(&key->until_time, utc)); - whack_log(RC_COMMENT, "%s, %4d RSA Key %s, until %s %s", - - timetoa(&key->installed_time, utc), 8*key->u.rsa.k, key->u.rsa.keyid, - expires_buf, - check_expiry(key->until_time, PUBKEY_WARNING_INTERVAL, TRUE)); - whack_log(RC_COMMENT," %s '%s'", - enum_show(&ident_names, key->id.kind), buf); - if (key->issuer.len > 0) - { - dntoa(buf, BUF_LEN, key->issuer); - whack_log(RC_COMMENT," issuer: '%s'", buf); - } - if (key->serial.len > 0) - { - datatot(key->serial.ptr, key->serial.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT," serial: %s", buf); - } + pubkey_t *key = p->key; + public_key_t *public = key->public_key; + identification_t *keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); + char buf[BUF_LEN]; + + idtoa(&key->id, buf, BUF_LEN); + whack_log(RC_COMMENT,"%T, '%s'", &key->installed_time, utc, buf); + whack_log(RC_COMMENT, " pubkey: %N %4d bits, until %T %s", + key_type_names, public->get_type(public), + public->get_keysize(public) * BITS_PER_BYTE, + &key->until_time, utc, + check_expiry(key->until_time, PUBKEY_WARNING_INTERVAL, TRUE)); + whack_log(RC_COMMENT," keyid: %Y", keyid); + if (key->issuer.len > 0) + { + dntoa(buf, BUF_LEN, key->issuer); + whack_log(RC_COMMENT," issuer: '%s'", buf); + } + if (key->serial.len > 0) + { + datatot(key->serial.ptr, key->serial.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT," serial: %s", buf); + } + p = p->next; } - p = p->next; - } } diff --git a/src/pluto/keys.h b/src/pluto/keys.h index b06e536a5..8bc94d839 100644 --- a/src/pluto/keys.h +++ b/src/pluto/keys.h @@ -1,5 +1,6 @@ /* 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 @@ -10,16 +11,14 @@ * 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. - * - * RCSID $Id: keys.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _KEYS_H #define _KEYS_H -#include <gmp.h> /* GNU Multi-Precision library */ +#include <credentials/keys/private_key.h> +#include <credentials/keys/public_key.h> -#include "pkcs1.h" #include "certs.h" #ifndef SHARED_SECRETS_FILE @@ -32,11 +31,10 @@ extern void load_preshared_secrets(int whackfd); extern void free_preshared_secrets(void); enum PrivateKeyKind { - PPK_PSK, - /* PPK_DSS, */ /* not implemented */ - PPK_RSA, - PPK_XAUTH, - PPK_PIN + PPK_PSK, + PPK_PUBKEY, + PPK_XAUTH, + PPK_PIN }; extern void xauth_defaults(void); @@ -45,69 +43,64 @@ extern void xauth_defaults(void); struct connection; extern const chunk_t *get_preshared_secret(const struct connection *c); -extern err_t unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey); -extern const RSA_private_key_t *get_RSA_private_key(const struct connection *c); -extern const RSA_private_key_t *get_x509_private_key(const x509cert_t *cert); +extern private_key_t *get_private_key(const struct connection *c); +extern private_key_t *get_x509_private_key(const x509cert_t *cert); /* public key machinery */ typedef struct pubkey pubkey_t; struct pubkey { - struct id id; - unsigned refcnt; /* reference counted! */ - enum dns_auth_level dns_auth_level; - char *dns_sig; - time_t installed_time - , last_tried_time - , last_worked_time - , until_time; - chunk_t issuer; - chunk_t serial; - enum pubkey_alg alg; - union { - RSA_public_key_t rsa; - } u; + struct id id; + unsigned refcnt; /* reference counted! */ + enum dns_auth_level dns_auth_level; + char *dns_sig; + time_t installed_time + , last_tried_time + , last_worked_time + , until_time; + chunk_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; + pubkey_t *key; + pubkey_list_t *next; }; -extern pubkey_list_t *pubkeys; /* keys from ipsec.conf or from certs */ +extern pubkey_list_t *pubkeys; /* keys from ipsec.conf or from certs */ -extern pubkey_t *public_key_from_rsa(const RSA_public_key_t *k); +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(const struct id *id, enum pubkey_alg alg - , chunk_t issuer, chunk_t serial); - +extern void delete_public_keys(const struct id *id, key_type_t type, + chunk_t issuer, chunk_t serial); extern pubkey_t *reference_key(pubkey_t *pk); extern void unreference_key(pubkey_t **pkp); -extern err_t add_public_key(const struct id *id - , enum dns_auth_level dns_auth_level - , enum pubkey_alg alg - , const chunk_t *key - , pubkey_list_t **head); +extern bool add_public_key(const struct id *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_x509_public_key(x509cert_t *cert, time_t until - , enum dns_auth_level dns_auth_level); + , enum dns_auth_level dns_auth_level); extern void add_pgp_public_key(pgpcert_t *cert, time_t until - , enum dns_auth_level dns_auth_level); + , enum dns_auth_level dns_auth_level); extern void remove_x509_public_key(const x509cert_t *cert); extern void list_public_keys(bool utc); -struct gw_info; /* forward declaration of tag (defined in dnskey.h) */ +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 + , pubkey_list_t **keys #endif /* USE_KEYRR */ - ); + ); #endif /* _KEYS_H */ diff --git a/src/pluto/lex.c b/src/pluto/lex.c index 08ab43876..f48d24a54 100644 --- a/src/pluto/lex.c +++ b/src/pluto/lex.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: lex.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdio.h> @@ -27,7 +25,7 @@ #include "constants.h" #include "defs.h" #include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ +#include "whack.h" /* for RC_LOG_SERIOUS */ #include "lex.h" struct file_lex_position *flp = NULL; @@ -39,36 +37,36 @@ struct file_lex_position *flp = NULL; 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; - } + 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; + fclose(flp->fp); + flp = flp->previous; } /* Token decoding: shift() loads the next token into tok. @@ -88,110 +86,110 @@ char *tok; bool shift(void) { - char *p = flp->cur; - char *sor = NULL; /* start of record for any new lines */ + char *p = flp->cur; + char *sor = NULL; /* start of record for any new lines */ - passert(flp->bdry == B_none); + passert(flp->bdry == B_none); - *p = flp->under; - flp->under = '\0'; + *p = flp->under; + flp->under = '\0'; - for (;;) - { - switch (*p) + for (;;) { - 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') + switch (*p) { - /* 0t... token goes to end of line */ - p += strlen(p); - } - else - { - /* "ordinary" token: up to whitespace or end of line */ - do { + 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++; - } while (*p != '\0' && !isspace(*p)) - ; - - /* fudge to separate ':' from a preceding adjacent token */ - if (p-1 > tok && p[-1] == ':') - 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; } - - /* 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 */ @@ -199,15 +197,15 @@ shift(void) 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; - } + 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 index 450149c64..f16769144 100644 --- a/src/pluto/lex.h +++ b/src/pluto/lex.h @@ -10,22 +10,20 @@ * 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. - * - * RCSID $Id: lex.h 3252 2007-10-06 21:24:50Z andreas $ */ #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 orignally at *cur */ - struct file_lex_position *previous; + 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 orignally at *cur */ + struct file_lex_position *previous; }; extern struct file_lex_position *flp; diff --git a/src/pluto/log.c b/src/pluto/log.c index b7c1ba8b8..e34409f1c 100644 --- a/src/pluto/log.c +++ b/src/pluto/log.c @@ -1,6 +1,7 @@ /* error logging functions * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. + * 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 @@ -11,8 +12,6 @@ * 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. - * - * RCSID $Id: log.c 4246 2008-08-03 18:01:21Z andreas $ */ #include <stdio.h> @@ -23,13 +22,15 @@ #include <errno.h> #include <string.h> #include <unistd.h> -#include <signal.h> /* used only if MSG_NOSIGNAL not defined */ +#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> #include <freeswan.h> +#include <library.h> +#include <debug.h> #include "constants.h" #include "defs.h" @@ -38,27 +39,27 @@ #include "state.h" #include "connections.h" #include "kernel.h" -#include "whack.h" /* needs connections.h */ +#include "whack.h" /* needs connections.h */ #include "timer.h" /* close one per-peer log */ -static void perpeer_logclose(struct connection *c); /* forward */ +static void perpeer_logclose(struct connection *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? */ + 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? */ + 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; + 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; @@ -74,42 +75,110 @@ static TAILQ_HEAD(perpeer, connection) perpeer_list; * 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 */ -struct connection *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 */ +int whack_log_fd = NULL_FD; /* only set during whack_handle() */ +struct state *cur_state = NULL; /* current state, for diagnostics */ +struct connection *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(int 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) + { + /* 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); + current = next; + } + } + va_end(args); + } +} void init_log(const char *program) { - if (log_to_stderr) - setbuf(stderr, NULL); - if (log_to_syslog) - openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV); + /* enable pluto debugging hook for libstrongswan */ + dbg = pluto_dbg; - TAILQ_INIT(&perpeer_list); + 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; + /* 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)); + /* 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(); + if (log_to_syslog) + closelog(); - close_peerlog(); + close_peerlog(); } /* Sanitize character string in situ: turns dangerous characters into \OOO. @@ -120,50 +189,50 @@ close_log(void) 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; +# 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 } @@ -174,349 +243,348 @@ sanitize(char *buf, size_t size) static void fmt_log(char *buf, size_t buf_len, const char *fmt, va_list ap) { - bool reproc = *fmt == '~'; - size_t ps; - struct connection *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) + bool reproc = *fmt == '~'; + size_t ps; + struct connection *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) { - fmt_conn_instance(c, bp); - bp += strlen(bp); - } + /* 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) + 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) { - /* state number */ - snprintf(bp, be - bp, " #%lu", cur_state->st_serialno); - bp += strlen(bp); + /* 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); } - 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); + + ps = strlen(buf); + vsnprintf(buf + ps, buf_len - ps, fmt, ap); + if (!reproc) + (void)sanitize(buf, buf_len); } static void perpeer_logclose(struct connection *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; - } + /* 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(struct connection *c) { - perpeer_logclose(c); - if (c->log_file_name != NULL) - { - pfree(c->log_file_name); - c->log_file_name = NULL; - c->log_file_err = FALSE; - } + 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(struct connection *c) { - syslog(LOG_INFO, "opening log file for conn %s", c->name); + 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 / */ + if (c->log_file_name == NULL) { - char c, *p, *q; - - p = peername; - q = dname; - do { - c = *p++; - if (c == '.' || c == ':') - c = '/'; - *q++ = c; - } while (c != '\0'); - } - - lf_len = peernamelen * 2 - + strlen(base_perpeer_logdir) - + sizeof("//.log") - + 1; - c->log_file_name = alloc_bytes(lf_len, "per-peer log file name"); - - 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); + char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF]; + int peernamelen, lf_len; - syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name); - } + addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername)); + peernamelen = strlen(peername); - /* 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, "temp copy of file name"); - dname = dirname(dname); - - if (access(dname, W_OK) != 0) - { - if (errno != ENOENT) - { - if (c->log_file_err) + /* copy IP address, turning : and . into / */ { - syslog(LOG_CRIT, "can not write to %s: %s" - , dname, strerror(errno)); - c->log_file_err = TRUE; - pfree(dname); - return; + char c, *p, *q; + + p = peername; + q = dname; + do { + c = *p++; + if (c == '.' || c == ':') + c = '/'; + *q++ = c; + } while (c != '\0'); } - } - /* 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 */ + 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); - while (*slashloc != '\0') - { - char saveslash; + syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name); + } - /* look for next slash */ - while (*slashloc != '\0' && *slashloc != '/') slashloc++; + /* now open the file, creating directories if necessary */ - saveslash = *slashloc; + { /* create the directory */ + char *dname; + int bpl_len = strlen(base_perpeer_logdir); + char *slashloc; - *slashloc = '\0'; + dname = clone_str(c->log_file_name); + dname = dirname(dname); - if (mkdir(dname, 0750) != 0 && errno != EEXIST) + if (access(dname, W_OK) != 0) { - syslog(LOG_CRIT, "can not create dir %s: %s" - , dname, strerror(errno)); - c->log_file_err = TRUE; - pfree(dname); - return; + 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++; + } } - syslog(LOG_DEBUG, "created new directory %s", dname); - *slashloc = saveslash; - slashloc++; - } + free(dname); } - pfree(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; + } - c->log_file = fopen(c->log_file_name, "a"); - if (c->log_file == NULL) - { - if (c->log_file_err) + /* look for a connection to close! */ + while (perpeer_count >= MAX_PEERLOG_COUNT) { - syslog(LOG_CRIT, "logging system can not open %s: %s" - , c->log_file_name, strerror(errno)); - c->log_file_err = TRUE; + /* can not be NULL because perpeer_count > 0 */ + passert(TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list); + + perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer)); } - 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++; + + /* 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); - } + 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_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); + 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); + if (log_to_stderr) + fprintf(stderr, "%s\n", m); + if (log_to_syslog) + syslog(LOG_WARNING, "%s", m); + if (log_to_perpeer) + peerlog("", m); - whack_log(RC_LOG, "~%s", m); + 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_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); + 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); + if (log_to_stderr) + fprintf(stderr, "%s\n", m); + if (log_to_syslog) + syslog(LOG_WARNING, "%s", m); + if (log_to_perpeer) + peerlog("", m); - whack_log(mess_no, "~%s", m); + 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); - } - - whack_log(RC_LOG_SERIOUS - , "~ERROR: %s. Errno %d: %s", m, e, strerror(e)); + 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); + } + + 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_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); + 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); + 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); - whack_log(RC_LOG_SERIOUS, "~FATAL ERROR: %s", m); + whack_log(RC_LOG_SERIOUS, "~FATAL ERROR: %s", m); - exit_pluto(1); + 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_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); + 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); + 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); - whack_log(RC_LOG_SERIOUS - , "~FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e)); + whack_log(RC_LOG_SERIOUS + , "~FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e)); - exit_pluto(1); + exit_pluto(1); } /* emit message to whack. @@ -531,65 +599,65 @@ static volatile sig_atomic_t dying_breath = FALSE; 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; + int wfd = whack_log_fd != NULL_FD ? whack_log_fd + : cur_state != NULL ? cur_state->st_whack_sock + : NULL_FD; - if (wfd != NULL_FD + if (wfd != NULL_FD #ifdef DEBUG - || dying_breath + || dying_breath #endif - ) - { - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - int prelen = snprintf(m, sizeof(m), "%03d ", mess_no); + ) + { + va_list args; + char m[LOG_WIDTH]; /* longer messages will be truncated */ + int prelen = snprintf(m, sizeof(m), "%03d ", mess_no); - passert(prelen >= 0); + passert(prelen >= 0); - va_start(args, message); - fmt_log(m+prelen, sizeof(m)-prelen, message, args); - va_end(args); + 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); - } + 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); + } #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); + 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; + 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); + 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); + (void) write(wfd, m, len + 1); - r = sigaction(SIGPIPE, &oldact, NULL); - passert(r == 0); + r = sigaction(SIGPIPE, &oldact, NULL); + passert(r == 0); #endif /* !MSG_NOSIGNAL */ + } } - } } /* Build up a diagnostic in a static buffer. @@ -607,16 +675,16 @@ 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; + 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 */ @@ -626,51 +694,51 @@ builddiag(const char *fmt, ...) void switch_fail(int n, const char *file_str, unsigned long line_no) { - char buf[30]; + char buf[30]; - snprintf(buf, sizeof(buf), "case %d unexpected", n); - passert_fail(buf, file_str, line_no); + 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 */ + /* 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); + /* 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; + base_debugging = DBG_NONE, /* default to reporting nothing */ + cur_debugging = DBG_NONE; void extra_debugging(const struct connection *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; - } + 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 "| ") */ @@ -678,21 +746,21 @@ extra_debugging(const struct connection *c) void DBG_log(const char *message, ...) { - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ + 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); + va_start(args, message); + vsnprintf(m, sizeof(m), message, args); + va_end(args); - (void)sanitize(m, sizeof(m)); + (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); + if (log_to_stderr) + fprintf(stderr, "| %s\n", m); + if (log_to_syslog) + syslog(LOG_DEBUG, "| %s", m); + if (log_to_perpeer) + peerlog("| ", m); } /* dump raw bytes in hex to stderr (for lack of any better destination) */ @@ -700,82 +768,99 @@ DBG_log(const char *message, ...) 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; +# 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; - if (label != NULL && label[0] != '\0') - { - /* Handle the label. Care must be taken to avoid buffer overrun. */ - size_t llen = strlen(label); + bp = buf; - if (llen + 1 > sizeof(buf)) + if (label != NULL && label[0] != '\0') { - 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); - } + /* 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; + 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); + 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 */ -void -show_status(bool all, const char *name) +static void show_loaded_plugins() { - if (all) - { - show_ifaces_status(); - show_myid_status(); - show_debug_status(); - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ - } - show_connections_status(all, name); - show_states_status(all, name); + char buf[BUF_LEN], *plugin; + int len = 0; + enumerator_t *enumerator; + + buf[0] = '\0'; + enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); + while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin)) + { + len += snprintf(&buf[len], BUF_LEN-len, "%s ", plugin); + } + enumerator->destroy(enumerator); + whack_log(RC_COMMENT, "loaded plugins: %s", buf); +} + +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(); + whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ + } + show_connections_status(all, name); + show_states_status(all, name); #ifdef KLIPS - show_shunt_status(); + show_shunt_status(); #endif } @@ -788,10 +873,10 @@ show_status(bool all, const char *name) const char * ip_str(const ip_address *src) { - static char buf[ADDRTOT_BUF]; + static char buf[ADDRTOT_BUF]; - addrtot(src, 0, buf, sizeof(buf)); - return buf; + addrtot(src, 0, buf, sizeof(buf)); + return buf; } /* @@ -802,35 +887,31 @@ ip_str(const ip_address *src) void daily_log_reset(void) { - /* now perform actions */ - logged_txt_warning = FALSE; + /* 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; + 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 *ltime; - time_t n, interval; - - /* attempt to schedule oneself to midnight, local time - * do this by getting seconds in the day, and delaying - * by 86400 - hour*3600+minutes*60+seconds. - */ - time(&n); - ltime = localtime(&n); - interval = (24 * 60 * 60) - - (ltime->tm_sec - + ltime->tm_min * 60 - + ltime->tm_hour * 3600); - - event_schedule(EVENT_LOG_DAILY, interval, NULL); - - daily_log_reset(); + 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(); } /* diff --git a/src/pluto/log.h b/src/pluto/log.h index db0fb0202..52c01bbd4 100644 --- a/src/pluto/log.h +++ b/src/pluto/log.h @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: log.h 3252 2007-10-06 21:24:50Z andreas $ */ #include <freeswan.h> @@ -27,49 +25,49 @@ #ifdef DEBUG extern void passert_fail(const char *pred_str - , const char *file_str, unsigned long line_no) NEVER_RETURNS; + , 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); + , 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; + , 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__); \ - } + if (!(pred)) \ + passert_fail(#pred, __FILE__, __LINE__); \ + } # define pexpect(pred) { \ - if (!(pred)) \ - pexpect_log(#pred, __FILE__, __LINE__); \ - } + 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__); \ - } + 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 */ +# 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? */ + 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; @@ -84,25 +82,25 @@ extern const char *base_perpeer_logdir; * 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 */ +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 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) + && cur_state == NULL \ + && cur_connection == NULL \ + && cur_from == NULL \ + && cur_debugging == base_debugging) #else /*!DEBUG*/ @@ -111,40 +109,40 @@ extern u_int16_t cur_from_port; /* host order */ # define reset_debugging() { } # define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \ - && cur_state == NULL \ - && cur_connection == NULL \ - && cur_from == NULL) + && 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(); \ - } + 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); \ - } + cur_connection = (c); \ + extra_debugging(c); \ + } #define reset_cur_connection() { \ - cur_connection = NULL; \ - reset_debugging(); \ - } + cur_connection = NULL; \ + reset_debugging(); \ + } #define set_cur_state(s) { \ - cur_state = (s); \ - extra_debugging((s)->st_connection); \ - } + cur_state = (s); \ + extra_debugging((s)->st_connection); \ + } #define reset_cur_state() { \ - cur_state = NULL; \ - reset_debugging(); \ - } + cur_state = NULL; \ + reset_debugging(); \ + } extern void init_log(const char *program); extern void close_log(void); @@ -188,12 +186,12 @@ extern void show_status(bool all, const char *name); * 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 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 */ +extern lset_t base_debugging; /* bits selecting what to report */ #define DBGP(cond) (cur_debugging & (cond)) #define DBG(cond, action) { if (DBGP(cond)) { action ; } } @@ -204,7 +202,7 @@ extern void DBG_dump(const char *label, const void *p, size_t len); #else /*!DEBUG*/ -#define DBG(cond, action) { } /* do nothing */ +#define DBG(cond, action) { } /* do nothing */ #endif /*!DEBUG*/ diff --git a/src/pluto/md2.c b/src/pluto/md2.c deleted file mode 100644 index d6465477d..000000000 --- a/src/pluto/md2.c +++ /dev/null @@ -1,237 +0,0 @@ -/* MD2C.C - RSA Data Security, Inc., MD2 message-digest algorithm - */ - -/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All - rights reserved. - - License to copy and use this software is granted for - non-commercial Internet Privacy-Enhanced Mail provided that it is - identified as the "RSA Data Security, Inc. MD2 Message Digest - Algorithm" in all material mentioning or referencing this software - or this function. - - RSA Data Security, Inc. makes no representations concerning either - the merchantability of this software or the suitability of this - software for any particular purpose. It is provided "as is" - without express or implied warranty of any kind. - - These notices must be retained in any copies of any part of this - documentation and/or software. - */ - -#include "md2.h" - -#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */ - -static void MD2Transform PROTO_LIST - ((unsigned char [16], unsigned char [16], const unsigned char [16])); - -#ifdef HAVEMEMCOPY -#include <memory.h> -#define MD2_memcpy memcpy -#define MD2_memset memset -#else -#ifdef HAVEBCOPY -#define MD2_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c)) -#define MD2_memset(_a,_b,_c) memset((_a), '\0',(_c)) -#else -static void MD2_memcpy PROTO_LIST ((POINTER, CONST_POINTER, unsigned int)); -static void MD2_memset PROTO_LIST ((POINTER, int, unsigned int)); -#endif -#endif - -/* Permutation of 0..255 constructed from the digits of pi. It gives a - "random" nonlinear byte substitution operation. - */ -static unsigned char PI_SUBST[256] = { - 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, - 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, - 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, - 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, - 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, - 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, - 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, - 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, - 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, - 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, - 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, - 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, - 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, - 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, - 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, - 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, - 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, - 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 -}; - -static const unsigned char *PADDING[] = { - (const unsigned char *)"", - (const unsigned char *)"\001", - (const unsigned char *)"\002\002", - (const unsigned char *)"\003\003\003", - (const unsigned char *)"\004\004\004\004", - (const unsigned char *)"\005\005\005\005\005", - (const unsigned char *)"\006\006\006\006\006\006", - (const unsigned char *)"\007\007\007\007\007\007\007", - (const unsigned char *)"\010\010\010\010\010\010\010\010", - (const unsigned char *)"\011\011\011\011\011\011\011\011\011", - (const unsigned char *)"\012\012\012\012\012\012\012\012\012\012", - (const unsigned char *)"\013\013\013\013\013\013\013\013\013\013\013", - (const unsigned char *)"\014\014\014\014\014\014\014\014\014\014\014\014", - (const unsigned char *) - "\015\015\015\015\015\015\015\015\015\015\015\015\015", - (const unsigned char *) - "\016\016\016\016\016\016\016\016\016\016\016\016\016\016", - (const unsigned char *) - "\017\017\017\017\017\017\017\017\017\017\017\017\017\017\017", - (const unsigned char *) - "\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020" -}; - -/* MD2 initialization. Begins an MD2 operation, writing a new context. - */ -void MD2Init (context) -MD2_CTX *context; /* context */ -{ - context->count = 0; - MD2_memset ((POINTER)context->state, 0, sizeof (context->state)); - MD2_memset - ((POINTER)context->checksum, 0, sizeof (context->checksum)); -} - -/* MD2 block update operation. Continues an MD2 message-digest - operation, processing another message block, and updating the - context. - */ -void MD2Update (context, input, inputLen) -MD2_CTX *context; /* context */ -const unsigned char *input; /* input block */ -unsigned int inputLen; /* length of input block */ -{ - unsigned int i, index, partLen; - - /* Update number of bytes mod 16 */ - index = context->count; - context->count = (index + inputLen) & 0xf; - - partLen = 16 - index; - - /* Transform as many times as possible. - */ - if (inputLen >= partLen) { - MD2_memcpy - ((POINTER)&context->buffer[index], (CONST_POINTER)input, partLen); - MD2Transform (context->state, context->checksum, context->buffer); - - for (i = partLen; i + 15 < inputLen; i += 16) - MD2Transform (context->state, context->checksum, &input[i]); - - index = 0; - } - else - i = 0; - - /* Buffer remaining input */ - MD2_memcpy - ((POINTER)&context->buffer[index], (CONST_POINTER)&input[i], - inputLen-i); -} - -/* MD2 finalization. Ends an MD2 message-digest operation, writing the - message digest and zeroizing the context. - */ -void MD2Final (digest, context) - -unsigned char digest[16]; /* message digest */ -MD2_CTX *context; /* context */ -{ - unsigned int index, padLen; - - /* Pad out to multiple of 16. - */ - index = context->count; - padLen = 16 - index; - MD2Update (context, PADDING[padLen], padLen); - - /* Extend with checksum */ - MD2Update (context, context->checksum, 16); - - /* Store state in digest */ - MD2_memcpy ((POINTER)digest, (POINTER)context->state, 16); - - /* Zeroize sensitive information. - */ - MD2_memset ((POINTER)context, 0, sizeof (*context)); -} - -/* MD2 basic transformation. Transforms state and updates checksum - based on block. - */ -static void MD2Transform (state, checksum, block) -unsigned char state[16]; -unsigned char checksum[16]; -const unsigned char block[16]; -{ - unsigned int i, j, t; - unsigned char x[48]; - - /* Form encryption block from state, block, state ^ block. - */ - MD2_memcpy ((POINTER)x, (CONST_POINTER)state, 16); - MD2_memcpy ((POINTER)x+16, (CONST_POINTER)block, 16); - for (i = 0; i < 16; i++) - x[i+32] = state[i] ^ block[i]; - - /* Encrypt block (18 rounds). - */ - t = 0; - for (i = 0; i < 18; i++) { - for (j = 0; j < 48; j++) - t = x[j] ^= PI_SUBST[t]; - t = (t + i) & 0xff; - } - - /* Save new state */ - MD2_memcpy ((POINTER)state, (POINTER)x, 16); - - /* Update checksum. - */ - t = checksum[15]; - for (i = 0; i < 16; i++) - t = checksum[i] ^= PI_SUBST[block[i] ^ t]; - - /* Zeroize sensitive information. - */ - MD2_memset ((POINTER)x, 0, sizeof (x)); -} - -#ifndef HAVEMEMCOPY -#ifndef HAVEBCOPY -/* Note: Replace "for loop" with standard memcpy if possible. - */ -static void MD2_memcpy (output, input, len) -POINTER output; -POINTER input; -unsigned int len; -{ - unsigned int i; - - for (i = 0; i < len; i++) - output[i] = input[i]; -} - -/* Note: Replace "for loop" with standard memset if possible. - */ -static void MD2_memset (output, value, len) -POINTER output; -int value; -unsigned int len; -{ - unsigned int i; - - for (i = 0; i < len; i++) - ((char *)output)[i] = (char)value; -} -#endif -#endif - diff --git a/src/pluto/md2.h b/src/pluto/md2.h deleted file mode 100644 index b3b48dd92..000000000 --- a/src/pluto/md2.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef _GLOBAL_H_ -#define _GLOBAL_H_ -/* GLOBAL.H - RSAREF types and constants - */ - -/* PROTOTYPES should be set to one if and only if the compiler supports - function argument prototyping. - The following makes PROTOTYPES default to 0 if it has not already - been defined with C compiler flags. - */ -#ifndef PROTOTYPES -#define PROTOTYPES 1 -#endif - -/* POINTER defines a generic pointer type */ -typedef unsigned char *POINTER; -typedef const unsigned char *CONST_POINTER; - -/* UINT2 defines a two byte word */ -typedef unsigned short int UINT2; - -/* UINT4 defines a four byte word */ -typedef unsigned long int UINT4; - -/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. - If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it - returns an empty list. - */ - -#if PROTOTYPES -#define PROTO_LIST(list) list -#else -#define PROTO_LIST(list) () -#endif - -#endif - -/* MD2.H - header file for MD2C.C - */ - -/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All - rights reserved. - - License to copy and use this software is granted for - non-commercial Internet Privacy-Enhanced Mail provided that it is - identified as the "RSA Data Security, Inc. MD2 Message Digest - Algorithm" in all material mentioning or referencing this software - or this function. - - RSA Data Security, Inc. makes no representations concerning either - the merchantability of this software or the suitability of this - software for any particular purpose. It is provided "as is" - without express or implied warranty of any kind. - - These notices must be retained in any copies of any part of this - documentation and/or software. - */ - -/* MD2 context. */ -typedef struct { - unsigned char state[16]; /* state */ - unsigned char checksum[16]; /* checksum */ - unsigned int count; /* number of bytes, modulo 16 */ - unsigned char buffer[16]; /* input buffer */ -} MD2_CTX; - -void MD2Init PROTO_LIST ((MD2_CTX *)); -void MD2Update PROTO_LIST - ((MD2_CTX *, const unsigned char *, unsigned int)); -void MD2Final PROTO_LIST ((unsigned char [16], MD2_CTX *)); - -#define _MD2_H_ diff --git a/src/pluto/md5.c b/src/pluto/md5.c deleted file mode 100644 index 5d75e38a4..000000000 --- a/src/pluto/md5.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic - * changes to accomodate it in the kernel by ji. - * Minor changes to make 64 bit clean by Peter Onion (i.e. using u_int*_t). - */ - -/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm - */ - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. - */ - -/* - * Additions by JI - * - * HAVEMEMCOPY is defined if mem* routines are available - * - * HAVEHTON is defined if htons() and htonl() can be used - * for big/little endian conversions - * - */ - -#include <stddef.h> -#include <string.h> -#include <sys/types.h> /* for u_int*_t */ -#include <endian.h> /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */ - -#include "md5.h" - -#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */ - -/* Constants for MD5Transform routine. - */ - -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - -#define MD5Transform _MD5Transform - -static void MD5Transform PROTO_LIST ((UINT4 [4], const unsigned char [64])); - -#if BYTE_ORDER == LITTLE_ENDIAN -#define Encode MD5_memcpy -#define Decode MD5_memcpy -#else -static void Encode PROTO_LIST - ((unsigned char *, UINT4 *, unsigned int)); -static void Decode PROTO_LIST - ((UINT4 *, unsigned char *, unsigned int)); -#endif - -#ifdef HAVEMEMCOPY -#include <memory.h> -#define MD5_memcpy memcpy -#define MD5_memset memset -#else -#ifdef HAVEBCOPY -#define MD5_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c)) -#define MD5_memset(_a,_b,_c) memset((_a), '\0',(_c)) -#else -static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); -static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); -#endif -#endif -static unsigned char PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* F, G, H and I are basic MD5 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* ROTATE_LEFT rotates x left n bits. - */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. -Rotation is separate from addition to prevent recomputation. - */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - -/* MD5 initialization. Begins an MD5 operation, writing a new context. - */ -void MD5Init (context) -MD5_CTX *context; /* context */ -{ - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. -*/ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} - -/* MD5 block update operation. Continues an MD5 message-digest - operation, processing another message block, and updating the - context. - */ -void MD5Update (context, input, inputLen) -MD5_CTX *context; /* context */ -const unsigned char *input; /* input block */ -UINT4 inputLen; /* length of input block */ -{ - UINT4 i; - unsigned int index, partLen; - - /* Compute number of bytes mod 64 */ - index = (unsigned int)((context->count[0] >> 3) & 0x3F); - - /* Update number of bits */ - if ((context->count[0] += (inputLen << 3)) < (inputLen << 3)) - context->count[1]++; - context->count[1] += (inputLen >> 29); - - partLen = 64 - index; - - /* Transform as many times as possible. */ - if (inputLen >= partLen) { - MD5_memcpy((POINTER)&context->buffer[index], (CONSTPOINTER)input, partLen); - MD5Transform (context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) - MD5Transform (context->state, &input[i]); - - index = 0; - } - else - i = 0; - - /* Buffer remaining input */ - MD5_memcpy((POINTER)&context->buffer[index], (CONSTPOINTER)&input[i], inputLen-i); -} - -/* MD5 finalization. Ends an MD5 message-digest operation, writing the - the message digest and zeroizing the context. - */ -void MD5Final (digest, context) -unsigned char digest[16]; /* message digest */ -MD5_CTX *context; /* context */ -{ - unsigned char bits[8]; - unsigned int index, padLen; - - /* Save number of bits */ - Encode (bits, context->count, 8); - - /* Pad out to 56 mod 64. -*/ - index = (unsigned int)((context->count[0] >> 3) & 0x3f); - padLen = (index < 56) ? (56 - index) : (120 - index); - MD5Update (context, PADDING, padLen); - - /* Append length (before padding) */ - MD5Update (context, bits, 8); - - if (digest != NULL) /* Bill Simpson's padding */ - { - /* store state in digest */ - Encode (digest, context->state, 16); - - /* Zeroize sensitive information. - */ - MD5_memset ((POINTER)context, 0, sizeof (*context)); - } -} - -/* MD5 basic transformation. Transforms state based on block. - */ -static void MD5Transform (state, block) -UINT4 state[4]; -const unsigned char block[64]; -{ - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode (x, block, 64); - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ - FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ - FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ - FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ - FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ - FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ - FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ - FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ - FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ - FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ - FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ - GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ - GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ - GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ - GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ - GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ - GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ - GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ - GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ - GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ - GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ - HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ - HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ - HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ - HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ - HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ - HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ - HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ - HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ - HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ - II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ - II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ - II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ - II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ - II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ - II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ - II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ - II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ - II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* Zeroize sensitive information. -*/ - MD5_memset ((POINTER)x, 0, sizeof (x)); -} - -#if BYTE_ORDER != LITTLE_ENDIAN - -/* Encodes input (UINT4) into output (unsigned char). Assumes len is - a multiple of 4. - */ -static void Encode (output, input, len) -unsigned char *output; -UINT4 *input; -unsigned int len; -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) { - output[j] = (unsigned char)(input[i] & 0xff); - output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); - output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); - output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); - } -} - -/* Decodes input (unsigned char) into output (UINT4). Assumes len is - a multiple of 4. - */ -static void Decode (output, input, len) -UINT4 *output; -unsigned char *input; -unsigned int len; -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | - (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); -} - -#endif - -#ifndef HAVEMEMCOPY -#ifndef HAVEBCOPY -/* Note: Replace "for loop" with standard memcpy if possible. - */ - -static void MD5_memcpy (output, input, len) -POINTER output; -POINTER input; -unsigned int len; -{ - unsigned int i; - - for (i = 0; i < len; i++) - - output[i] = input[i]; -} - -/* Note: Replace "for loop" with standard memset if possible. - */ -static void MD5_memset (output, value, len) -POINTER output; -int value; -unsigned int len; -{ - unsigned int i; - - for (i = 0; i < len; i++) - ((char *)output)[i] = (char)value; -} -#endif -#endif - diff --git a/src/pluto/md5.h b/src/pluto/md5.h deleted file mode 100644 index 9b29bc46e..000000000 --- a/src/pluto/md5.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _GLOBAL_H_ -#define _GLOBAL_H_ -/* GLOBAL.H - RSAREF types and constants - */ - -/* PROTOTYPES should be set to one if and only if the compiler supports - function argument prototyping. - The following makes PROTOTYPES default to 0 if it has not already - been defined with C compiler flags. - */ -#ifndef PROTOTYPES -#define PROTOTYPES 1 -#endif - -/* POINTER defines a generic pointer type */ -typedef unsigned char *POINTER; -typedef const unsigned char *CONSTPOINTER; - -/* UINT2 defines a two byte word */ -typedef u_int16_t UINT2; - -/* UINT4 defines a four byte word */ -typedef u_int32_t UINT4; - -/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. - If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it - returns an empty list. - */ - -#if PROTOTYPES -#define PROTO_LIST(list) list -#else -#define PROTO_LIST(list) () -#endif - -#endif - -/* MD5.H - header file for MD5C.C - */ - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. - */ - -/* MD5 context. */ -typedef struct { - UINT4 state[4]; /* state (ABCD) */ - UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -} MD5_CTX; - -void MD5Init PROTO_LIST ((MD5_CTX *)); -void MD5Update PROTO_LIST - ((MD5_CTX *, const unsigned char *, UINT4)); -void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); - -#define _MD5_H_ diff --git a/src/pluto/modecfg.c b/src/pluto/modecfg.c index 93624588a..228827f2a 100644 --- a/src/pluto/modecfg.c +++ b/src/pluto/modecfg.c @@ -2,7 +2,7 @@ * 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-2007 Andreas Steffen - Hochschule fuer Technik Rapperswil + * Copyright (C) 2006-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 @@ -14,8 +14,6 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: modecfg.c 3738 2008-04-02 19:04:45Z andreas $ - * * 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 @@ -27,6 +25,9 @@ #include <freeswan.h> +#include <library.h> +#include <crypto/prfs/prf.h> + #include "constants.h" #include "defs.h" #include "state.h" @@ -34,21 +35,23 @@ #include "timer.h" #include "ipsec_doi.h" #include "log.h" -#include "md5.h" -#include "sha1.h" #include "crypto.h" #include "modecfg.h" #include "whack.h" #include "xauth.h" -#define MAX_XAUTH_TRIES 3 +#define MAX_XAUTH_TRIES 3 +#define DNS_SERVER_MAX 2 +#define NBNS_SERVER_MAX 2 #define SUPPORTED_ATTR_SET ( LELEM(INTERNAL_IP4_ADDRESS) \ - | LELEM(INTERNAL_IP4_NETMASK) \ - | LELEM(INTERNAL_IP4_DNS) \ - | LELEM(INTERNAL_IP4_NBNS) \ - | LELEM(APPLICATION_VERSION) \ - ) + | LELEM(INTERNAL_IP4_NETMASK) \ + | LELEM(INTERNAL_IP4_DNS) \ + | LELEM(INTERNAL_IP4_NBNS) \ + | LELEM(APPLICATION_VERSION) \ + | LELEM(INTERNAL_IP6_DNS) \ + | LELEM(INTERNAL_IP6_NBNS) \ + ) #define SUPPORTED_UNITY_ATTR_SET ( LELEM(UNITY_BANNER - UNITY_BASE) ) @@ -61,21 +64,21 @@ typedef struct internal_addr internal_addr_t; struct internal_addr { - lset_t attr_set; - lset_t xauth_attr_set; - lset_t unity_attr_set; + lset_t attr_set; + lset_t xauth_attr_set; + lset_t unity_attr_set; - /* ModeCfg variables */ - ip_address ipaddr; - ip_address dns[2]; - ip_address wins[2]; + /* ModeCfg variables */ + ip_address ipaddr; + ip_address dns[DNS_SERVER_MAX]; + ip_address nbns[NBNS_SERVER_MAX]; - char *unity_banner; + char *unity_banner; - /* XAUTH variables */ - u_int16_t xauth_type; - xauth_t xauth_secret; - bool xauth_status; + /* XAUTH variables */ + u_int16_t xauth_type; + xauth_t xauth_secret; + bool xauth_status; }; /* @@ -84,20 +87,30 @@ struct internal_addr static void init_internal_addr(internal_addr_t *ia) { - ia->attr_set = LEMPTY; - ia->xauth_attr_set = LEMPTY; - ia->xauth_secret.user_name = empty_chunk; - ia->xauth_secret.user_password = empty_chunk; - ia->xauth_type = XAUTH_TYPE_GENERIC; - ia->xauth_status = XAUTH_STATUS_FAIL; - ia->unity_attr_set = LEMPTY; - ia->unity_banner = NULL; - - anyaddr(AF_INET, &ia->ipaddr); - anyaddr(AF_INET, &ia->dns[0]); - anyaddr(AF_INET, &ia->dns[1]); - anyaddr(AF_INET, &ia->wins[0]); - anyaddr(AF_INET, &ia->wins[1]); + int i; + + ia->attr_set = LEMPTY; + ia->xauth_attr_set = LEMPTY; + ia->xauth_secret.user_name = chunk_empty; + ia->xauth_secret.user_password = chunk_empty; + ia->xauth_type = XAUTH_TYPE_GENERIC; + ia->xauth_status = XAUTH_STATUS_FAIL; + ia->unity_attr_set = LEMPTY; + ia->unity_banner = NULL; + + anyaddr(AF_INET, &ia->ipaddr); + + /* initialize DNS server information */ + for (i = 0; i < DNS_SERVER_MAX; i++) + { + anyaddr(AF_INET, &ia->dns[i]); + } + + /* initialize WINS server information */ + for (i = 0; i < NBNS_SERVER_MAX; i++) + { + anyaddr(AF_INET, &ia->nbns[i]); + } } /* @@ -106,97 +119,152 @@ init_internal_addr(internal_addr_t *ia) static void get_internal_addr(struct connection *c, internal_addr_t *ia) { - if (isanyaddr(&c->spd.that.host_srcip)) - { - /* not defined in connection - fetch it from LDAP */ - } - else - { - char srcip[ADDRTOT_BUF]; - - ia->ipaddr = c->spd.that.host_srcip; - - addrtot(&ia->ipaddr, 0, srcip, sizeof(srcip)); - plog("assigning virtual IP source address %s", srcip); - } - - if (!isanyaddr(&ia->ipaddr)) /* We got an IP address, send it */ - { - c->spd.that.client.addr = ia->ipaddr; - c->spd.that.client.maskbits = 32; - c->spd.that.has_client = TRUE; - - ia->attr_set = LELEM(INTERNAL_IP4_ADDRESS) - | LELEM(INTERNAL_IP4_NETMASK); - } - - if (!isanyaddr(&ia->dns[0])) /* We got DNS addresses, send them */ - ia->attr_set |= LELEM(INTERNAL_IP4_DNS); - - if (!isanyaddr(&ia->wins[0])) /* We got WINS addresses, send them */ - ia->attr_set |= LELEM(INTERNAL_IP4_NBNS); + int i, dns_idx = 0, nbns_idx = 0; + + if (isanyaddr(&c->spd.that.host_srcip)) + { + /* not defined in connection - fetch it from LDAP */ + } + else + { + char srcip[ADDRTOT_BUF]; + + ia->ipaddr = c->spd.that.host_srcip; + + addrtot(&ia->ipaddr, 0, srcip, sizeof(srcip)); + plog("assigning virtual IP source address %s", srcip); + } + + if (!isanyaddr(&ia->ipaddr)) /* We got an IP address, send it */ + { + c->spd.that.client.addr = ia->ipaddr; + c->spd.that.client.maskbits = 32; + c->spd.that.has_client = TRUE; + + ia->attr_set = LELEM(INTERNAL_IP4_ADDRESS) + | LELEM(INTERNAL_IP4_NETMASK); + } + + /* assign DNS servers */ + for (i = 1; i <= DNS_SERVER_MAX; i++) + { + char dns_key[16], *dns_str; + + snprintf(dns_key, sizeof(dns_key), "pluto.dns%d", i); + dns_str = lib->settings->get_str(lib->settings, dns_key, NULL); + if (dns_str) + { + err_t ugh; + sa_family_t family = strchr(dns_str, ':') ? AF_INET6 : AF_INET; + + ugh = ttoaddr(dns_str, 0, family, &ia->dns[dns_idx]); + if (ugh != NULL) + { + plog("error in DNS server address: %s", ugh); + continue; + } + plog("assigning DNS server %s to peer", dns_str); + + /* differentiate between IP4 and IP6 in modecfg_build_msg() */ + ia->attr_set |= LELEM(INTERNAL_IP4_DNS); + dns_idx++; + } + } + + /* assign WINS servers */ + for (i = 1; i <= NBNS_SERVER_MAX; i++) + { + char nbns_key[16], *nbns_str; + + snprintf(nbns_key, sizeof(nbns_key), "pluto.nbns%d", i); + nbns_str = lib->settings->get_str(lib->settings, nbns_key, NULL); + if (nbns_str) + { + err_t ugh; + sa_family_t family = strchr(nbns_str, ':') ? AF_INET6 : AF_INET; + + ugh = ttoaddr(nbns_str, 0, family, &ia->nbns[nbns_idx]); + if (ugh != NULL) + { + plog("error in WINS server address: %s", ugh); + continue; + } + plog("assigning NBNS server %s to peer", nbns_str); + + /* differentiate between IP4 and IP6 in modecfg_build_msg() */ + ia->attr_set |= LELEM(INTERNAL_IP4_NBNS); + nbns_idx++; + } + } } + /* * Set srcip and client subnet to internal IP address */ static bool set_internal_addr(struct connection *c, internal_addr_t *ia) { - if (ia->attr_set & LELEM(INTERNAL_IP4_ADDRESS) - && !isanyaddr(&ia->ipaddr)) - { - if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0 - || isanyaddr(&c->spd.this.host_srcip) - || sameaddr(&c->spd.this.host_srcip, &ia->ipaddr)) + if (ia->attr_set & LELEM(INTERNAL_IP4_ADDRESS) + && !isanyaddr(&ia->ipaddr)) { - char srcip[ADDRTOT_BUF]; + if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0 + || isanyaddr(&c->spd.this.host_srcip) + || sameaddr(&c->spd.this.host_srcip, &ia->ipaddr)) + { + char srcip[ADDRTOT_BUF]; - addrtot(&ia->ipaddr, 0, srcip, sizeof(srcip)); - plog("setting virtual IP source address to %s", srcip); - } - else - { - char old_srcip[ADDRTOT_BUF]; - char new_srcip[ADDRTOT_BUF]; + addrtot(&ia->ipaddr, 0, srcip, sizeof(srcip)); + plog("setting virtual IP source address to %s", srcip); + } + else + { + char old_srcip[ADDRTOT_BUF]; + char new_srcip[ADDRTOT_BUF]; - addrtot(&c->spd.this.host_srcip, 0, old_srcip, sizeof(old_srcip)); - addrtot(&ia->ipaddr, 0, new_srcip, sizeof(new_srcip)); - plog("replacing virtual IP source address %s by %s" - , old_srcip, new_srcip); + addrtot(&c->spd.this.host_srcip, 0, old_srcip, sizeof(old_srcip)); + addrtot(&ia->ipaddr, 0, new_srcip, sizeof(new_srcip)); + plog("replacing virtual IP source address %s by %s" + , old_srcip, new_srcip); + } + + /* setting srcip */ + c->spd.this.host_srcip = ia->ipaddr; + + /* setting client subnet to srcip/32 */ + addrtosubnet(&ia->ipaddr, &c->spd.this.client); + setportof(0, &c->spd.this.client.addr); + c->spd.this.has_client = TRUE; + return TRUE; } - - /* setting srcip */ - c->spd.this.host_srcip = ia->ipaddr; - - /* setting client subnet to srcip/32 */ - addrtosubnet(&ia->ipaddr, &c->spd.this.client); - setportof(0, &c->spd.this.client.addr); - c->spd.this.has_client = TRUE; - return TRUE; - } - return FALSE; + return FALSE; } /* * Compute HASH of Mode Config. */ -static size_t -modecfg_hash(u_char *dest, const u_char *start, const u_char *roof - , const struct state *st) +static size_t modecfg_hash(u_char *dest, u_char *start, u_char *roof, + const struct state *st) { - struct hmac_ctx ctx; - - hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); - hmac_update(&ctx, (const u_char *) &st->st_msgid, sizeof(st->st_msgid)); - hmac_update(&ctx, start, roof-start); - hmac_final(dest, &ctx); - - DBG(DBG_CRYPT, - DBG_log("ModeCfg HASH computed:"); - DBG_dump("", dest, ctx.hmac_digest_size) - ) - return ctx.hmac_digest_size; + 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; } @@ -205,202 +273,222 @@ modecfg_hash(u_char *dest, const u_char *start, const u_char *roof */ static stf_status modecfg_build_msg(struct state *st, pb_stream *rbody - , u_int16_t msg_type - , internal_addr_t *ia - , u_int16_t ap_id) + , u_int16_t msg_type + , internal_addr_t *ia + , u_int16_t ap_id) { - u_char *r_hash_start, *r_hashval; + u_char *r_hash_start, *r_hashval; - START_HASH_PAYLOAD(*rbody, ISAKMP_NEXT_ATTR); + START_HASH_PAYLOAD(*rbody, ISAKMP_NEXT_ATTR); - /* ATTR out */ - { - struct isakmp_mode_attr attrh; - struct isakmp_attribute attr; - pb_stream strattr,attrval; - int attr_type; - int dns_idx, wins_idx; - bool dont_advance; - bool is_xauth_attr_set = ia->xauth_attr_set != LEMPTY; - bool is_unity_attr_set = ia->unity_attr_set != LEMPTY; - lset_t attr_set = ia->attr_set; - - 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; - - attr_type = 0; - dns_idx = 0; - wins_idx = 0; - - while (attr_set != LEMPTY || is_xauth_attr_set || is_unity_attr_set) + /* ATTR out */ { - if (attr_set == LEMPTY) - { - if (is_xauth_attr_set) - { - attr_set = ia->xauth_attr_set; - attr_type = XAUTH_BASE; - is_xauth_attr_set = FALSE; - } - else + struct isakmp_mode_attr attrh; + struct isakmp_attribute attr; + pb_stream strattr,attrval; + int attr_type, dns_attr_type, nbns_attr_type; + int dns_idx, nbns_idx; + bool dont_advance; + bool is_xauth_attr_set = ia->xauth_attr_set != LEMPTY; + bool is_unity_attr_set = ia->unity_attr_set != LEMPTY; + lset_t attr_set = ia->attr_set; + + 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)) { - attr_set = ia->unity_attr_set; - attr_type = UNITY_BASE; - is_unity_attr_set = FALSE; + return STF_INTERNAL_ERROR; } - } - - dont_advance = FALSE; + attr_type = 0; + dns_idx = 0; + nbns_idx = 0; - if (attr_set & 1) - { - const u_char *byte_ptr; - u_int len; - - /* ISAKMP attr out */ - if (attr_type == XAUTH_TYPE) - { - attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TV; - attr.isaat_lv = ia->xauth_type; - } - else if (attr_type == XAUTH_STATUS) + while (attr_set != LEMPTY || is_xauth_attr_set || is_unity_attr_set) { - attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TV; - attr.isaat_lv = ia->xauth_status; - } - else - { - attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TLV; - } - out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); - - switch (attr_type) - { - case INTERNAL_IP4_ADDRESS: - if (!isanyaddr(&ia->ipaddr)) - { - len = addrbytesptr(&ia->ipaddr, &byte_ptr); - out_raw(byte_ptr, len, &attrval, "IP4_addr"); - } - break; - case INTERNAL_IP4_NETMASK: - { - u_int mask; -#if 0 - char mask[4],bits[8]={0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe}; - int t,m=st->st_connection->that.host_addr.maskbit; - for (t=0; t<4; t++) + if (attr_set == LEMPTY) { - if (m < 8) - mask[t] = bits[m]; - else - mask[t] = 0xff; - m -= 8; + if (is_xauth_attr_set) + { + attr_set = ia->xauth_attr_set; + attr_type = XAUTH_BASE; + is_xauth_attr_set = FALSE; + } + else + { + attr_set = ia->unity_attr_set; + attr_type = UNITY_BASE; + is_unity_attr_set = FALSE; + } } -#endif - if (st->st_connection->spd.this.client.maskbits == 0) - mask = 0; - else - mask = 0xffffffff * 1; - out_raw(&mask, 4, &attrval, "IP4_mask"); - } - break; - case INTERNAL_IP4_SUBNET: - { - char mask[4]; - char bits[8] = {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe}; - int t; - int m = st->st_connection->spd.this.client.maskbits; + + dont_advance = FALSE; - for (t = 0; t < 4; t++) + if (attr_set & 1) { - if (m < 8) - mask[t] = bits[m]; - else - mask[t] = 0xff; - m -= 8; - if (m < 0) - m = 0; + const u_char *byte_ptr; + u_int len; + + /* ISAKMP attr out */ + if (attr_type == XAUTH_TYPE) + { + attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TV; + attr.isaat_lv = ia->xauth_type; + } + else if (attr_type == XAUTH_STATUS) + { + attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TV; + attr.isaat_lv = ia->xauth_status; + } + else if (attr_type == INTERNAL_IP4_DNS && !isanyaddr(&ia->dns[dns_idx])) + { + dns_attr_type = (addrtypeof(&ia->dns[dns_idx]) == AF_INET) ? + INTERNAL_IP4_DNS : INTERNAL_IP6_DNS; + attr.isaat_af_type = dns_attr_type | ISAKMP_ATTR_AF_TLV; + + } + else if (attr_type == INTERNAL_IP4_NBNS && !isanyaddr(&ia->nbns[nbns_idx])) + { + nbns_attr_type = (addrtypeof(&ia->nbns[nbns_idx]) == AF_INET) ? + INTERNAL_IP4_NBNS : INTERNAL_IP6_NBNS; + attr.isaat_af_type = nbns_attr_type | ISAKMP_ATTR_AF_TLV; + + } + else + { + attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TLV; + } + out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); + + switch (attr_type) + { + case INTERNAL_IP4_ADDRESS: + if (!isanyaddr(&ia->ipaddr)) + { + len = addrbytesptr(&ia->ipaddr, &byte_ptr); + out_raw(byte_ptr, len, &attrval, "IP4_addr"); + } + break; + case INTERNAL_IP4_NETMASK: + { + u_int mask; +#if 0 + char mask[4],bits[8]={0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe}; + int t,m=st->st_connection->that.host_addr.maskbit; + for (t=0; t<4; t++) + { + if (m < 8) + mask[t] = bits[m]; + else + mask[t] = 0xff; + m -= 8; + } +#endif + if (st->st_connection->spd.this.client.maskbits == 0) + { + mask = 0; + } + else + { + mask = 0xffffffff * 1; + out_raw(&mask, 4, &attrval, "IP4_mask"); + } + } + break; + case INTERNAL_IP4_SUBNET: + { + char mask[4]; + char bits[8] = {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe}; + int t; + int m = st->st_connection->spd.this.client.maskbits; + + for (t = 0; t < 4; t++) + { + mask[t] = (m < 8) ? bits[m] : 0xff; + m -= 8; + if (m < 0) + { + m = 0; + } + } + len = addrbytesptr(&st->st_connection->spd.this.client.addr, &byte_ptr); + out_raw(byte_ptr, len, &attrval, "IP4_subnet"); + out_raw(mask, sizeof(mask), &attrval, "IP4_submsk"); + } + break; + case INTERNAL_IP4_DNS: + case INTERNAL_IP6_DNS: + if (!isanyaddr(&ia->dns[dns_idx])) + { + len = addrbytesptr(&ia->dns[dns_idx++], &byte_ptr); + out_raw(byte_ptr, len, &attrval, "IP_dns"); + } + if (dns_idx < DNS_SERVER_MAX && !isanyaddr(&ia->dns[dns_idx])) + { + dont_advance = TRUE; + } + break; + case INTERNAL_IP4_NBNS: + case INTERNAL_IP6_NBNS: + if (!isanyaddr(&ia->nbns[nbns_idx])) + { + len = addrbytesptr(&ia->nbns[nbns_idx++], &byte_ptr); + out_raw(byte_ptr, len, &attrval, "IP_nbns"); + } + if (nbns_idx < NBNS_SERVER_MAX && !isanyaddr(&ia->nbns[nbns_idx])) + { + dont_advance = TRUE; + } + break; + case XAUTH_TYPE: + break; + case XAUTH_USER_NAME: + if (ia->xauth_secret.user_name.ptr != NULL) + { + out_raw(ia->xauth_secret.user_name.ptr + , ia->xauth_secret.user_name.len + , &attrval, "xauth_user_name"); + } + break; + case XAUTH_USER_PASSWORD: + if (ia->xauth_secret.user_password.ptr != NULL) + { + out_raw(ia->xauth_secret.user_password.ptr + , ia->xauth_secret.user_password.len + , &attrval, "xauth_user_password"); + } + break; + case XAUTH_STATUS: + break; + case UNITY_BANNER: + if (ia->unity_banner != NULL) + { + out_raw(ia->unity_banner + , strlen(ia->unity_banner) + , &attrval, "UNITY_BANNER"); + } + break; + default: + plog("attempt to send unsupported mode cfg attribute %s." + , enum_show(&modecfg_attr_names, attr_type)); + break; + } + close_output_pbs(&attrval); + } + if (!dont_advance) + { + attr_type++; + attr_set >>= 1; } - len = addrbytesptr(&st->st_connection->spd.this.client.addr, &byte_ptr); - out_raw(byte_ptr, len, &attrval, "IP4_subnet"); - out_raw(mask, sizeof(mask), &attrval, "IP4_submsk"); - } - break; - case INTERNAL_IP4_DNS: - if (!isanyaddr(&ia->dns[dns_idx])) - { - len = addrbytesptr(&ia->dns[dns_idx++], &byte_ptr); - out_raw(byte_ptr, len, &attrval, "IP4_dns"); - } - if (dns_idx < 2 && !isanyaddr(&ia->dns[dns_idx])) - { - dont_advance = TRUE; - } - break; - case INTERNAL_IP4_NBNS: - if (!isanyaddr(&ia->wins[wins_idx])) - { - len = addrbytesptr(&ia->wins[wins_idx++], &byte_ptr); - out_raw(byte_ptr, len, &attrval, "IP4_wins"); - } - if (wins_idx < 2 && !isanyaddr(&ia->wins[wins_idx])) - { - dont_advance = TRUE; - } - break; - case XAUTH_TYPE: - break; - case XAUTH_USER_NAME: - if (ia->xauth_secret.user_name.ptr != NULL) - { - out_raw(ia->xauth_secret.user_name.ptr - , ia->xauth_secret.user_name.len - , &attrval, "xauth_user_name"); - } - break; - case XAUTH_USER_PASSWORD: - if (ia->xauth_secret.user_password.ptr != NULL) - { - out_raw(ia->xauth_secret.user_password.ptr - , ia->xauth_secret.user_password.len - , &attrval, "xauth_user_password"); - } - break; - case XAUTH_STATUS: - break; - case UNITY_BANNER: - if (ia->unity_banner != NULL) - { - out_raw(ia->unity_banner - , strlen(ia->unity_banner) - , &attrval, "UNITY_BANNER"); - } - break; - default: - plog("attempt to send unsupported mode cfg attribute %s." - , enum_show(&modecfg_attr_names, attr_type)); - break; } - close_output_pbs(&attrval); - } - if (!dont_advance) - { - attr_type++; - attr_set >>= 1; - } + close_message(&strattr); } - close_message(&strattr); - } - modecfg_hash(r_hashval, r_hash_start, rbody->cur, st); - close_message(rbody); - encrypt_message(rbody, st); - return STF_OK; + modecfg_hash(r_hashval, r_hash_start, rbody->cur, st); + close_message(rbody); + encrypt_message(rbody, st); + return STF_OK; } /* @@ -409,55 +497,56 @@ modecfg_build_msg(struct state *st, pb_stream *rbody static stf_status modecfg_send_msg(struct state *st, int isama_type, internal_addr_t *ia) { - 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)) + 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 */ { - return STF_INTERNAL_ERROR; + 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 */ - modecfg_build_msg(st, &rbody - , isama_type - , ia - , 0 /* XXX isama_id */ - ); - - freeanychunk(st->st_tpacket); - clonetochunk(st->st_tpacket, msg.start, pbs_offset(&msg), "ModeCfg msg"); - - /* 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; + + /* ATTR out */ + modecfg_build_msg(st, &rbody + , isama_type + , ia + , 0 /* XXX isama_id */ + ); + + 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; } /* @@ -466,111 +555,184 @@ modecfg_send_msg(struct state *st, int isama_type, internal_addr_t *ia) static stf_status modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia) { - struct isakmp_attribute attr; - pb_stream strattr; - - while (pbs_left(attrs) >= sizeof(struct isakmp_attribute)) - { - u_int16_t attr_type; - u_int16_t attr_len; + struct isakmp_attribute attr; + pb_stream strattr; + err_t ugh; + char buf[BUF_LEN]; + int dns_idx = 0; + int nbns_idx = 0; - if (!in_struct(&attr, &isakmp_modecfg_attribute_desc, attrs, &strattr)) + while (pbs_left(attrs) >= sizeof(struct isakmp_attribute)) { - return STF_FAIL; - } - attr_type = attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK; - attr_len = attr.isaat_lv; + u_int16_t attr_type; + u_int16_t attr_len; - switch (attr_type) - { - case INTERNAL_IP4_ADDRESS: - if (attr_len == 4) - { - initaddr((char *)(strattr.cur), 4, AF_INET, &ia->ipaddr); - } - /* fall through to set attribute flag */ - case INTERNAL_IP4_NETMASK: - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_SUBNET: - case INTERNAL_IP4_NBNS: - case INTERNAL_ADDRESS_EXPIRY: - case INTERNAL_IP4_DHCP: - case INTERNAL_IP6_ADDRESS: - case INTERNAL_IP6_NETMASK: - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: - case INTERNAL_IP6_DHCP: - case SUPPORTED_ATTRIBUTES: - case INTERNAL_IP6_SUBNET: - ia->attr_set |= LELEM(attr_type); - break; - case APPLICATION_VERSION: - if (attr_len > 0) - { - DBG(DBG_PARSING, - DBG_log(" '%.*s'", attr_len, strattr.cur) - ) - } - ia->attr_set |= LELEM(attr_type); - break; - case XAUTH_TYPE: - ia->xauth_type = attr.isaat_lv; - ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); - break; - case XAUTH_USER_NAME: - setchunk(ia->xauth_secret.user_name, strattr.cur, attr_len); - ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); - break; - case XAUTH_USER_PASSWORD: - setchunk(ia->xauth_secret.user_password, strattr.cur, attr_len); - ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); - break; - case XAUTH_STATUS: - ia->xauth_status = attr.isaat_lv; - ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); - break; - case XAUTH_MESSAGE: - if (attr_len > 0) - { - DBG(DBG_PARSING, - DBG_log(" '%.*s'", attr_len, strattr.cur) - ) - } - /* fall through to set attribute flag */ - case XAUTH_PASSCODE: - case XAUTH_CHALLENGE: - case XAUTH_DOMAIN: - case XAUTH_NEXT_PIN: - case XAUTH_ANSWER: - ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); - break; - case UNITY_DDNS_HOSTNAME: - if (attr_len > 0) - { - DBG(DBG_PARSING, - DBG_log(" '%.*s'", attr_len, strattr.cur) - ) - } - /* fall through to set attribute flag */ - 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: - ia->unity_attr_set |= LELEM(attr_type - UNITY_BASE); - break; - default: - plog("unsupported ModeCfg attribute %s received." - , enum_show(&modecfg_attr_names, attr_type)); - break; + 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; + + switch (attr_type) + { + case INTERNAL_IP4_ADDRESS: + if (attr_len == 4) + { + ugh = initaddr((char *)(strattr.cur), 4, AF_INET, &ia->ipaddr); + if (ugh != NULL) + { + plog("received invalid virtual IPv4 address: %s", ugh); + } + } + ia->attr_set |= LELEM(attr_type); + break; + case INTERNAL_IP4_DNS: + if (attr_len == 4 && dns_idx < DNS_SERVER_MAX) + { + ugh = initaddr((char *)(strattr.cur), 4, AF_INET, &ia->dns[dns_idx]); + if (ugh != NULL) + { + plog("received invalid IPv4 DNS server address: %s", ugh); + } + else + { + addrtot(&ia->dns[dns_idx], 0, buf, BUF_LEN); + plog("received IPv4 DNS server address %s", buf); + dns_idx++; + } + } + ia->attr_set |= LELEM(attr_type); + break; + case INTERNAL_IP4_NBNS: + if (attr_len == 4 && nbns_idx < NBNS_SERVER_MAX) + { + ugh = initaddr((char *)(strattr.cur), 4, AF_INET, &ia->nbns[nbns_idx]); + if (ugh != NULL) + { + plog("received invalid IPv4 WINS server address: %s", ugh); + } + else + { + addrtot(&ia->nbns[nbns_idx], 0, buf, BUF_LEN); + plog("received IPv4 WINS server address %s", buf); + nbns_idx++; + } + } + ia->attr_set |= LELEM(attr_type); + break; + case INTERNAL_IP6_DNS: + if (attr_len == 16 && dns_idx < DNS_SERVER_MAX) + { + ugh = initaddr((char *)(strattr.cur), 16, AF_INET6, &ia->dns[dns_idx]); + if (ugh != NULL) + { + plog("received invalid IPv6 DNS server address: %s", ugh); + } + else + { + addrtot(&ia->dns[dns_idx], 0, buf, BUF_LEN); + plog("received IPv6 DNS server address %s", buf); + dns_idx++; + } + } + ia->attr_set |= LELEM(attr_type); + break; + case INTERNAL_IP6_NBNS: + if (attr_len == 16 && nbns_idx < NBNS_SERVER_MAX) + { + ugh = initaddr((char *)(strattr.cur), 16, AF_INET6, &ia->nbns[nbns_idx]); + if (ugh != NULL) + { + plog("received invalid IPv6 WINS server address: %s", ugh); + } + else + { + addrtot(&ia->nbns[nbns_idx], 0, buf, BUF_LEN); + plog("received IPv6 WINS server address %s", buf); + nbns_idx++; + } + } + ia->attr_set |= LELEM(attr_type); + break; + case INTERNAL_IP4_NETMASK: + case INTERNAL_IP4_SUBNET: + case INTERNAL_ADDRESS_EXPIRY: + case INTERNAL_IP4_DHCP: + case INTERNAL_IP6_ADDRESS: + case INTERNAL_IP6_NETMASK: + case INTERNAL_IP6_DHCP: + case SUPPORTED_ATTRIBUTES: + case INTERNAL_IP6_SUBNET: + ia->attr_set |= LELEM(attr_type); + break; + case APPLICATION_VERSION: + if (attr_len > 0) + { + DBG(DBG_PARSING, + DBG_log(" '%.*s'", attr_len, strattr.cur) + ) + } + ia->attr_set |= LELEM(attr_type); + break; + case XAUTH_TYPE: + ia->xauth_type = attr.isaat_lv; + ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); + break; + case XAUTH_USER_NAME: + ia->xauth_secret.user_name = chunk_create(strattr.cur, attr_len); + ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); + break; + case XAUTH_USER_PASSWORD: + ia->xauth_secret.user_password = chunk_create(strattr.cur, attr_len); + ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); + break; + case XAUTH_STATUS: + ia->xauth_status = attr.isaat_lv; + ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); + break; + case XAUTH_MESSAGE: + if (attr_len > 0) + { + DBG(DBG_PARSING, + DBG_log(" '%.*s'", attr_len, strattr.cur) + ) + } + /* fall through to set attribute flag */ + case XAUTH_PASSCODE: + case XAUTH_CHALLENGE: + case XAUTH_DOMAIN: + case XAUTH_NEXT_PIN: + case XAUTH_ANSWER: + ia->xauth_attr_set |= LELEM(attr_type - XAUTH_BASE); + break; + case UNITY_DDNS_HOSTNAME: + if (attr_len > 0) + { + DBG(DBG_PARSING, + DBG_log(" '%.*s'", attr_len, strattr.cur) + ) + } + /* fall through to set attribute flag */ + 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: + ia->unity_attr_set |= LELEM(attr_type - UNITY_BASE); + break; + default: + plog("unsupported ModeCfg attribute %s received." + , enum_show(&modecfg_attr_names, attr_type)); + break; + } } - } - return STF_OK; + return STF_OK; } /* @@ -578,50 +740,52 @@ modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia) */ static stf_status modecfg_parse_msg(struct msg_digest *md, int isama_type, u_int16_t *isama_id - , internal_addr_t *ia) + , internal_addr_t *ia) { - struct state *const st = md->st; - struct payload_digest *p; - stf_status stat; + struct state *const st = md->st; + struct payload_digest *p; + stf_status stat; - st->st_msgid = md->hdr.isa_msgid; + 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"); + 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) - { - internal_addr_t ia_candidate; + /* process the ModeCfg payloads received */ + for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next) + { + internal_addr_t ia_candidate; - init_internal_addr(&ia_candidate); + init_internal_addr(&ia_candidate); - if (p->payload.attribute.isama_type == isama_type) - { - *isama_id = p->payload.attribute.isama_identifier; + if (p->payload.attribute.isama_type == isama_type) + { + *isama_id = p->payload.attribute.isama_identifier; - stat = modecfg_parse_attributes(&p->pbs, &ia_candidate); - if (stat == STF_OK) - { - /* return with a valid set of attributes */ - *ia = ia_candidate; - 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, &ia_candidate); + if (stat == STF_OK) + { + /* return with a valid set of attributes */ + *ia = ia_candidate; + 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, &ia_candidate); + stat = modecfg_parse_attributes(&p->pbs, &ia_candidate); + } + if (stat != STF_OK) + { + return stat; + } } - if (stat != STF_OK) - return stat; - } - return STF_IGNORE; + return STF_IGNORE; } /* @@ -630,20 +794,22 @@ modecfg_parse_msg(struct msg_digest *md, int isama_type, u_int16_t *isama_id stf_status modecfg_send_request(struct state *st) { - stf_status stat; - internal_addr_t ia; + stf_status stat; + internal_addr_t ia; - init_internal_addr(&ia); + init_internal_addr(&ia); - ia.attr_set = LELEM(INTERNAL_IP4_ADDRESS) - | LELEM(INTERNAL_IP4_NETMASK); + ia.attr_set = LELEM(INTERNAL_IP4_ADDRESS) + | LELEM(INTERNAL_IP4_NETMASK); - plog("sending ModeCfg request"); - st->st_state = STATE_MODE_CFG_I1; - stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia); - if (stat == STF_OK) - st->st_modecfg.started = TRUE; - return stat; + plog("sending ModeCfg request"); + st->st_state = STATE_MODE_CFG_I1; + stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia); + if (stat == STF_OK) + { + st->st_modecfg.started = TRUE; + } + return stat; } /* STATE_MODE_CFG_R0: @@ -654,38 +820,40 @@ modecfg_send_request(struct state *st) stf_status modecfg_inR0(struct msg_digest *md) { - struct state *const st = md->st; - u_int16_t isama_id; - internal_addr_t ia; - bool want_unity_banner; - stf_status stat, stat_build; - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia); - if (stat != STF_OK) - return stat; - - want_unity_banner = (ia.unity_attr_set & LELEM(UNITY_BANNER - UNITY_BASE)) != LEMPTY; + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + bool want_unity_banner; + stf_status stat, stat_build; - init_internal_addr(&ia); - get_internal_addr(st->st_connection, &ia); + stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia); + if (stat != STF_OK) + { + return stat; + } - if (want_unity_banner) - { - ia.unity_banner = UNITY_BANNER_STR; - ia.unity_attr_set |= LELEM(UNITY_BANNER - UNITY_BASE); - } + want_unity_banner = (ia.unity_attr_set & LELEM(UNITY_BANNER - UNITY_BASE)) != LEMPTY; + init_internal_addr(&ia); + get_internal_addr(st->st_connection, &ia); - plog("sending ModeCfg reply"); + if (want_unity_banner) + { + ia.unity_banner = UNITY_BANNER_STR; + ia.unity_attr_set |= LELEM(UNITY_BANNER - UNITY_BASE); + } - stat_build = modecfg_build_msg(st, &md->rbody - , ISAKMP_CFG_REPLY - , &ia - , isama_id); - if (stat_build != STF_OK) - return stat_build; + plog("sending ModeCfg reply"); - st->st_msgid = 0; - return STF_OK; + stat_build = modecfg_build_msg(st, &md->rbody + , ISAKMP_CFG_REPLY + , &ia + , isama_id); + if (stat_build != STF_OK) + { + return stat_build; + } + st->st_msgid = 0; + return STF_OK; } /* STATE_MODE_CFG_I1: @@ -696,20 +864,21 @@ modecfg_inR0(struct msg_digest *md) stf_status modecfg_inI1(struct msg_digest *md) { - struct state *const st = md->st; - u_int16_t isama_id; - internal_addr_t ia; - stf_status stat; - - plog("parsing ModeCfg reply"); + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + stf_status stat; - stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia); - if (stat != STF_OK) - return stat; + plog("parsing ModeCfg reply"); - st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia); - st->st_msgid = 0; - return STF_OK; + stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia); + if (stat != STF_OK) + { + return stat; + } + st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia); + st->st_msgid = 0; + return STF_OK; } @@ -719,23 +888,25 @@ modecfg_inI1(struct msg_digest *md) stf_status modecfg_send_set(struct state *st) { - stf_status stat; - internal_addr_t ia; + stf_status stat; + internal_addr_t ia; - init_internal_addr(&ia); - get_internal_addr(st->st_connection, &ia); + init_internal_addr(&ia); + get_internal_addr(st->st_connection, &ia); #ifdef CISCO_QUIRKS - ia.unity_banner = UNITY_BANNER_STR; - ia.unity_attr_set |= LELEM(UNITY_BANNER - UNITY_BASE); + ia.unity_banner = UNITY_BANNER_STR; + ia.unity_attr_set |= LELEM(UNITY_BANNER - UNITY_BASE); #endif plog("sending ModeCfg set"); - st->st_state = STATE_MODE_CFG_R3; - stat = modecfg_send_msg(st, ISAKMP_CFG_SET, &ia); - if (stat == STF_OK) - st->st_modecfg.started = TRUE; - return stat; + st->st_state = STATE_MODE_CFG_R3; + stat = modecfg_send_msg(st, ISAKMP_CFG_SET, &ia); + if (stat == STF_OK) + { + st->st_modecfg.started = TRUE; + } + return stat; } /* STATE_MODE_CFG_I0: @@ -746,38 +917,40 @@ modecfg_send_set(struct state *st) stf_status modecfg_inI0(struct msg_digest *md) { - struct state *const st = md->st; - u_int16_t isama_id; - internal_addr_t ia; - lset_t attr_set, unity_attr_set; - stf_status stat, stat_build; + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + lset_t attr_set, unity_attr_set; + stf_status stat, stat_build; - plog("parsing ModeCfg set"); + plog("parsing ModeCfg set"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia); - if (stat != STF_OK) - return stat; - - st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia); - - /* prepare ModeCfg ack which sends zero length attributes */ - attr_set = ia.attr_set; - unity_attr_set = ia.unity_attr_set; - init_internal_addr(&ia); - ia.attr_set = attr_set & SUPPORTED_ATTR_SET; - ia.unity_attr_set = unity_attr_set & SUPPORTED_UNITY_ATTR_SET; - - plog("sending ModeCfg ack"); - - stat_build = modecfg_build_msg(st, &md->rbody - , ISAKMP_CFG_ACK - , &ia - , isama_id); - if (stat_build != STF_OK) - return stat_build; - - st->st_msgid = 0; - return STF_OK; + stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia); + if (stat != STF_OK) + { + return stat; + } + st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia); + + /* prepare ModeCfg ack which sends zero length attributes */ + attr_set = ia.attr_set; + unity_attr_set = ia.unity_attr_set; + init_internal_addr(&ia); + ia.attr_set = attr_set & SUPPORTED_ATTR_SET; + ia.unity_attr_set = unity_attr_set & SUPPORTED_UNITY_ATTR_SET; + + plog("sending ModeCfg ack"); + + stat_build = modecfg_build_msg(st, &md->rbody + , ISAKMP_CFG_ACK + , &ia + , isama_id); + if (stat_build != STF_OK) + { + return stat_build; + } + st->st_msgid = 0; + return STF_OK; } /* STATE_MODE_CFG_R3: @@ -788,19 +961,20 @@ modecfg_inI0(struct msg_digest *md) stf_status modecfg_inR3(struct msg_digest *md) { - struct state *const st = md->st; - u_int16_t isama_id; - internal_addr_t ia; - stf_status stat; + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + stf_status stat; - plog("parsing ModeCfg ack"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia); - if (stat != STF_OK) - return stat; + plog("parsing ModeCfg ack"); - st->st_msgid = 0; - return STF_OK; + stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia); + if (stat != STF_OK) + { + return stat; + } + st->st_msgid = 0; + return STF_OK; } /* @@ -809,19 +983,21 @@ modecfg_inR3(struct msg_digest *md) stf_status xauth_send_request(struct state *st) { - stf_status stat; - internal_addr_t ia; - - init_internal_addr(&ia); - ia.xauth_attr_set = LELEM(XAUTH_USER_NAME - XAUTH_BASE) - | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE); - - plog("sending XAUTH request"); - st->st_state = STATE_XAUTH_R1; - stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia); - if (stat == STF_OK) - st->st_xauth.started = TRUE; - return stat; + stf_status stat; + internal_addr_t ia; + + init_internal_addr(&ia); + ia.xauth_attr_set = LELEM(XAUTH_USER_NAME - XAUTH_BASE) + | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE); + + plog("sending XAUTH request"); + st->st_state = STATE_XAUTH_R1; + stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia); + if (stat == STF_OK) + { + st->st_xauth.started = TRUE; + } + return stat; } /* STATE_XAUTH_I0: @@ -832,97 +1008,102 @@ xauth_send_request(struct state *st) stf_status xauth_inI0(struct msg_digest *md) { - struct state *const st = md->st; - u_int16_t isama_id; - internal_addr_t ia; - stf_status stat, stat_build; - bool xauth_type_present; + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + stf_status stat, stat_build; + bool xauth_type_present; - plog("parsing XAUTH request"); + plog("parsing XAUTH request"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia); - if (stat != STF_OK) - return stat; - - /* check XAUTH attributes */ - xauth_type_present = (ia.xauth_attr_set & LELEM(XAUTH_TYPE - XAUTH_BASE)) != LEMPTY; - - if (xauth_type_present && ia.xauth_type != XAUTH_TYPE_GENERIC) - { - plog("xauth type %s is not supported", enum_name(&xauth_type_names, ia.xauth_type)); - stat = STF_FAIL; - } - else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE)) == LEMPTY) - { - plog("user name attribute is missing in XAUTH request"); - stat = STF_FAIL; - } - else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE)) == LEMPTY) - { - plog("user password attribute is missing in XAUTH request"); - stat = STF_FAIL; - } - - /* prepare XAUTH reply */ - init_internal_addr(&ia); - - if (stat == STF_OK) - { - /* get user credentials using a plugin function */ - if (!xauth_module.get_secret(&ia.xauth_secret)) + stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia); + if (stat != STF_OK) { - plog("xauth user credentials not found"); - stat = STF_FAIL; + return stat; } - } - if (stat == STF_OK) - { - DBG(DBG_CONTROL, - DBG_log("my xauth user name is '%.*s'" - , ia.xauth_secret.user_name.len - , ia.xauth_secret.user_name.ptr) - ) - DBG(DBG_PRIVATE, - DBG_log("my xauth user password is '%.*s'" - , ia.xauth_secret.user_password.len - , ia.xauth_secret.user_password.ptr) - ) - ia.xauth_attr_set = LELEM(XAUTH_USER_NAME - XAUTH_BASE) - | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE); - if (xauth_type_present) - ia.xauth_attr_set |= LELEM(XAUTH_TYPE - XAUTH_BASE); - } - else - { - ia.xauth_attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE); - ia.xauth_status = XAUTH_STATUS_FAIL; - } - plog("sending XAUTH reply"); + /* check XAUTH attributes */ + xauth_type_present = (ia.xauth_attr_set & LELEM(XAUTH_TYPE - XAUTH_BASE)) != LEMPTY; - stat_build = modecfg_build_msg(st, &md->rbody - , ISAKMP_CFG_REPLY - , &ia - , isama_id); - if (stat_build != STF_OK) - return stat_build; + if (xauth_type_present && ia.xauth_type != XAUTH_TYPE_GENERIC) + { + plog("xauth type %s is not supported", enum_name(&xauth_type_names, ia.xauth_type)); + stat = STF_FAIL; + } + else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE)) == LEMPTY) + { + plog("user name attribute is missing in XAUTH request"); + stat = STF_FAIL; + } + else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE)) == LEMPTY) + { + plog("user password attribute is missing in XAUTH request"); + stat = STF_FAIL; + } - 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 */ - freeanychunk(st->st_tpacket); - clonetochunk(st->st_tpacket, md->reply.start - , pbs_offset(&md->reply), "XAUTH reply msg"); - send_packet(st, "XAUTH reply msg"); - delete_state(st); - return STF_IGNORE; - } + /* prepare XAUTH reply */ + init_internal_addr(&ia); + + if (stat == STF_OK) + { + /* get user credentials using a plugin function */ + if (!xauth_module.get_secret(&ia.xauth_secret)) + { + plog("xauth user credentials not found"); + stat = STF_FAIL; + } + } + if (stat == STF_OK) + { + DBG(DBG_CONTROL, + DBG_log("my xauth user name is '%.*s'" + , ia.xauth_secret.user_name.len + , ia.xauth_secret.user_name.ptr) + ) + DBG(DBG_PRIVATE, + DBG_log("my xauth user password is '%.*s'" + , ia.xauth_secret.user_password.len + , ia.xauth_secret.user_password.ptr) + ) + ia.xauth_attr_set = LELEM(XAUTH_USER_NAME - XAUTH_BASE) + | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE); + if (xauth_type_present) + { + ia.xauth_attr_set |= LELEM(XAUTH_TYPE - XAUTH_BASE); + } + } + else + { + ia.xauth_attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE); + ia.xauth_status = XAUTH_STATUS_FAIL; + } + + plog("sending XAUTH reply"); + + stat_build = modecfg_build_msg(st, &md->rbody + , ISAKMP_CFG_REPLY + , &ia + , isama_id); + 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; + } } /* STATE_XAUTH_R1: @@ -933,72 +1114,76 @@ xauth_inI0(struct msg_digest *md) stf_status xauth_inR1(struct msg_digest *md) { - struct state *const st = md->st; - u_int16_t isama_id; - internal_addr_t ia; - stf_status stat, stat_build; + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + stf_status stat, stat_build; - plog("parsing XAUTH reply"); + plog("parsing XAUTH reply"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia); - if (stat != STF_OK) - return stat; - - /* did the client return an XAUTH FAIL status? */ - if ((ia.xauth_attr_set & LELEM(XAUTH_STATUS - XAUTH_BASE)) != LEMPTY) - { - plog("received FAIL status in XAUTH reply"); - - /* client is not able to do XAUTH, delete ISAKMP SA */ - delete_state(st); - return STF_IGNORE; - } - - /* check XAUTH reply */ - if ((ia.xauth_attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE)) == LEMPTY) - { - plog("user name attribute is missing in XAUTH reply"); - st->st_xauth.status = FALSE; - } - else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE)) == LEMPTY) - { - plog("user password attribute is missing in XAUTH reply"); - st->st_xauth.status = FALSE; - } - else - { - xauth_peer_t peer; - - peer.conn_name = st->st_connection->name; - addrtot(&md->sender, 0, peer.ip_address, sizeof(peer.ip_address)); - idtoa(&md->st->st_connection->spd.that.id, peer.id, sizeof(peer.id)); - - DBG(DBG_CONTROL, - DBG_log("peer xauth user name is '%.*s'" - , ia.xauth_secret.user_name.len - , ia.xauth_secret.user_name.ptr) - ) - DBG(DBG_PRIVATE, - DBG_log("peer xauth user password is '%.*s'" - , ia.xauth_secret.user_password.len - , ia.xauth_secret.user_password.ptr) - ) - /* verify the user credentials using a plugin function */ - st->st_xauth.status = xauth_module.verify_secret(&peer, &ia.xauth_secret); - plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); - } + stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia); + if (stat != STF_OK) + { + return stat; + } + + /* did the client return an XAUTH FAIL status? */ + if ((ia.xauth_attr_set & LELEM(XAUTH_STATUS - XAUTH_BASE)) != LEMPTY) + { + plog("received FAIL status in XAUTH reply"); + + /* client is not able to do XAUTH, delete ISAKMP SA */ + delete_state(st); + return STF_IGNORE; + } + + /* check XAUTH reply */ + if ((ia.xauth_attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE)) == LEMPTY) + { + plog("user name attribute is missing in XAUTH reply"); + st->st_xauth.status = FALSE; + } + else if ((ia.xauth_attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE)) == LEMPTY) + { + plog("user password attribute is missing in XAUTH reply"); + st->st_xauth.status = FALSE; + } + else + { + xauth_peer_t peer; + + peer.conn_name = st->st_connection->name; + addrtot(&md->sender, 0, peer.ip_address, sizeof(peer.ip_address)); + idtoa(&md->st->st_connection->spd.that.id, peer.id, sizeof(peer.id)); + + DBG(DBG_CONTROL, + DBG_log("peer xauth user name is '%.*s'" + , ia.xauth_secret.user_name.len + , ia.xauth_secret.user_name.ptr) + ) + DBG(DBG_PRIVATE, + DBG_log("peer xauth user password is '%.*s'" + , ia.xauth_secret.user_password.len + , ia.xauth_secret.user_password.ptr) + ) + /* verify the user credentials using a plugin function */ + st->st_xauth.status = xauth_module.verify_secret(&peer, &ia.xauth_secret); + plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); + } - /* prepare XAUTH set which sends the authentication status */ - init_internal_addr(&ia); - ia.xauth_attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE); - ia.xauth_status = (st->st_xauth.status)? XAUTH_STATUS_OK : XAUTH_STATUS_FAIL; + /* prepare XAUTH set which sends the authentication status */ + init_internal_addr(&ia); + ia.xauth_attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE); + ia.xauth_status = (st->st_xauth.status)? XAUTH_STATUS_OK : XAUTH_STATUS_FAIL; - plog("sending XAUTH status:"); + plog("sending XAUTH status:"); - stat_build = modecfg_send_msg(st, ISAKMP_CFG_SET, &ia); - if (stat_build != STF_OK) - return stat_build; - return STF_OK; + stat_build = modecfg_send_msg(st, ISAKMP_CFG_SET, &ia); + if (stat_build != STF_OK) + { + return stat_build; + } + return STF_OK; } /* STATE_XAUTH_I1: @@ -1009,47 +1194,48 @@ xauth_inR1(struct msg_digest *md) stf_status xauth_inI1(struct msg_digest *md) { - struct state *const st = md->st; - u_int16_t isama_id; - internal_addr_t ia; - stf_status stat, stat_build; - - plog("parsing XAUTH status"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia); - if (stat != STF_OK) - { - /* notification payload - not exactly the right choice, but okay */ - md->note = ATTRIBUTES_NOT_SUPPORTED; - return stat; - } - - st->st_xauth.status = ia.xauth_status; - plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); - - plog("sending XAUTH ack"); - init_internal_addr(&ia); - stat_build = modecfg_build_msg(st, &md->rbody - , ISAKMP_CFG_ACK - , &ia - , isama_id); - 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 */ - freeanychunk(st->st_tpacket); - clonetochunk(st->st_tpacket, md->reply.start - , pbs_offset(&md->reply), "XAUTH ack msg"); - send_packet(st, "XAUTH ack msg"); - delete_state(st); - return STF_IGNORE; - } + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + stf_status stat, stat_build; + + plog("parsing XAUTH status"); + stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia); + if (stat != STF_OK) + { + /* notification payload - not exactly the right choice, but okay */ + md->note = ATTRIBUTES_NOT_SUPPORTED; + return stat; + } + + st->st_xauth.status = ia.xauth_status; + plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); + + plog("sending XAUTH ack"); + init_internal_addr(&ia); + stat_build = modecfg_build_msg(st, &md->rbody + , ISAKMP_CFG_ACK + , &ia + , isama_id); + 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; + } } /* STATE_XAUTH_R2: @@ -1060,25 +1246,26 @@ xauth_inI1(struct msg_digest *md) stf_status xauth_inR2(struct msg_digest *md) { - struct state *const st = md->st; - u_int16_t isama_id; - internal_addr_t ia; - stf_status stat; + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + stf_status stat; - plog("parsing XAUTH ack"); + plog("parsing XAUTH ack"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia); - if (stat != STF_OK) - return stat; - - st->st_msgid = 0; - if (st->st_xauth.status) - { - return STF_OK; - } - else - { - delete_state(st); - return STF_IGNORE; - } + stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia); + if (stat != STF_OK) + { + return stat; + } + 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 index 95481de89..86bfc6ed2 100644 --- a/src/pluto/modecfg.h +++ b/src/pluto/modecfg.h @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: modecfg.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _MODECFG_H diff --git a/src/pluto/mp_defs.c b/src/pluto/mp_defs.c deleted file mode 100644 index cdae8ee79..000000000 --- a/src/pluto/mp_defs.c +++ /dev/null @@ -1,70 +0,0 @@ -/* some multiprecision utilities - * 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. - * - * RCSID $Id: mp_defs.c 3252 2007-10-06 21:24:50Z andreas $ - */ - -#include <freeswan.h> - -#include "constants.h" -#include "defs.h" -#include "mp_defs.h" -#include "log.h" - -/* Convert MP_INT to network form (binary octets, big-endian). - * We do the malloc; caller must eventually do free. - */ -chunk_t -mpz_to_n(const MP_INT *mp, size_t bytes) -{ - chunk_t r; - MP_INT temp1, temp2; - int i; - - r.len = bytes; - r.ptr = alloc_bytes(r.len, "host representation of large integer"); - - mpz_init(&temp1); - mpz_init(&temp2); - - mpz_set(&temp1, mp); - - for (i = r.len-1; i >= 0; i--) - { - r.ptr[i] = mpz_mdivmod_ui(&temp2, NULL, &temp1, 1 << BITS_PER_BYTE); - mpz_set(&temp1, &temp2); - } - - passert(mpz_sgn(&temp1) == 0); /* we must have done all the bits */ - mpz_clear(&temp1); - mpz_clear(&temp2); - - return r; -} - -/* Convert network form (binary bytes, big-endian) to MP_INT. - * The *mp must not be previously mpz_inited. - */ -void -n_to_mpz(MP_INT *mp, const u_char *nbytes, size_t nlen) -{ - size_t i; - - mpz_init_set_ui(mp, 0); - - for (i = 0; i != nlen; i++) - { - mpz_mul_ui(mp, mp, 1 << BITS_PER_BYTE); - mpz_add_ui(mp, mp, nbytes[i]); - } -} diff --git a/src/pluto/mp_defs.h b/src/pluto/mp_defs.h deleted file mode 100644 index e0ec74df8..000000000 --- a/src/pluto/mp_defs.h +++ /dev/null @@ -1,36 +0,0 @@ -/* some multiprecision utilities - * 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. - * - * RCSID $Id: mp_defs.h 3252 2007-10-06 21:24:50Z andreas $ - */ - -#ifndef _MP_DEFS_H -#define _MP_DEFS_H - -#include <gmp.h> - -#include "defs.h" - -extern void n_to_mpz(MP_INT *mp, const u_char *nbytes, size_t nlen); -extern chunk_t mpz_to_n(const MP_INT *mp, size_t bytes); - -/* var := mod(base ** exp, mod), ensuring var is mpz_inited */ -#define mpz_init_powm(flag, var, base, exp, mod) { \ - if (!(flag)) \ - mpz_init(&(var)); \ - (flag) = TRUE; \ - mpz_powm(&(var), &(base), &(exp), (mod)); \ - } - -#endif /* _MP_DEFS_H */ diff --git a/src/pluto/nat_traversal.c b/src/pluto/nat_traversal.c index 95ce9e32e..de3972fe2 100644 --- a/src/pluto/nat_traversal.c +++ b/src/pluto/nat_traversal.c @@ -1,5 +1,6 @@ /* FreeS/WAN NAT-Traversal * 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 @@ -10,8 +11,6 @@ * 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. - * - * RCSID $Id: nat_traversal.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdio.h> @@ -26,10 +25,12 @@ #include <sys/queue.h> #include <freeswan.h> -#include <ipsec_policy.h> #include <pfkeyv2.h> #include <pfkey.h> +#include <library.h> +#include <crypto/hashers/hasher.h> + #include "constants.h" #include "defs.h" #include "log.h" @@ -42,8 +43,6 @@ #include "whack.h" #include "timer.h" #include "cookie.h" -#include "sha1.h" -#include "md5.h" #include "crypto.h" #include "vendor.h" #include "ike_alg.h" @@ -79,81 +78,91 @@ 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) + bool fka, bool spf) { - nat_traversal_enabled = activate; - nat_traversal_support_non_ike = activate; + nat_traversal_enabled = activate; + nat_traversal_support_non_ike = activate; #ifdef NAT_T_SUPPORT_LAST_DRAFTS - nat_traversal_support_port_floating = activate ? spf : FALSE; + 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]" : ""); + _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; + 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 *hasher, char *hash, - u_int8_t *icookie, u_int8_t *rcookie, - const ip_address *ip, u_int16_t port) +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) { - union hash_ctx ctx; - - 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 - */ - hasher->hash_init(&ctx); - hasher->hash_update(&ctx, icookie, COOKIE_SIZE); - hasher->hash_update(&ctx, rcookie, COOKIE_SIZE); - switch (addrtypeof(ip)) { - case AF_INET: - hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr - , sizeof(ip->u.v4.sin_addr.s_addr)); - break; - case AF_INET6: - hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr - , sizeof(ip->u.v6.sin6_addr.s6_addr)); - break; - } - hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t)); - hasher->hash_final(hash, &ctx); -#ifdef NAT_D_DEBUG - DBG(DBG_NATT, - DBG_log("_natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len); - DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE); - DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE); - switch (addrtypeof(ip)) { - case AF_INET: - DBG_dump("_natd_hash: ip=", &ip->u.v4.sin_addr.s_addr - , sizeof(ip->u.v4.sin_addr.s_addr)); - break; + if (is_zero_cookie(icookie)) + { + DBG_log("_natd_hash: Warning, icookie is zero !!"); } - DBG_log("_natd_hash: port=%d", port); - DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len); - ); + 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) @@ -161,180 +170,180 @@ static void _natd_hash(const struct hash_desc *hasher, char *hash, */ 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; + 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; + 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 negociation", 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 && - memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len) == 0)) - { + 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 negociation", 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)); - ) + 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 && - memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len) == 0) - { - i++; - } - } - if (!i) - { + 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)); - } - ) + 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); - } + 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); + 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) + 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), + 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 + 0 #else - ntohs(md->sender_port) + 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), + ); + 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 + 0 #else - ntohs(st->st_connection->spd.this.host_port) + 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")); + ); + return (out_generic_raw(np, &isakmp_nat_d, outs, + hash, st->st_oakley.hasher->hash_digest_len, "NAT-D")); } /* @@ -344,245 +353,245 @@ bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, */ 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 + struct payload_digest *p; + struct state *st = md->st; + int i; + ip_address ip; + + if (!st || !md->iface) { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv4 NAT-OA " - "with invalid IP size (%d)", (int)pbs_left(&p->pbs)); - return; + loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" + , __FILE__, __LINE__); + return; } - break; - case ID_IPV6_ADDR: - if (pbs_left(&p->pbs) == sizeof(struct in6_addr)) + + /* 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))) { - initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET6, &ip); + loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " + "ignored because peer is not NATed", i); + return; } - else + + if (i > 1) { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv6 NAT-OA " - "with invalid IP size (%d)", (int)pbs_left(&p->pbs)); - return; + loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " + "using first, ignoring others", i); } - 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, + /* 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) { - char ip_t[ADDRTOT_BUF]; - addrtot(&ip, 0, ip_t, sizeof(ip_t)); - - DBG_log("received NAT-OA: %s", ip_t); + 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; } - ) - if (isanyaddr(&ip)) - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %%any NAT-OA..."); - else - st->nat_oa = ip; + 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 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; + 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)) - { + 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, - "Warning: peer is NATed but source port is still udp/%d. " - "Ipsec-passthrough NAT device suspected -- NAT-T may not work.", - IKE_UDP_PORT + "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)); + 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; + 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 */ + if (_ka_evt) + return; /* event already scheduled */ - event_schedule(EVENT_NAT_T_KEEPALIVE, _kap, NULL); - _ka_evt = 1; + 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; + 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); - ) + 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 */ - setchunk(sav, st->st_tpacket.ptr, st->st_tpacket.len); + /* save state chunk */ + sav = st->st_tpacket; - /* send keep alive */ - setchunk(st->st_tpacket, &ka_payload, 1); - send_packet(st, "NAT-T Keep Alive"); + /* send keep alive */ + st->st_tpacket = chunk_create(&ka_payload, 1); + send_packet(st, "NAT-T Keep Alive"); - /* restore state chunk */ - setchunk(st->st_tpacket, sav.ptr, sav.len); + /* restore state chunk */ + st->st_tpacket = sav; } /** @@ -590,277 +599,277 @@ static void nat_traversal_send_ka (struct state *st) */ static void nat_traversal_ka_event_state (struct state *st, void *data) { - unsigned int *_kap_st = (unsigned int *)data; - const struct connection *c = st->st_connection; - - if (!c) - return; + unsigned int *_kap_st = (unsigned int *)data; + const struct connection *c = st->st_connection; - 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)) - { + 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)++; } - 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; + unsigned int _kap_st = 0; - _ka_evt = 0; /* ready to be reschedule */ + _ka_evt = 0; /* ready to be reschedule */ - for_each_state((void *)nat_traversal_ka_event_state, &_kap_st); + 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(); + /* 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; + ip_address addr; + u_int16_t sport, dport; }; static void nat_traversal_find_new_mapp_state (struct state *st, void *data) { - struct connection *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) - { + struct connection *c = st->st_connection; + struct _new_mapp_nfo *nfo = (struct _new_mapp_nfo *)data; - /* 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 (c != NULL + && sameaddr(&c->spd.that.host_addr, &(nfo->addr)) + && c->spd.that.host_port == nfo->sport) { - 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; - } + + /* 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) + 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; - } + char srca[ADDRTOT_BUF], dsta[ADDRTOT_BUF]; + struct _new_mapp_nfo nfo; - DBG_log("NAT-T: new mapping %s:%d/%d)", srca, sport, dport); + addrtot(src, 0, srca, ADDRTOT_BUF); + addrtot(dst, 0, dsta, ADDRTOT_BUF); - nfo.addr = *src; - nfo.sport = sport; - nfo.dport = dport; + 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; + } - for_each_state((void *)nat_traversal_find_new_mapp_state, &nfo); + DBG_log("NAT-T: new mapping %s:%d/%d)", srca, sport, dport); - return 0; + 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) { - struct connection *c = st ? st->st_connection : NULL; - struct iface *i = NULL; + struct connection *c = st ? st->st_connection : NULL; + struct iface *i = NULL; - if ((st == NULL) || (c == NULL)) - return; + 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) + if (md) { - nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port, - &c->spd.that.host_addr, md->sender_port); + /* + * 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 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. + * If we're initiator and NAT-T (with port floating) is detected, we + * need to change port (MAIN_I3 or QUICK_I1) */ - 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) - { + 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: using interface %s:%d", i->rname, - i->ike_float ? NAT_T_IKE_FLOAT_PORT : pluto_port); + DBG_log("NAT-T: floating to port %d", NAT_T_IKE_FLOAT_PORT); ) - c->interface = i; - break; - } + 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_klips_mapp_nfo { - struct sadb_sa *sa; - ip_address src, dst; - u_int16_t sport, dport; + struct sadb_sa *sa; + ip_address src, dst; + u_int16_t sport, dport; }; static void nat_t_new_klips_mapp (struct state *st, void *data) { - struct connection *c = st->st_connection; - struct _new_klips_mapp_nfo *nfo = (struct _new_klips_mapp_nfo *)data; - - if (c != NULL && st->st_esp.present - && sameaddr(&c->spd.that.host_addr, &(nfo->src)) - && st->st_esp.our_spi == nfo->sa->sadb_sa_spi) - { - nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port, - &(nfo->dst), nfo->dport); - } + struct connection *c = st->st_connection; + struct _new_klips_mapp_nfo *nfo = (struct _new_klips_mapp_nfo *)data; + + if (c != NULL && st->st_esp.present + && sameaddr(&c->spd.that.host_addr, &(nfo->src)) + && st->st_esp.our_spi == nfo->sa->sadb_sa_spi) + { + nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port, + &(nfo->dst), nfo->dport); + } } void process_pfkey_nat_t_new_mapping( - struct sadb_msg *msg __attribute__ ((unused)), - struct sadb_ext *extensions[SADB_EXT_MAX + 1]) + struct sadb_msg *msg __attribute__ ((unused)), + struct sadb_ext *extensions[SADB_EXT_MAX + 1]) { - struct _new_klips_mapp_nfo nfo; - struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC]; - struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST]; - struct sockaddr *srca, *dsta; - err_t ugh = NULL; - - nfo.sa = (void *) extensions[SADB_EXT_SA]; - - if (!nfo.sa || !srcx || !dstx) - { - plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: " - "got NULL params"); - return; - } - - srca = ((struct sockaddr *)(void *)&srcx[1]); - dsta = ((struct sockaddr *)(void *)&dstx[1]); - - if (srca->sa_family != AF_INET || dsta->sa_family != AF_INET) - { - ugh = "only AF_INET supported"; - } - else - { - char text_said[SATOT_BUF]; - char _srca[ADDRTOT_BUF], _dsta[ADDRTOT_BUF]; - ip_said said; - - initaddr((const void *) &((const struct sockaddr_in *)srca)->sin_addr, - sizeof(((const struct sockaddr_in *)srca)->sin_addr), - srca->sa_family, &(nfo.src)); - nfo.sport = ntohs(((const struct sockaddr_in *)srca)->sin_port); - initaddr((const void *) &((const struct sockaddr_in *)dsta)->sin_addr, - sizeof(((const struct sockaddr_in *)dsta)->sin_addr), - dsta->sa_family, &(nfo.dst)); - nfo.dport = ntohs(((const struct sockaddr_in *)dsta)->sin_port); + struct _new_klips_mapp_nfo nfo; + struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC]; + struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST]; + struct sockaddr *srca, *dsta; + err_t ugh = NULL; - DBG(DBG_NATT, - initsaid(&nfo.src, nfo.sa->sadb_sa_spi, SA_ESP, &said); - satot(&said, 0, text_said, SATOT_BUF); - addrtot(&nfo.src, 0, _srca, ADDRTOT_BUF); - addrtot(&nfo.dst, 0, _dsta, ADDRTOT_BUF); - DBG_log("new klips mapping %s %s:%d %s:%d", - text_said, _srca, nfo.sport, _dsta, nfo.dport); - ) + nfo.sa = (void *) extensions[SADB_EXT_SA]; - for_each_state((void *)nat_t_new_klips_mapp, &nfo); - } + if (!nfo.sa || !srcx || !dstx) + { + plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: " + "got NULL params"); + return; + } + + srca = ((struct sockaddr *)(void *)&srcx[1]); + dsta = ((struct sockaddr *)(void *)&dstx[1]); + + if (srca->sa_family != AF_INET || dsta->sa_family != AF_INET) + { + ugh = "only AF_INET supported"; + } + else + { + char text_said[SATOT_BUF]; + char _srca[ADDRTOT_BUF], _dsta[ADDRTOT_BUF]; + ip_said said; + + initaddr((const void *) &((const struct sockaddr_in *)srca)->sin_addr, + sizeof(((const struct sockaddr_in *)srca)->sin_addr), + srca->sa_family, &(nfo.src)); + nfo.sport = ntohs(((const struct sockaddr_in *)srca)->sin_port); + initaddr((const void *) &((const struct sockaddr_in *)dsta)->sin_addr, + sizeof(((const struct sockaddr_in *)dsta)->sin_addr), + dsta->sa_family, &(nfo.dst)); + nfo.dport = ntohs(((const struct sockaddr_in *)dsta)->sin_port); + + DBG(DBG_NATT, + initsaid(&nfo.src, nfo.sa->sadb_sa_spi, SA_ESP, &said); + satot(&said, 0, text_said, SATOT_BUF); + addrtot(&nfo.src, 0, _srca, ADDRTOT_BUF); + addrtot(&nfo.dst, 0, _dsta, ADDRTOT_BUF); + DBG_log("new klips mapping %s %s:%d %s:%d", + text_said, _srca, nfo.sport, _dsta, nfo.dport); + ) + + for_each_state((void *)nat_t_new_klips_mapp, &nfo); + } - if (ugh != NULL) - plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: %s", ugh); + if (ugh != NULL) + plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: %s", ugh); } diff --git a/src/pluto/nat_traversal.h b/src/pluto/nat_traversal.h index 9041d84de..98b0a2bc0 100644 --- a/src/pluto/nat_traversal.h +++ b/src/pluto/nat_traversal.h @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: nat_traversal.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _NAT_TRAVERSAL_H @@ -32,37 +30,37 @@ * 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) ) + ( 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) ) + ( 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) ) + ( 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) ) + ( 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) ) + ( LELEM(NAT_TRAVERSAL_RFC) ) /** * NAT-Traversal detected */ #define NAT_T_DETECTED \ - ( LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER) ) + ( LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER) ) /** * NAT-T Port Floating @@ -70,7 +68,7 @@ #define NAT_T_IKE_FLOAT_PORT 4500 void init_nat_traversal (bool activate, unsigned int keep_alive_period, - bool fka, bool spf); + bool fka, bool spf); extern bool nat_traversal_enabled; extern bool nat_traversal_support_non_ike; @@ -82,7 +80,7 @@ extern bool nat_traversal_support_port_floating; 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); + struct msg_digest *md); #endif /** @@ -91,7 +89,7 @@ bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, 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); + struct state *st); #endif /** @@ -119,8 +117,8 @@ void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st); */ #ifdef __PFKEY_V2_H void process_pfkey_nat_t_new_mapping( - struct sadb_msg *, - struct sadb_ext *[SADB_EXT_MAX + 1]); + struct sadb_msg *, + struct sadb_ext *[SADB_EXT_MAX + 1]); #endif /** @@ -133,22 +131,22 @@ 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) \ - ) \ - ) + ((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 index 74b86bf19..80164fa1d 100644 --- a/src/pluto/ocsp.c +++ b/src/pluto/ocsp.c @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: ocsp.c 4827 2009-01-09 01:36:13Z andreas $ */ #include <unistd.h> @@ -24,7 +22,13 @@ #include <fcntl.h> #include <freeswan.h> -#include <ipsec_policy.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" @@ -32,120 +36,116 @@ #include "x509.h" #include "crl.h" #include "ca.h" -#include "rnd.h" -#include "asn1.h" #include "certs.h" #include "smartcard.h" -#include <asn1/oid.h> #include "whack.h" -#include "pkcs1.h" #include "keys.h" #include "fetch.h" #include "ocsp.h" -#define NONCE_LENGTH 16 +#define NONCE_LENGTH 16 static const char *const cert_status_names[] = { - "good", - "revoked", - "unknown", - "undefined" + "good", + "revoked", + "unknown", + "undefined" }; static const char *const response_status_names[] = { - "successful", - "malformed request", - "internal error", - "try later", - "status #4", - "signature required", - "unauthorized" + "successful", + "malformed request", + "internal error", + "try later", + "status #4", + "signature required", + "unauthorized" }; /* response container */ typedef struct response response_t; struct response { - chunk_t tbs; - chunk_t responder_id_name; - chunk_t responder_id_key; - time_t produced_at; - chunk_t responses; - chunk_t nonce; - int algorithm; - chunk_t signature; + chunk_t tbs; + chunk_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, 0 } , /* 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 */ + { NULL, 0 } , /* tbs */ + { NULL, 0 } , /* 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; + 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 */ - REASON_UNSPECIFIED, /* revocationReason */ - UNDEFINED_TIME , /* this_update */ - UNDEFINED_TIME /* next_update */ + 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 */ + 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; + chunk_t request; + request_list_t *next; }; /* some OCSP specific prefabricated ASN.1 constants */ static u_char ASN1_nonce_oid_str[] = { - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 + 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 }; -static const chunk_t ASN1_nonce_oid = strchunk(ASN1_nonce_oid_str); +static const chunk_t ASN1_nonce_oid = chunk_from_buf(ASN1_nonce_oid_str); static u_char ASN1_response_oid_str[] = { - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 + 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 }; -static const chunk_t ASN1_response_oid = strchunk(ASN1_response_oid_str); +static const chunk_t ASN1_response_oid = chunk_from_buf(ASN1_response_oid_str); static u_char ASN1_response_content_str[] = { - 0x04, 0x0D, - 0x30, 0x0B, - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 + 0x04, 0x0D, + 0x30, 0x0B, + 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 }; -static const chunk_t ASN1_response_content = strchunk(ASN1_response_content_str); +static const chunk_t ASN1_response_content = chunk_from_buf(ASN1_response_content_str); /* default OCSP uri */ static chunk_t ocsp_default_uri; @@ -158,57 +158,60 @@ static x509cert_t *ocsp_requestor_cert = NULL; static smartcard_t *ocsp_requestor_sc = NULL; -static const struct RSA_private_key *ocsp_requestor_pri = NULL; - -/* asn.1 definitions for parsing */ +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, "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 -#define OCSP_RESPONSE_ROOF 7 +#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 */ - { 4, "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_OBJ }, /* 24 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */ + { 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 */ + { 4, "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 @@ -221,1349 +224,1326 @@ static const asn1Object_t basicResponseObjects[] = { #define BASIC_RESPONSE_ALGORITHM 20 #define BASIC_RESPONSE_SIGNATURE 21 #define BASIC_RESPONSE_CERTIFICATE 24 -#define BASIC_RESPONSE_ROOF 27 +/** + * 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, "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 -#define RESPONSES_SINGLE_RESPONSE 1 -#define RESPONSES_ROOF 3 - +/** + * 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, "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_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 -#define SINGLE_RESPONSE_ROOF 28 - -/* build an ocsp location from certificate information +#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 x509cert_t *cert, ocsp_location_t *location) +static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location) { - static u_char digest[SHA1_DIGEST_SIZE]; /* temporary storage */ + hasher_t *hasher; + static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */ + + location->uri = cert->accessLocation; - location->uri = cert->accessLocation; + if (location->uri.ptr == NULL) + { + ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber + , cert->authKeyID); + if (ca != NULL && ca->ocspuri != NULL) + { + location->uri = chunk_create(ca->ocspuri, strlen(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, cert->issuer, digest); + hasher->destroy(hasher); - if (location->uri.ptr == NULL) - { - ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID); - if (ca != NULL && ca->ocspuri != NULL) - setchunk(location->uri, ca->ocspuri, strlen(ca->ocspuri)) - else - /* abort if no ocsp location uri is defined */ - return FALSE; - } - - setchunk(location->authNameID, digest, SHA1_DIGEST_SIZE); - compute_digest(cert->issuer, OID_SHA1, &location->authNameID); - - location->next = NULL; - location->issuer = cert->issuer; - location->authKeyID = cert->authKeyID; - location->authKeySerialNumber = cert->authKeySerialNumber; - - if (cert->authKeyID.ptr == NULL) - { - x509cert_t *authcert = get_authcert(cert->issuer - , cert->authKeySerialNumber, cert->authKeyID, AUTH_CA); - - if (authcert != NULL) + location->next = NULL; + location->issuer = cert->issuer; + location->authKeyID = cert->authKeyID; + location->authKeySerialNumber = cert->authKeySerialNumber; + + if (cert->authKeyID.ptr == NULL) { - location->authKeyID = authcert->subjectKeyID; - location->authKeySerialNumber = authcert->serialNumber; + x509cert_t *authcert = get_authcert(cert->issuer + , cert->authKeySerialNumber, cert->authKeyID, AUTH_CA); + + if (authcert != NULL) + { + location->authKeyID = authcert->subjectKeyID; + location->authKeySerialNumber = authcert->serialNumber; + } } - } - location->nonce = empty_chunk; - location->certinfo = NULL; + location->nonce = chunk_empty; + location->certinfo = NULL; - return TRUE; + return TRUE; } -/* - * compare two ocsp locations for equality +/** + * Compare two ocsp locations for equality */ -static bool -same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b) +static bool same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b) { - return ((a->authKeyID.ptr != NULL) - ? same_keyid(a->authKeyID, b->authKeyID) - : (same_dn(a->issuer, b->issuer) - && same_serial(a->authKeySerialNumber, b->authKeySerialNumber))) - && same_chunk(a->uri, b->uri); + return ((a->authKeyID.ptr != NULL) + ? same_keyid(a->authKeyID, b->authKeyID) + : (same_dn(a->issuer, b->issuer) + && same_serial(a->authKeySerialNumber, b->authKeySerialNumber))) + && chunk_equals(a->uri, b->uri); } -/* - * find an existing ocsp location in a chained list +/** + * Find an existing ocsp location in a chained list */ -ocsp_location_t* -get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain) +ocsp_location_t* get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain) { - while (chain != NULL) - { - if (same_ocsp_location(loc, chain)) - return chain; - chain = chain->next; - } - return NULL; + while (chain != NULL) + { + if (same_ocsp_location(loc, chain)) + return chain; + chain = chain->next; + } + return NULL; } - -/* retrieves the status of a cert from the ocsp cache + +/** + * 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) +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; + ocsp_certinfo_t *certinfo, **certinfop; + int cmp = -1; - /* find location */ - ocsp_location_t *location = get_ocsp_location(loc, ocsp_cache); + /* 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; + if (location == NULL) + return CERT_UNDEFINED; - while (certinfo != NULL) - { - cmp = cmp_chunk(serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; + /* traverse list of certinfos in increasing order */ + certinfop = &location->certinfo; certinfo = *certinfop; - } - if (cmp == 0) - { - *nextUpdate = certinfo->nextUpdate; - *revocationTime = certinfo->revocationTime; - *revocationReason = certinfo->revocationReason; - return certinfo->status; - } + while (certinfo != NULL) + { + 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; + return CERT_UNDEFINED; } -/* - * verify the ocsp status of a certificate +/** + * Verify the ocsp status of a certificate */ -cert_status_t -verify_by_ocsp(const x509cert_t *cert, time_t *until -, time_t *revocationDate, crl_reason_t *revocationReason) +cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until, + time_t *revocationDate, + crl_reason_t *revocationReason) { - cert_status_t status; - ocsp_location_t location; - time_t nextUpdate = 0; - - *revocationDate = UNDEFINED_TIME; - *revocationReason = REASON_UNSPECIFIED; - - /* is an ocsp location defined? */ - if (!build_ocsp_location(cert, &location)) - return CERT_UNDEFINED; + cert_status_t status; + ocsp_location_t location; + time_t nextUpdate = 0; + + *revocationDate = UNDEFINED_TIME; + *revocationReason = 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, cert->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, cert->serialNumber); - lock_ocsp_cache("verify_by_ocsp"); - status = get_ocsp_status(&location, cert->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, cert->serialNumber); - - /* inititate fetching of ocsp status */ - wake_fetch_thread("verify_by_ocsp"); - } - *until = nextUpdate; - return status; + /* inititate fetching of ocsp status */ + wake_fetch_thread("verify_by_ocsp"); + } + *until = nextUpdate; + return status; } -/* - * check if an ocsp status is about to expire +/** + * Check if an ocsp status is about to expire */ -void -check_ocsp(void) +void check_ocsp(void) { - ocsp_location_t *location; - - lock_ocsp_cache("check_ocsp"); - location = ocsp_cache; - - while (location != NULL) - { - char buf[BUF_LEN]; - bool first = TRUE; - ocsp_certinfo_t *certinfo = location->certinfo; + ocsp_location_t *location; - while (certinfo != NULL) + lock_ocsp_cache("check_ocsp"); + location = ocsp_cache; + + while (location != NULL) { - if (!certinfo->once) - { - time_t time_left = certinfo->nextUpdate - time(NULL); + char buf[BUF_LEN]; + bool first = TRUE; + ocsp_certinfo_t *certinfo = location->certinfo; - DBG(DBG_CONTROL, - if (first) - { - dntoa(buf, BUF_LEN, location->issuer); - DBG_log("issuer: '%s'", buf); - if (location->authKeyID.ptr != NULL) + while (certinfo != NULL) + { + if (!certinfo->once) { - datatot(location->authKeyID.ptr, location->authKeyID.len - , ':', buf, BUF_LEN); - DBG_log("authkey: %s", buf); + time_t time_left = certinfo->nextUpdate - time(NULL); + + DBG(DBG_CONTROL, + if (first) + { + dntoa(buf, BUF_LEN, location->issuer); + DBG_log("issuer: '%s'", buf); + if (location->authKeyID.ptr != NULL) + { + 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); } - 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; + certinfo = certinfo->next; + } + location = location->next; } - location = location->next; - } - unlock_ocsp_cache("check_ocsp"); + unlock_ocsp_cache("check_ocsp"); } -/* +/** * frees the allocated memory of a certinfo struct */ -static void -free_certinfo(ocsp_certinfo_t *certinfo) +static void free_certinfo(ocsp_certinfo_t *certinfo) { - freeanychunk(certinfo->serialNumber); - pfree(certinfo); + free(certinfo->serialNumber.ptr); + free(certinfo); } -/* +/** * frees all certinfos in a chained list */ -static void -free_certinfos(ocsp_certinfo_t *chain) +static void free_certinfos(ocsp_certinfo_t *chain) { - ocsp_certinfo_t *certinfo; + ocsp_certinfo_t *certinfo; - while (chain != NULL) - { - certinfo = chain; - chain = chain->next; - free_certinfo(certinfo); - } + while (chain != NULL) + { + certinfo = chain; + chain = chain->next; + free_certinfo(certinfo); + } } -/* - * frees the memory allocated to an ocsp location including all certinfos +/** + * Frees the memory allocated to an ocsp location including all certinfos */ -static void -free_ocsp_location(ocsp_location_t* location) +static void free_ocsp_location(ocsp_location_t* location) { - freeanychunk(location->issuer); - freeanychunk(location->authNameID); - freeanychunk(location->authKeyID); - freeanychunk(location->authKeySerialNumber); - freeanychunk(location->uri); - free_certinfos(location->certinfo); - pfree(location); + free(location->issuer.ptr); + free(location->authNameID.ptr); + free(location->authKeyID.ptr); + free(location->authKeySerialNumber.ptr); + free(location->uri.ptr); + free_certinfos(location->certinfo); + free(location); } /* - * free a chained list of ocsp locations + * Free a chained list of ocsp locations */ -void -free_ocsp_locations(ocsp_location_t **chain) +void free_ocsp_locations(ocsp_location_t **chain) { - while (*chain != NULL) - { - ocsp_location_t *location = *chain; - *chain = location->next; - free_ocsp_location(location); - } + while (*chain != NULL) + { + ocsp_location_t *location = *chain; + *chain = location->next; + free_ocsp_location(location); + } } -/* - * free the ocsp cache +/** + * Free the ocsp cache */ -void -free_ocsp_cache(void) +void free_ocsp_cache(void) { - lock_ocsp_cache("free_ocsp_cache"); - free_ocsp_locations(&ocsp_cache); - unlock_ocsp_cache("free_ocsp_cache"); + lock_ocsp_cache("free_ocsp_cache"); + free_ocsp_locations(&ocsp_cache); + unlock_ocsp_cache("free_ocsp_cache"); } -/* - * frees the ocsp cache and global variables +/** + * Frees the ocsp cache and global variables */ -void -free_ocsp(void) +void free_ocsp(void) { - pfreeany(ocsp_default_uri.ptr); - free_ocsp_cache(); + free(ocsp_default_uri.ptr); + free_ocsp_cache(); } -/* - * list a chained list of ocsp_locations +/** + * List a chained list of ocsp_locations */ -void -list_ocsp_locations(ocsp_location_t *location, bool requests, bool utc -, bool strict) +void list_ocsp_locations(ocsp_location_t *location, bool requests, + bool utc, bool strict) { - bool first = TRUE; - - while (location != NULL) - { - ocsp_certinfo_t *certinfo = location->certinfo; + bool first = TRUE; - if (certinfo != NULL) + while (location != NULL) { - u_char buf[BUF_LEN]; - - 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.ptr != NULL) - { - dntoa(buf, BUF_LEN, location->issuer); - whack_log(RC_COMMENT, " issuer: '%s'", buf); - } - whack_log(RC_COMMENT, " uri: '%.*s'", (int)location->uri.len - , location->uri.ptr); - if (location->authNameID.ptr != NULL) - { - datatot(location->authNameID.ptr, location->authNameID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authname: %s", buf); - } - if (location->authKeyID.ptr != NULL) - { - datatot(location->authKeyID.ptr, location->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); - } - if (location->authKeySerialNumber.ptr != NULL) - { - datatot(location->authKeySerialNumber.ptr - , location->authKeySerialNumber.len, ':', buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); - } - while (certinfo != NULL) - { - char thisUpdate[TIMETOA_BUF]; - - strcpy(thisUpdate, timetoa(&certinfo->thisUpdate, utc)); - - if (requests) - { - whack_log(RC_COMMENT, "%s, trials: %d", thisUpdate - , certinfo->trials); - } - else if (certinfo->once) - { - whack_log(RC_COMMENT, "%s, onetime use%s", thisUpdate - , (certinfo->nextUpdate < time(NULL))? " (expired)": ""); - } - else + ocsp_certinfo_t *certinfo = location->certinfo; + + if (certinfo != NULL) { - whack_log(RC_COMMENT, "%s, until %s %s", thisUpdate - , timetoa(&certinfo->nextUpdate, utc) - , check_expiry(certinfo->nextUpdate, OCSP_WARNING_INTERVAL, strict)); + u_char buf[BUF_LEN]; + + 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.ptr != NULL) + { + dntoa(buf, BUF_LEN, location->issuer); + whack_log(RC_COMMENT, " issuer: '%s'", buf); + } + whack_log(RC_COMMENT, " uri: '%.*s'", (int)location->uri.len + , location->uri.ptr); + if (location->authNameID.ptr != NULL) + { + datatot(location->authNameID.ptr, location->authNameID.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " authname: %s", buf); + } + if (location->authKeyID.ptr != NULL) + { + datatot(location->authKeyID.ptr, location->authKeyID.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " authkey: %s", buf); + } + if (location->authKeySerialNumber.ptr != NULL) + { + datatot(location->authKeySerialNumber.ptr + , location->authKeySerialNumber.len, ':', buf, BUF_LEN); + whack_log(RC_COMMENT, " aserial: %s", buf); + } + while (certinfo != NULL) + { + char thisUpdate[BUF_LEN]; + + snprintf(thisUpdate, BUF_LEN, "%T", &certinfo->thisUpdate, utc); + + if (requests) + { + whack_log(RC_COMMENT, "%s, trials: %d", thisUpdate + , certinfo->trials); + } + else if (certinfo->once) + { + whack_log(RC_COMMENT, "%s, onetime use%s", thisUpdate + , (certinfo->nextUpdate < time(NULL))? " (expired)": ""); + } + else + { + whack_log(RC_COMMENT, "%s, until %T %s", thisUpdate + , &certinfo->nextUpdate, utc + , check_expiry(certinfo->nextUpdate, OCSP_WARNING_INTERVAL, strict)); + } + datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len, ':' + , buf, BUF_LEN); + whack_log(RC_COMMENT, " serial: %s, %s", buf + , cert_status_names[certinfo->status]); + certinfo = certinfo->next; + } } - datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " serial: %s, %s", buf - , cert_status_names[certinfo->status]); - certinfo = certinfo->next; - } + location = location->next; } - location = location->next; - } } -/* - * list the ocsp cache +/** + * List the ocsp cache */ -void -list_ocsp_cache(bool utc, bool strict) +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"); + 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) +static bool get_ocsp_requestor_cert(ocsp_location_t *location) { - x509cert_t *cert = NULL; + x509cert_t *cert = NULL; - /* initialize temporary static storage */ - ocsp_requestor_cert = NULL; - ocsp_requestor_sc = NULL; - ocsp_requestor_pri = NULL; + /* initialize temporary static storage */ + ocsp_requestor_cert = NULL; + ocsp_requestor_sc = NULL; + ocsp_requestor_key = NULL; - for (;;) - { - char buf[BUF_LEN]; - - /* looking for a certificate from the same issuer */ - cert = get_x509cert(location->issuer, location->authKeySerialNumber - ,location->authKeyID, cert); - if (cert == NULL) - break; - - DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, cert->subject); - DBG_log("candidate: '%s'", buf); - ) - - if (cert->smartcard) + for (;;) { - /* look for a matching private key on a smartcard */ - smartcard_t *sc = scx_get(cert); + char buf[BUF_LEN]; + + /* looking for a certificate from the same issuer */ + cert = get_x509cert(location->issuer, location->authKeySerialNumber + ,location->authKeyID, cert); + if (cert == NULL) + break; - if (sc != NULL) - { DBG(DBG_CONTROL, - DBG_log("matching smartcard found") + dntoa(buf, BUF_LEN, cert->subject); + DBG_log("candidate: '%s'", buf); ) - if (sc->valid) + + if (cert->smartcard) { - ocsp_requestor_cert = cert; - ocsp_requestor_sc = sc; - return TRUE; + /* look for a matching private key on a smartcard */ + smartcard_t *sc = scx_get(cert); + + if (sc != NULL) + { + 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"); + } } - plog("unable to sign ocsp request without PIN"); - } - } - else - { - /* look for a matching private key in the chained list */ - const struct RSA_private_key *pri = get_x509_private_key(cert); + else + { + /* look for a matching private key in the chained list */ + private_key_t *private = get_x509_private_key(cert); - if (pri != NULL) - { - DBG(DBG_CONTROL, - DBG_log("matching private key found") - ) - ocsp_requestor_cert = cert; - ocsp_requestor_pri = pri; - return TRUE; - } + if (private != NULL) + { + DBG(DBG_CONTROL, + DBG_log("matching private key found") + ) + ocsp_requestor_cert = cert; + ocsp_requestor_key = private; + return TRUE; + } + } } - } - return FALSE; + return FALSE; } -static chunk_t -generate_signature(chunk_t digest, smartcard_t *sc - , const RSA_private_key_t *pri) +static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc) { - chunk_t sigdata; - u_char *pos; - size_t siglen = 0; - - if (sc != NULL) - { - /* RSA signature is done on smartcard */ + hasher_t *hasher; + u_char *pos; + u_char digest_buf[HASH_SIZE_SHA1]; + chunk_t digest = chunk_from_buf(digest_buf); + chunk_t digest_info, sigdata; + size_t siglen = 0; if (!scx_establish_context(sc) || !scx_login(sc)) { - scx_release_context(sc); - return empty_chunk; + 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 empty_chunk; + 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) + DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)" + , (int)sc->slot, sc->id) ) - pos = build_asn1_object(&sigdata, ASN1_BIT_STRING, 1 + siglen); + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (hasher == NULL) + { + return chunk_empty; + } + hasher->get_hash(hasher, tbs, digest_buf); + 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, "cm" + , asn1_algorithmIdentifier(OID_SHA1) + , asn1_simple_object(ASN1_OCTET_STRING, digest)); + + pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen); *pos++ = 0x00; - scx_sign_hash(sc, digest.ptr, digest.len, pos, siglen); + scx_sign_hash(sc, digest_info.ptr, digest_info.len, pos, siglen); + free(digest_info.ptr); + if (!pkcs11_keep_state) - scx_release_context(sc); - } - else - { - /* RSA signature is done in software */ - siglen = pri->pub.k; - pos = build_asn1_object(&sigdata, ASN1_BIT_STRING, 1 + siglen); - *pos++ = 0x00; - sign_hash(pri, digest.ptr, digest.len, pos, siglen); - } - return sigdata; + { + 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 +/** + * 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) +static chunk_t build_signature(chunk_t tbsRequest) { - chunk_t sigdata, certs; - chunk_t digest_info; - - u_char digest_buf[MAX_DIGEST_LEN]; - chunk_t digest_raw = { digest_buf, MAX_DIGEST_LEN }; - - if (!compute_digest(tbsRequest, OID_SHA1, &digest_raw)) - return empty_chunk; - - /* according to PKCS#1 v2.1 digest must be packaged into - * an ASN.1 structure for encryption - */ - digest_info = asn1_wrap(ASN1_SEQUENCE, "cm" - , ASN1_sha1_id - , asn1_simple_object(ASN1_OCTET_STRING, digest_raw)); - - /* generate the RSA signature */ - sigdata = generate_signature(digest_info - , ocsp_requestor_sc - , ocsp_requestor_pri); - freeanychunk(digest_info); - - /* has the RSA signature generation been successful? */ - if (sigdata.ptr == NULL) - return empty_chunk; - - /* include our certificate */ - certs = asn1_wrap(ASN1_CONTEXT_C_0, "m" - , asn1_simple_object(ASN1_SEQUENCE - , ocsp_requestor_cert->certificate - ) - ); - - /* build signature comprising algorithm, signature and cert */ - return asn1_wrap(ASN1_CONTEXT_C_0, "m" - , asn1_wrap(ASN1_SEQUENCE, "cmm" - , ASN1_sha1WithRSA_id - , sigdata - , certs - ) - ); + chunk_t sigdata, certs; + + if (ocsp_requestor_sc != NULL) + { + /* 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 */ + certs = asn1_wrap(ASN1_CONTEXT_C_0, "m" + , asn1_simple_object(ASN1_SEQUENCE + , ocsp_requestor_cert->certificate + ) + ); + + /* build signature comprising algorithm, signature and cert */ + return asn1_wrap(ASN1_CONTEXT_C_0, "m" + , asn1_wrap(ASN1_SEQUENCE, "cmm" + , asn1_algorithmIdentifier(OID_SHA1_WITH_RSA) + , sigdata + , certs + ) + ); } -/* build request (into requestList) +/** + * Build request (into requestList) * no singleRequestExtensions used */ -static chunk_t -build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo) +static chunk_t build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo) { - chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm" - , ASN1_sha1_id - , asn1_simple_object(ASN1_OCTET_STRING, location->authNameID) - , asn1_simple_object(ASN1_OCTET_STRING, location->authKeyID) - , asn1_simple_object(ASN1_INTEGER, certinfo->serialNumber)); + chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm" + , 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); + return asn1_wrap(ASN1_SEQUENCE, "m", reqCert); } -/* +/** * build requestList (into TBSRequest) */ -static chunk_t -build_request_list(ocsp_location_t *location) +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 != NULL) - { - /* build request for every certificate in list - * and store them in a chained list - */ - request_list_t *req = alloc_thing(request_list_t, "ocsp request"); + chunk_t requestList; + request_list_t *reqs = NULL; + ocsp_certinfo_t *certinfo = location->certinfo; + u_char *pos; - req->request = build_request(location, certinfo); - req->next = reqs; - reqs = req; + size_t datalen = 0; - datalen += req->request.len; - certinfo = certinfo->next; - } + /* build content */ + while (certinfo != NULL) + { + /* 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 = build_asn1_object(&requestList, ASN1_SEQUENCE - , datalen); + pos = asn1_build_object(&requestList, ASN1_SEQUENCE, datalen); - /* copy all in chained list, free list afterwards */ - while (reqs != NULL) - { - request_list_t *req = reqs; + /* copy all in chained list, free list afterwards */ + while (reqs != NULL) + { + request_list_t *req = reqs; - mv_chunk(&pos, req->request); - reqs = reqs->next; - pfree(req); - } + mv_chunk(&pos, req->request); + reqs = reqs->next; + free(req); + } - return requestList; + return requestList; } -/* - * build requestorName (into TBSRequest) +/** + * Build requestorName (into TBSRequest) */ -static chunk_t -build_requestor_name(void) +static chunk_t build_requestor_name(void) { - return asn1_wrap(ASN1_CONTEXT_C_1, "m" - , asn1_simple_object(ASN1_CONTEXT_C_4 - , ocsp_requestor_cert->subject)); + return asn1_wrap(ASN1_CONTEXT_C_1, "m" + , asn1_simple_object(ASN1_CONTEXT_C_4 + , ocsp_requestor_cert->subject)); } -/* +/** * build nonce extension (into requestExtensions) */ -static chunk_t -build_nonce_extension(ocsp_location_t *location) +static chunk_t build_nonce_extension(ocsp_location_t *location) { - /* generate a random nonce */ - location->nonce.ptr = alloc_bytes(NONCE_LENGTH, "ocsp nonce"), - location->nonce.len = NONCE_LENGTH; - get_rnd_bytes(location->nonce.ptr, NONCE_LENGTH); - - return asn1_wrap(ASN1_SEQUENCE, "cm" - , ASN1_nonce_oid - , asn1_simple_object(ASN1_OCTET_STRING, location->nonce)); + 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) +/** + * Build requestExtensions (into TBSRequest) */ -static chunk_t -build_request_ext(ocsp_location_t *location) +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 - ) - ) - ); + 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) +/** + * Build TBSRequest (into OCSPRequest) */ -static chunk_t -build_tbs_request(ocsp_location_t *location, bool has_requestor_cert) +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() - : empty_chunk - , build_request_list(location) - , build_request_ext(location)); + /* 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 +/** + * 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) +chunk_t build_ocsp_request(ocsp_location_t *location) { - bool has_requestor_cert; - chunk_t tbsRequest, signature; - char buf[BUF_LEN]; - - DBG(DBG_CONTROL, - DBG_log("assembling ocsp request"); - dntoa(buf, BUF_LEN, location->issuer); - DBG_log("issuer: '%s'", buf); - if (location->authKeyID.ptr != NULL) - { - datatot(location->authKeyID.ptr, location->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); - } - ) - lock_certs_and_keys("build_ocsp_request"); + bool has_requestor_cert; + chunk_t tbsRequest, signature; + char buf[BUF_LEN]; - /* looks for requestor cert and matching private key */ - has_requestor_cert = get_ocsp_requestor_cert(location); + DBG(DBG_CONTROL, + DBG_log("assembling ocsp request"); + dntoa(buf, BUF_LEN, location->issuer); + DBG_log("issuer: '%s'", buf); + if (location->authKeyID.ptr != NULL) + { + datatot(location->authKeyID.ptr, location->authKeyID.len, ':' + , buf, BUF_LEN); + DBG_log("authkey: %s", buf); + } + ) + 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); + /* build content */ + tbsRequest = build_tbs_request(location, has_requestor_cert); - /* sign tbsReuqest */ - signature = (has_requestor_cert)? build_signature(tbsRequest) - : empty_chunk; + /* sign tbsReuqest */ + signature = (has_requestor_cert)? build_signature(tbsRequest) + : chunk_empty; - unlock_certs_and_keys("build_ocsp_request"); + unlock_certs_and_keys("build_ocsp_request"); - return asn1_wrap(ASN1_SEQUENCE, "mm" - , tbsRequest - , signature); + return asn1_wrap(ASN1_SEQUENCE, "mm" + , tbsRequest + , signature); } -/* - * check if the OCSP response has a valid signature +/** + * Check if the OCSP response has a valid signature */ -static bool -valid_ocsp_response(response_t *res) +static bool valid_ocsp_response(response_t *res) { - int pathlen; - x509cert_t *authcert; + int pathlen; + x509cert_t *authcert; - lock_authcert_list("valid_ocsp_response"); + lock_authcert_list("valid_ocsp_response"); - authcert = get_authcert(res->responder_id_name, empty_chunk - , res->responder_id_key, AUTH_OCSP | AUTH_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 (!check_signature(res->tbs, res->signature, res->algorithm - , res->algorithm, authcert)) - { - 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 = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) - { - u_char buf[BUF_LEN]; - err_t ugh = NULL; - time_t until; - - x509cert_t *cert = authcert; - - DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, cert->subject); - DBG_log("subject: '%s'",buf); - dntoa(buf, BUF_LEN, cert->issuer); - DBG_log("issuer: '%s'",buf); - if (cert->authKeyID.ptr != NULL) - { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); - } - ) - - ugh = check_validity(authcert, &until); - - if (ugh != NULL) - { - plog("%s", ugh); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - - DBG(DBG_CONTROL, - DBG_log("certificate is valid") - ) - - authcert = get_authcert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, AUTH_CA); + authcert = get_authcert(res->responder_id_name, chunk_empty + , res->responder_id_key, AUTH_OCSP | AUTH_CA); if (authcert == NULL) { - plog("issuer cacert not found"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; + plog("no matching ocsp signer cert found"); + unlock_authcert_list("valid_ocsp_response"); + return FALSE; } DBG(DBG_CONTROL, - DBG_log("issuer cacert found") + DBG_log("ocsp signer cert found") ) - if (!check_signature(cert->tbsCertificate, cert->signature - , cert->algorithm, cert->algorithm, authcert)) + if (!x509_check_signature(res->tbs, res->signature, res->algorithm, authcert)) { - plog("certificate signature is invalid"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; + plog("signature of ocsp response is invalid"); + unlock_authcert_list("valid_ocsp_response"); + return FALSE; } DBG(DBG_CONTROL, - DBG_log("certificate signature is valid") + DBG_log("signature of ocsp response is valid") ) - /* check if cert is self-signed */ - if (same_dn(cert->issuer, cert->subject)) + + for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) { - DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca") - ) - unlock_authcert_list("valid_ocsp_response"); - return TRUE; + u_char buf[BUF_LEN]; + err_t ugh = NULL; + time_t until; + + x509cert_t *cert = authcert; + + DBG(DBG_CONTROL, + dntoa(buf, BUF_LEN, cert->subject); + DBG_log("subject: '%s'",buf); + dntoa(buf, BUF_LEN, cert->issuer); + DBG_log("issuer: '%s'",buf); + if (cert->authKeyID.ptr != NULL) + { + datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' + , buf, BUF_LEN); + DBG_log("authkey: %s", buf); + } + ) + + ugh = check_validity(authcert, &until); + + if (ugh != NULL) + { + plog("%s", ugh); + unlock_authcert_list("valid_ocsp_response"); + return FALSE; + } + + DBG(DBG_CONTROL, + DBG_log("certificate is valid") + ) + + authcert = get_authcert(cert->issuer, cert->authKeySerialNumber + , cert->authKeyID, AUTH_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 (!x509_check_signature(cert->tbsCertificate, cert->signature, + cert->algorithm, authcert)) + { + plog("certificate signature is invalid"); + unlock_authcert_list("valid_ocsp_response"); + return FALSE; + } + DBG(DBG_CONTROL, + DBG_log("certificate signature is valid") + ) + + /* check if cert is self-signed */ + if (same_dn(cert->issuer, cert->subject)) + { + DBG(DBG_CONTROL, + DBG_log("reached self-signed root ca") + ) + unlock_authcert_list("valid_ocsp_response"); + return TRUE; + } } - } - plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; + plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN); + unlock_authcert_list("valid_ocsp_response"); + return FALSE; } -/* - * parse a basic OCSP response +/** + * Parse a basic OCSP response */ -static bool -parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) +static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) { - asn1_ctx_t ctx; - bool critical; - chunk_t object; - u_int level, version; - u_char buf[BUF_LEN]; - int objectID = 0; - int extn_oid = OID_UNKNOWN; - - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); - - while (objectID < BASIC_RESPONSE_ROOF) - { - if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx)) - return FALSE; - - switch (objectID) + asn1_parser_t *parser; + chunk_t object; + u_int version; + u_char buf[BUF_LEN]; + 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)) { - 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); - return FALSE; - } - break; - case BASIC_RESPONSE_ID_BY_NAME: - res->responder_id_name = object; - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'",buf) - ) - break; - case BASIC_RESPONSE_ID_BY_KEY: - res->responder_id_key = object; - break; - case BASIC_RESPONSE_PRODUCED_AT: - res->produced_at = asn1totime(&object, ASN1_GENERALIZEDTIME); - break; - case BASIC_RESPONSE_RESPONSES: - res->responses = object; - break; - case BASIC_RESPONSE_EXT_ID: - extn_oid = 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 = parse_algorithmIdentifier(object, level+1, NULL); - break; - case BASIC_RESPONSE_SIGNATURE: - res->signature = object; - break; - case BASIC_RESPONSE_CERTIFICATE: - { - chunk_t blob; - x509cert_t *cert = alloc_thing(x509cert_t, "ocspcert"); - - clonetochunk(blob, object.ptr, object.len, "ocspcert blob"); - *cert = empty_x509cert; - - if (parse_x509cert(blob, level+1, cert) - && cert->isOcspSigner - && trust_authcert_candidate(cert, NULL)) + switch (objectID) { - add_authcert(cert, AUTH_OCSP); - } - else - { - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log("embedded ocsp certificate rejected") - ) - free_x509cert(cert); + 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 = object; + DBG(DBG_PARSING, + dntoa(buf, BUF_LEN, object); + DBG_log(" '%s'",buf) + ) + 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: + { + chunk_t blob = chunk_clone(object); + x509cert_t *cert = malloc_thing(x509cert_t); + + *cert = empty_x509cert; + + if (parse_x509cert(blob, parser->get_level(parser)+1, cert) + && cert->isOcspSigner + && trust_authcert_candidate(cert, NULL)) + { + add_authcert(cert, AUTH_OCSP); + } + else + { + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log("embedded ocsp certificate rejected") + ) + free_x509cert(cert); + } + } + break; } - } - break; } - objectID++; - } - return TRUE; + success = parser->success(parser); + +end: + parser->destroy(parser); + return success; + } -/* - * parse an ocsp response and return the result as a response_t struct +/** + * 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) +static response_status parse_ocsp_response(chunk_t blob, response_t * res) { - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - int ocspResponseType = OID_UNKNOWN; - response_status rStatus = STATUS_INTERNALERROR; - - asn1_init(&ctx, blob, 0, FALSE, DBG_RAW); - - while (objectID < OCSP_RESPONSE_ROOF) - { - if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx)) - return STATUS_INTERNALERROR; - - 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]); - return rStatus; - default: - return STATUS_INTERNALERROR; - } - break; - case OCSP_RESPONSE_TYPE: - ocspResponseType = known_oid(object); - break; - case OCSP_RESPONSE: - { - switch (ocspResponseType) { - case OID_BASIC: - if (!parse_basic_ocsp_response(object, level+1, res)) - return STATUS_INTERNALERROR; - break; - default: - DBG(DBG_CONTROL, - DBG_log("ocsp response is not of type BASIC"); - DBG_dump_chunk("ocsp response OID: ", object); - ) - return STATUS_INTERNALERROR; + 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; } - } - break; } - objectID++; - } - return rStatus; + success &= parser->success(parser); + +end: + parser->destroy(parser); + return rStatus; } -/* - * parse a basic OCSP response +/** + * Parse a basic OCSP response */ -static bool -parse_ocsp_single_response(chunk_t blob, int level0, single_response_t *sres) +static bool parse_ocsp_single_response(chunk_t blob, int level0, + single_response_t *sres) { - u_int level, extn_oid; - asn1_ctx_t ctx; - bool critical; - chunk_t object; - int objectID = 0; - - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); + asn1_parser_t *parser; + chunk_t object; + u_int extn_oid; + int objectID; + bool critical; + bool success = FALSE; - while (objectID < SINGLE_RESPONSE_ROOF) - { - if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx)) - return FALSE; + parser = asn1_parser_create(singleResponseObjects, blob); + parser->set_top_level(parser, level0); - switch (objectID) + while (parser->iterate(parser, &objectID, &object)) { - case SINGLE_RESPONSE_ALGORITHM: - sres->hash_algorithm = parse_algorithmIdentifier(object, level+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 = asn1totime(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON: - sres->revocationReason = (object.len == 1) - ? *object.ptr : REASON_UNSPECIFIED; - break; - case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN: - sres->status = CERT_UNKNOWN; - break; - case SINGLE_RESPONSE_THIS_UPDATE: - sres->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_NEXT_UPDATE: - sres->nextUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_EXT_ID: - extn_oid = 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; + 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 : 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; + } } - objectID++; - } - return TRUE; + success = parser->success(parser); + parser->destroy(parser); + return success; } -/* - * add an ocsp location to a chained list +/** + * 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* add_ocsp_location(const ocsp_location_t *loc, + ocsp_location_t **chain) { - ocsp_location_t *location = alloc_thing(ocsp_location_t, "ocsp location"); - - /* unshare location fields */ - clonetochunk(location->issuer - , loc->issuer.ptr, loc->issuer.len - , "ocsp issuer"); - - clonetochunk(location->authNameID - , loc->authNameID.ptr, loc->authNameID.len - , "ocsp authNameID"); - - if (loc->authKeyID.ptr == NULL) - location->authKeyID = empty_chunk; - else - clonetochunk(location->authKeyID - , loc->authKeyID.ptr, loc->authKeyID.len - , "ocsp authKeyID"); - - if (loc->authKeySerialNumber.ptr == NULL) - location->authKeySerialNumber = empty_chunk; - else - clonetochunk(location->authKeySerialNumber - , loc->authKeySerialNumber.ptr, loc->authKeySerialNumber.len - , "ocsp authKeySerialNumber"); - - clonetochunk(location->uri - , loc->uri.ptr, loc->uri.len - , "ocsp 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; + ocsp_location_t *location = malloc_thing(ocsp_location_t); + + /* unshare location fields */ + location->issuer = chunk_clone(loc->issuer); + location->authNameID = chunk_clone(loc->authNameID); + location->authKeyID = chunk_clone(loc->authKeyID); + location->authKeySerialNumber = chunk_clone(loc->authKeySerialNumber); + location->uri = chunk_clone(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) +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 != NULL) - { - cmp = cmp_chunk(info->serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; + 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; - } - - if (cmp != 0) - { - /* add a new certinfo entry */ - ocsp_certinfo_t *cnew = alloc_thing(ocsp_certinfo_t, "ocsp certinfo"); - clonetochunk(cnew->serialNumber, info->serialNumber.ptr - , info->serialNumber.len, "serialNumber"); - cnew->next = certinfo; - *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; - + + while (certinfo != NULL) + { + cmp = chunk_compare(info->serialNumber, certinfo->serialNumber); + if (cmp <= 0) + break; + certinfop = &certinfo->next; + certinfo = *certinfop; + } + 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; + { + /* add a new certinfo entry */ + ocsp_certinfo_t *cnew = malloc_thing(ocsp_certinfo_t); + + cnew->serialNumber = chunk_clone(info->serialNumber); + cnew->next = certinfo; + *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->once = (info->nextUpdate == UNDEFINED_TIME); - certinfo->nextUpdate = (certinfo->once)? - (now + OCSP_DEFAULT_VALID_TIME) : info->nextUpdate; - } + certinfo->nextUpdate = (certinfo->once)? + (now + OCSP_DEFAULT_VALID_TIME) : info->nextUpdate; + } } -/* - * process received ocsp single response and add it to ocsp cache +/** + * Process received ocsp single response and add it to ocsp cache */ -static void -process_single_response(ocsp_location_t *location, single_response_t *sres) +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 (!(same_chunk(sres->issuer_name_hash, location->authNameID) - && same_chunk(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 != NULL) - { - cmp = cmp_chunk(sres->serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; + 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; - } - - 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); + while (certinfo != NULL) + { + 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); } -/* - * parse and verify ocsp response and update the ocsp cache +/** + * Parse and verify ocsp response and update the ocsp cache */ -void -parse_ocsp(ocsp_location_t *location, chunk_t blob) +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"); - return; - } - /* check if there was a nonce in the request */ - if (location->nonce.ptr != NULL && res.nonce.ptr == NULL) - { - plog("ocsp response contains no nonce, replay attack possible"); - } - /* check if the nonce is identical */ - if (res.nonce.ptr != NULL && !same_chunk(res.nonce, location->nonce)) - { - plog("invalid nonce in ocsp response"); - return; - } - /* check if the response is signed by a trusted key */ - if (!valid_ocsp_response(&res)) - { - plog("invalid ocsp response"); - return; - } - DBG(DBG_CONTROL, - DBG_log("valid ocsp response") - ) - - /* now parse the single responses one at a time */ - { - u_int level; - asn1_ctx_t ctx; - chunk_t object; - int objectID = 0; + response_t res = empty_response; - asn1_init(&ctx, res.responses, 0, FALSE, DBG_RAW); + /* parse the ocsp response without looking at the single responses yet */ + response_status status = parse_ocsp_response(blob, &res); - while (objectID < RESPONSES_ROOF) + if (status != STATUS_SUCCESSFUL) + { + plog("error in ocsp response"); + return; + } + /* check if there was a nonce in the request */ + if (location->nonce.ptr != NULL && res.nonce.ptr == NULL) + { + plog("ocsp response contains no nonce, replay attack possible"); + } + /* check if the nonce is identical */ + if (res.nonce.ptr != NULL && !chunk_equals(res.nonce, location->nonce)) + { + plog("invalid nonce in ocsp response"); + return; + } + /* check if the response is signed by a trusted key */ + if (!valid_ocsp_response(&res)) { - if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx)) + plog("invalid ocsp response"); return; - - if (objectID == RESPONSES_SINGLE_RESPONSE) - { - single_response_t sres = empty_single_response; + } + DBG(DBG_CONTROL, + DBG_log("valid ocsp response") + ) - if (parse_ocsp_single_response(object, level+1, &sres)) + /* 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)) { - process_single_response(location, &sres); + 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); + } } - } - objectID++; +end: + parser->destroy(parser); } - } } diff --git a/src/pluto/ocsp.h b/src/pluto/ocsp.h index 6bf42831b..d8ee7bd8c 100644 --- a/src/pluto/ocsp.h +++ b/src/pluto/ocsp.h @@ -11,27 +11,25 @@ * 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. - * - * RCSID $Id: ocsp.h 3253 2007-10-06 21:39:00Z andreas $ */ #include "constants.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 */ +#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 + STATUS_SUCCESSFUL = 0, + STATUS_MALFORMEDREQUEST = 1, + STATUS_INTERNALERROR = 2, + STATUS_TRYLATER = 3, + STATUS_SIGREQUIRED = 5, + STATUS_UNAUTHORIZED= 6 } response_status; /* OCSP access structures */ @@ -39,46 +37,46 @@ typedef enum { 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; + 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; - chunk_t issuer; - chunk_t authNameID; - chunk_t authKeyID; - chunk_t authKeySerialNumber; - chunk_t uri; - chunk_t nonce; - ocsp_certinfo_t *certinfo; + ocsp_location_t *next; + chunk_t issuer; + chunk_t authNameID; + chunk_t authKeyID; + chunk_t authKeySerialNumber; + chunk_t uri; + chunk_t nonce; + ocsp_certinfo_t *certinfo; }; extern ocsp_location_t* get_ocsp_location(const ocsp_location_t *loc - , ocsp_location_t *chain); + , ocsp_location_t *chain); extern ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc - , ocsp_location_t **chain); + , ocsp_location_t **chain); extern void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info - , ocsp_location_t **chain, bool request); + , ocsp_location_t **chain, bool request); extern void check_ocsp(void); extern cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until - , time_t *revocationTime, crl_reason_t *revocationReason); + , 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 x509cert_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); + , 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); diff --git a/src/pluto/packet.c b/src/pluto/packet.c index e8a3a1e11..01967efed 100644 --- a/src/pluto/packet.c +++ b/src/pluto/packet.c @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: packet.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdio.h> @@ -27,7 +25,7 @@ #include "defs.h" #include "log.h" #include "packet.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ +#include "whack.h" /* for RC_LOG_SERIOUS */ /* ISAKMP Header: for all messages * layout from RFC 2408 "ISAKMP" section 3.1 @@ -49,15 +47,15 @@ */ 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 } + { 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) }; @@ -74,10 +72,10 @@ struct_desc isakmp_hdr_desc = { "ISAKMP Message", isa_fields, sizeof(struct isak */ 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 } + { 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) }; @@ -100,36 +98,36 @@ struct_desc isakmp_generic_desc = { "ISAKMP Generic Payload", isag_fields, sizeo /* 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 } + { 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) }; + "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 } + { 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) }; + "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 } + { 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 ModeCfg attribute", + isaat_fields_modecfg, sizeof(struct isakmp_attribute) }; /* ISAKMP Security Association Payload * layout from RFC 2408 "ISAKMP" section 3.4 @@ -148,18 +146,18 @@ struct_desc isakmp_modecfg_attribute_desc = { * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 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 } + { 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 } + { 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) }; @@ -179,14 +177,14 @@ struct_desc ipsec_sit_desc = { "IPsec DOI SIT", ipsec_sit_field, sizeof(u_int32_ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 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 } + { 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) }; @@ -210,63 +208,63 @@ struct_desc isakmp_proposal_desc = { "ISAKMP Proposal Payload", isap_fields, siz /* 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 } + { 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) }; + "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_transformid_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } + { 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_transformid_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) }; + "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_transformid_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } + { 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_transformid_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) }; + "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 } + { 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 Transform Payload (COMP)", + isat_fields_ipcomp, sizeof(struct isakmp_transform) }; /* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones. @@ -303,13 +301,13 @@ struct_desc isakmp_keyex_desc = { "ISAKMP Key Exchange Payload", isag_fields, si * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 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 } + { 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) }; @@ -330,13 +328,13 @@ struct_desc isakmp_identification_desc = { "ISAKMP Identification Payload", isai * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 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 } + { 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) }; @@ -357,11 +355,11 @@ struct_desc isakmp_ipsec_identification_desc = { "ISAKMP Identification Payload * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 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 } + { 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 @@ -385,11 +383,11 @@ static field_desc isacert_fields[] = { * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 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 } + { 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 @@ -469,14 +467,14 @@ struct_desc isakmp_nonce_desc = { "ISAKMP Nonce Payload", isag_fields, sizeof(st * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 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 } + { 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) }; @@ -500,14 +498,14 @@ struct_desc isakmp_notification_desc = { "ISAKMP Notification Payload", isan_fie * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 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 } + { 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) }; @@ -532,26 +530,26 @@ struct_desc isakmp_vendor_id_desc = { "ISAKMP Vendor ID Payload", isag_fields, s /* * 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 ~ - ! ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 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 } + { 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) }; @@ -581,12 +579,12 @@ struct_desc isakmp_nat_d = { "ISAKMP NAT-D Payload", isag_fields, sizeof(struct * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ 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 } + { 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) }; @@ -600,40 +598,40 @@ struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof( * 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) */ + 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; + 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 @@ -648,85 +646,85 @@ 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); + bool immediate = FALSE; + const u_int8_t *inp = struct_ptr; + field_desc *fp; - for (fp = sd->fields; fp->field_type != ft_end; fp++) - { - int i = fp->size; - u_int32_t n = 0; + DBG_log("%s%s:", label, sd->name); - switch (fp->field_type) + for (fp = sd->fields; fp->field_type != ft_end; fp++) { - 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); + 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 @@ -734,35 +732,35 @@ 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 (;;) + /* 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 { - if (pre <= space) - break; - *--pre = '*'; - if (p == NULL) - break; - p = p->container; + 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); } - DBG_print_struct(pre, struct_ptr, sd, len_meaningful); - } } #endif @@ -785,191 +783,191 @@ 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; + err_t ugh = NULL; + u_int8_t *cur = ins->cur; - for (fp = sd->fields; ugh == NULL; fp++) + if (ins->roof - cur < (ptrdiff_t)sd->size) { - 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++; + 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; - 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) + for (fp = sd->fields; ugh == NULL; fp++) { - 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; - } + size_t i = fp->size; - case ft_raw: /* bytes to be left in network-order */ - for (; i != 0; i--) - { - *outp++ = *cur++; - } - break; + passert(ins->roof - cur >= (ptrdiff_t)i); + passert(cur - ins->cur <= (ptrdiff_t)(sd->size - i)); + passert(outp - (cur - ins->cur) == struct_ptr); - 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; +#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); + } } - 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; + /* 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) + if (pbs_left(ins) < len) { - DBG(DBG_PARSING - , DBG_log("skipping %u raw bytes of %s (%s)" - , (unsigned) len, ins->name, name); - DBG_dump(name, ins->cur, len)); + loglog(RC_LOG_SERIOUS, "not enough bytes left to get %s from %s", name, ins->name); + return FALSE; } 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)); + 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; } - ins->cur += len; - return TRUE; - } } /* "emit" a host struct into a network packet. @@ -994,227 +992,227 @@ 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; + err_t ugh = NULL; + const u_int8_t *inp = struct_ptr; + u_int8_t *cur = outs->cur; - obj.lenfld = NULL; /* until a length field is discovered */ - obj.lenfld_desc = NULL; + DBG(DBG_EMITTING + , DBG_prefix_print_struct(outs, "emit ", struct_ptr, sd, obj_pbs==NULL)); - for (fp = sd->fields; ugh == NULL; fp++) + if (outs->roof - cur < (ptrdiff_t)sd->size) { - 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; + ugh = builddiag("not enough room left in output packet to place %s" + , sd->name); + } + else + { + bool immediate = FALSE; + pb_stream obj; + field_desc *fp; - 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); - } + obj.lenfld = NULL; /* until a length field is discovered */ + obj.lenfld_desc = NULL; - switch (fp->field_type) + for (fp = sd->fields; ugh == NULL; fp++) { - 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; - } + size_t i = fp->size; - 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; + passert(outs->roof - cur >= (ptrdiff_t)i); + passert(cur - outs->cur <= (ptrdiff_t)(sd->size - i)); + passert(inp - (cur - outs->cur) == struct_ptr); - *obj_pbs = obj; +#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); + } } - 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; + /* 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; + struct isakmp_generic gen; - passert(sd->fields == isakmp_generic_desc.fields); - gen.isag_np = np; - return out_struct(&gen, sd, outs, obj_pbs); + 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; + pb_stream pbs; - if (!out_generic(np, sd, outs, &pbs) - || !out_raw(bytes, len, &pbs, name)) - return FALSE; - close_output_pbs(&pbs); - return TRUE; + 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; - } + 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; - } + 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. @@ -1224,21 +1222,21 @@ out_zero(size_t len, pb_stream *outs, const char *name) 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) + if (pbs->lenfld != NULL) { - pbs->lenfld[i] = (u_int8_t)len; - len >>= BITS_PER_BYTE; + 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 */ + 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 index 1eadf0e02..1510b81a0 100644 --- a/src/pluto/packet.h +++ b/src/pluto/packet.h @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: packet.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _PACKET_H @@ -23,9 +21,9 @@ */ typedef const struct struct_desc { - const char *name; - const struct field_desc *fields; - size_t size; + 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, @@ -35,24 +33,24 @@ typedef const struct struct_desc { */ 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 */ + 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 */ + 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 @@ -62,18 +60,18 @@ typedef const struct field_desc { * 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; + 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. @@ -88,17 +86,17 @@ typedef struct packet_byte_stream { 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); + 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); + 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); + 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); + 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) + 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)) @@ -106,7 +104,7 @@ 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); + struct_desc *sd, bool len_meaningful); #endif /* ISAKMP Header: for all messages @@ -160,16 +158,16 @@ extern void DBG_print_struct(const char *label, const void *struct_ptr, 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 */ + 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; @@ -186,9 +184,9 @@ extern struct_desc isakmp_hdr_desc; */ struct isakmp_generic { - u_int8_t isag_np; - u_int8_t isag_reserved; - u_int16_t isag_length; + u_int8_t isag_np; + u_int8_t isag_reserved; + u_int16_t isag_length; }; extern struct_desc isakmp_generic_desc; @@ -209,17 +207,17 @@ extern struct_desc isakmp_generic_desc; */ 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 */ + /* 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 @@ -229,8 +227,8 @@ struct isakmp_attribute #define ISAKMP_ATTR_RTYPE_MASK 0x7FFF extern struct_desc - isakmp_oakley_attribute_desc, - isakmp_ipsec_attribute_desc; + isakmp_oakley_attribute_desc, + isakmp_ipsec_attribute_desc; /* ISAKMP Security Association Payload * layout from RFC 2408 "ISAKMP" section 3.4 @@ -250,10 +248,10 @@ extern struct_desc */ 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 */ + 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; @@ -276,13 +274,13 @@ extern struct_desc ipsec_sit_desc; */ 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 */ + 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; @@ -305,19 +303,19 @@ extern struct_desc isakmp_proposal_desc; */ 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; + 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_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 @@ -354,12 +352,12 @@ extern struct_desc isakmp_keyex_desc; */ 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; + 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; @@ -381,12 +379,12 @@ extern struct_desc isakmp_identification_desc; */ 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; + 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; @@ -408,17 +406,17 @@ extern struct_desc isakmp_ipsec_identification_desc; */ struct isakmp_cert { - u_int8_t isacert_np; - u_int8_t isacert_reserved; - u_int16_t isacert_length; - u_int8_t isacert_type; + 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 +#define ISAKMP_CERT_SIZE 5 extern struct_desc isakmp_ipsec_certificate_desc; @@ -439,17 +437,17 @@ extern struct_desc isakmp_ipsec_certificate_desc; */ struct isakmp_cr { - u_int8_t isacr_np; - u_int8_t isacr_reserved; - u_int16_t isacr_length; - u_int8_t isacr_type; + 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 +#define ISAKMP_CR_SIZE 5 extern struct_desc isakmp_ipsec_cert_req_desc; @@ -526,13 +524,13 @@ extern struct_desc isakmp_nonce_desc; */ 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; + 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; @@ -557,40 +555,40 @@ extern struct_desc isakmp_notification_desc; */ 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; + 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 ~ - ! ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 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; + 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; @@ -614,12 +612,12 @@ 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; + 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; @@ -628,18 +626,18 @@ 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; + 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 diff --git a/src/pluto/pem.c b/src/pluto/pem.c index 5ebe4b576..646447c1a 100644 --- a/src/pluto/pem.c +++ b/src/pluto/pem.c @@ -1,5 +1,6 @@ /* Loading of PEM encoded files with optional encryption - * Copyright (C) 2001-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * Copyright (C) 2001-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 @@ -10,8 +11,6 @@ * 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. - * - * RCSID $Id: pem.c 3252 2007-10-06 21:24:50Z andreas $ */ /* decrypt a PEM encoded data block using DES-EDE3-CBC @@ -27,437 +26,101 @@ #include <sys/types.h> #include <freeswan.h> -#define HEADER_DES_LOCL_H /* stupid trick to force prototype decl in <des.h> */ -#include <libdes/des.h> + +#include <library.h> +#include <asn1/pem.h> #include "constants.h" #include "defs.h" #include "log.h" -#include "md5.h" #include "whack.h" #include "pem.h" -/* - * check the presence of a pattern in a character string - */ -static bool -present(const char* pattern, chunk_t* ch) -{ - u_int pattern_len = strlen(pattern); - - if (ch->len >= pattern_len && strncmp(ch->ptr, pattern, pattern_len) == 0) - { - ch->ptr += pattern_len; - ch->len -= pattern_len; - return TRUE; - } - return FALSE; -} - -/* - * compare string with chunk - */ -static bool -match(const char *pattern, const chunk_t *ch) -{ - return ch->len == strlen(pattern) && - strncmp(pattern, ch->ptr, ch->len) == 0; -} - -/* - * find a boundary of the form -----tag name----- - */ -static bool -find_boundary(const char* tag, chunk_t *line) -{ - chunk_t name = empty_chunk; - - if (!present("-----", line)) - return FALSE; - if (!present(tag, line)) - return FALSE; - if (*line->ptr != ' ') - return FALSE; - line->ptr++; line->len--; - - /* extract name */ - name.ptr = line->ptr; - while (line->len > 0) - { - if (present("-----", line)) - { - DBG(DBG_PARSING, - DBG_log(" -----%s %.*s-----", - tag, (int)name.len, name.ptr); - ) - return TRUE; - } - line->ptr++; line->len--; name.len++; - } - return FALSE; -} - -/* - * eat whitespace - */ -static void -eat_whitespace(chunk_t *src) -{ - while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t')) - { - src->ptr++; src->len--; - } -} - -/* - * extracts a token ending with a given termination symbol - */ -static bool -extract_token(chunk_t *token, char termination, chunk_t *src) -{ - u_char *eot = memchr(src->ptr, termination, src->len); - - /* initialize empty token */ - *token = empty_chunk; - - if (eot == NULL) /* termination symbol not found */ - return FALSE; - - /* extract token */ - token->ptr = src->ptr; - token->len = (u_int)(eot - src->ptr); - - /* advance src pointer after termination symbol */ - src->ptr = eot + 1; - src->len -= (token->len + 1); - - return TRUE; -} - -/* - * extracts a name: value pair from the PEM header - */ -static bool -extract_parameter(chunk_t *name, chunk_t *value, chunk_t *line) -{ - DBG(DBG_PARSING, - DBG_log(" %.*s", (int)line->len, line->ptr); - ) - - /* extract name */ - if (!extract_token(name,':', line)) - return FALSE; - - eat_whitespace(line); - - /* extract value */ - *value = *line; - return TRUE; -} - -/* - * fetches a new line terminated by \n or \r\n - */ -static bool -fetchline(chunk_t *src, chunk_t *line) -{ - if (src->len == 0) /* end of src reached */ - return FALSE; - - if (extract_token(line, '\n', src)) - { - if (line->len > 0 && *(line->ptr + line->len -1) == '\r') - line->len--; /* remove optional \r */ - } - else /*last line ends without newline */ - { - *line = *src; - src->ptr += src->len; - src->len = 0; - } - return TRUE; -} - -/* - * decrypts a DES-EDE-CBC encrypted data block - */ -static bool -pem_decrypt_3des(chunk_t *blob, chunk_t *iv, const char *passphrase) -{ - MD5_CTX context; - u_char digest[MD5_DIGEST_SIZE]; - u_char des_iv[DES_CBC_BLOCK_SIZE]; - u_char key[24]; - des_cblock *deskey = (des_cblock *)key; - des_key_schedule ks[3]; - u_char padding, *last_padding_pos, *first_padding_pos; - - /* Convert passphrase to 3des key */ - MD5Init(&context); - MD5Update(&context, passphrase, strlen(passphrase)); - MD5Update(&context, iv->ptr, iv->len); - MD5Final(digest, &context); - - memcpy(key, digest, MD5_DIGEST_SIZE); - - MD5Init(&context); - MD5Update(&context, digest, MD5_DIGEST_SIZE); - MD5Update(&context, passphrase, strlen(passphrase)); - MD5Update(&context, iv->ptr, iv->len); - MD5Final(digest, &context); - - memcpy(key + MD5_DIGEST_SIZE, digest, 24 - MD5_DIGEST_SIZE); - - (void) des_set_key(&deskey[0], ks[0]); - (void) des_set_key(&deskey[1], ks[1]); - (void) des_set_key(&deskey[2], ks[2]); - - /* decrypt data block */ - memcpy(des_iv, iv->ptr, DES_CBC_BLOCK_SIZE); - des_ede3_cbc_encrypt((des_cblock *)blob->ptr, (des_cblock *)blob->ptr, - blob->len, ks[0], ks[1], ks[2], (des_cblock *)des_iv, FALSE); - - /* determine amount of padding */ - last_padding_pos = blob->ptr + blob->len - 1; - padding = *last_padding_pos; - first_padding_pos = (padding > blob->len)? - blob->ptr : last_padding_pos - padding; - - /* check the padding pattern */ - while (--last_padding_pos > first_padding_pos) - { - if (*last_padding_pos != padding) - return FALSE; - } - - /* remove padding */ - blob->len -= padding; - return TRUE; -} - -/* - * optionally prompts for a passphrase before decryption - * currently we support DES-EDE3-CBC, only +/** + * Converts a PEM encoded file into its binary form + * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993 + * RFC 934 Message Encapsulation, January 1985 */ -static err_t -pem_decrypt(chunk_t *blob, chunk_t *iv, prompt_pass_t *pass, const char* label) +err_t pemtobin(chunk_t *blob, prompt_pass_t *pass, const char* label, bool *pgp) { - DBG(DBG_CRYPT, - DBG_log(" decrypting file using 'DES-EDE3-CBC'"); - ) - if (iv->len != DES_CBC_BLOCK_SIZE) - return "size of DES-EDE3-CBC IV is not 8 bytes"; - - if (pass == NULL) - return "no passphrase available"; + chunk_t password = chunk_empty; - /* do we prompt for the passphrase? */ - if (pass->prompt && pass->fd != NULL_FD) - { - int i; - chunk_t blob_copy; - err_t ugh = "invalid passphrase, too many trials"; - - whack_log(RC_ENTERSECRET, "need passphrase for '%s'", label); - - for (i = 0; i < MAX_PROMPT_PASS_TRIALS; i++) + /* do we prompt for the passphrase? */ + if (pass && pass->prompt && pass->fd != NULL_FD) { - int n; - - if (i > 0) - whack_log(RC_ENTERSECRET, "invalid passphrase, please try again"); - - n = read(pass->fd, pass->secret, PROMPT_PASS_LEN); - - if (n == -1) - { - err_t ugh = "read(whackfd) failed"; - - whack_log(RC_LOG_SERIOUS,ugh); - return ugh; - } + int i; + chunk_t blob_copy; + err_t ugh = "invalid passphrase, too many trials"; + status_t status; - pass->secret[n-1] = '\0'; - - if (strlen(pass->secret) == 0) - { - err_t ugh = "no passphrase entered, aborted"; + whack_log(RC_ENTERSECRET, "need passphrase for '%s'", label); + for (i = 0; i < MAX_PROMPT_PASS_TRIALS; i++) + { + int n; + + if (i > 0) + { + whack_log(RC_ENTERSECRET, "invalid passphrase, please try again"); + } + n = read(pass->fd, pass->secret, PROMPT_PASS_LEN); + + if (n == -1) + { + err_t ugh = "read(whackfd) failed"; + + whack_log(RC_LOG_SERIOUS,ugh); + return ugh; + } + + pass->secret[n-1] = '\0'; + + if (strlen(pass->secret) == 0) + { + err_t ugh = "no passphrase entered, aborted"; + + whack_log(RC_LOG_SERIOUS, ugh); + return ugh; + } + + blob_copy = chunk_clone(*blob); + password = chunk_create(pass->secret, strlen(pass->secret)); + + status = pem_to_bin(blob, password, pgp); + if (status != INVALID_ARG) + { + if (status == SUCCESS) + { + whack_log(RC_SUCCESS, "valid passphrase"); + } + else + { + whack_log(RC_LOG_SERIOUS, "%N, aborted", status_names, status); + } + free(blob_copy.ptr); + return NULL; + } + + /* blob is useless after wrong decryption, restore the original */ + free(blob->ptr); + *blob = blob_copy; + } whack_log(RC_LOG_SERIOUS, ugh); return ugh; - } - - clonetochunk(blob_copy, blob->ptr, blob->len, "blob copy"); - - if (pem_decrypt_3des(blob, iv, pass->secret)) - { - whack_log(RC_SUCCESS, "valid passphrase"); - pfree(blob_copy.ptr); - return NULL; - } - - /* blob is useless after wrong decryption, restore the original */ - pfree(blob->ptr); - *blob = blob_copy; - } - whack_log(RC_LOG_SERIOUS, ugh); - return ugh; - } - else - { - if (pem_decrypt_3des(blob, iv, pass->secret)) - return NULL; - else - return "invalid passphrase"; - } -} - -/* Converts a PEM encoded file into its binary form - * - * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993 - * RFC 934 Message Encapsulation, January 1985 - */ -err_t -pemtobin(chunk_t *blob, prompt_pass_t *pass, const char* label, bool *pgp) -{ - typedef enum { - PEM_PRE = 0, - PEM_MSG = 1, - PEM_HEADER = 2, - PEM_BODY = 3, - PEM_POST = 4, - PEM_ABORT = 5 - } state_t; - - bool encrypted = FALSE; - - state_t state = PEM_PRE; - - chunk_t src = *blob; - chunk_t dst = *blob; - chunk_t line = empty_chunk; - chunk_t iv = empty_chunk; - - u_char iv_buf[MAX_DIGEST_LEN]; - - /* zero size of converted blob */ - dst.len = 0; - - /* zero size of IV */ - iv.ptr = iv_buf; - iv.len = 0; - - while (fetchline(&src, &line)) - { - if (state == PEM_PRE) - { - if (find_boundary("BEGIN", &line)) - { - *pgp = FALSE; - state = PEM_MSG; - } - continue; } else { - if (find_boundary("END", &line)) - { - state = PEM_POST; - break; - } - if (state == PEM_MSG) - { - state = (memchr(line.ptr, ':', line.len) == NULL)? - PEM_BODY : PEM_HEADER; - } - if (state == PEM_HEADER) - { - chunk_t name = empty_chunk; - chunk_t value = empty_chunk; - - /* an empty line separates HEADER and BODY */ - if (line.len == 0) - { - state = PEM_BODY; - continue; - } - - /* we are looking for a name: value pair */ - if (!extract_parameter(&name, &value, &line)) - continue; - - if (match("Proc-Type", &name) && *value.ptr == '4') - encrypted = TRUE; - else if (match("DEK-Info", &name)) + if (pass) { - const char *ugh = NULL; - size_t len = 0; - chunk_t dek; - - if (!extract_token(&dek, ',', &value)) - dek = value; - - /* we support DES-EDE3-CBC encrypted files, only */ - if (!match("DES-EDE3-CBC", &dek)) - return "we support DES-EDE3-CBC encrypted files, only"; - - eat_whitespace(&value); - ugh = ttodata(value.ptr, value.len, 16, - iv.ptr, MAX_DIGEST_LEN, &len); - if (ugh) - return "error in IV"; - - iv.len = len; + password = chunk_create(pass->secret, strlen(pass->secret)); } - } - else /* state is PEM_BODY */ - { - const char *ugh = NULL; - size_t len = 0; - chunk_t data; - - /* remove any trailing whitespace */ - if (!extract_token(&data ,' ', &line)) - data = line; - - /* check for PGP armor checksum */ - if (*data.ptr == '=') + if (pem_to_bin(blob, password, pgp) == SUCCESS) { - *pgp = TRUE; - data.ptr++; - data.len--; - DBG(DBG_PARSING, - DBG_log(" Armor checksum: %.*s", (int)data.len, data.ptr); - ) - continue; - } - - ugh = ttodata(data.ptr, data.len, 64, - dst.ptr, blob->len - dst.len, &len); - if (ugh) - { - DBG(DBG_PARSING, - DBG_log(" %s", ugh); - ) - state = PEM_ABORT; - break; + return NULL; } else { - dst.ptr += len; - dst.len += len; + return "pem to bin conversion failed"; } - } - } - } - /* set length to size of binary blob */ - blob->len = dst.len; - - if (state != PEM_POST) - return "file coded in unknown format, discarded"; - - if (encrypted) - return pem_decrypt(blob, &iv, pass, label); - else - return NULL; + } } diff --git a/src/pluto/pem.h b/src/pluto/pem.h index e74915cb2..5e97b99ed 100644 --- a/src/pluto/pem.h +++ b/src/pluto/pem.h @@ -1,5 +1,7 @@ /* Loading of PEM encoded files with optional encryption - * Copyright (C) 2001-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * Copyright (C) 2001-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 @@ -10,9 +12,7 @@ * 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. - * - * RCSID $Id: pem.h 3252 2007-10-06 21:24:50Z andreas $ */ -extern err_t pemtobin(chunk_t *blob, prompt_pass_t *pass, const char* label - , bool *pgp); +extern err_t pemtobin(chunk_t *blob, prompt_pass_t *pass, const char* label, + bool *pgp); diff --git a/src/pluto/pgp.c b/src/pluto/pgp.c deleted file mode 100644 index b956ce4d7..000000000 --- a/src/pluto/pgp.c +++ /dev/null @@ -1,647 +0,0 @@ -/* Support of OpenPGP certificates - * 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. - * - * RCSID $Id: pgp.c 3252 2007-10-06 21:24:50Z andreas $ - */ - -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include <freeswan.h> -#include <ipsec_policy.h> - -#include "constants.h" -#include "defs.h" -#include "mp_defs.h" -#include "log.h" -#include "id.h" -#include "pgp.h" -#include "certs.h" -#include "md5.h" -#include "whack.h" -#include "pkcs1.h" -#include "keys.h" - -/* - * chained list of OpenPGP end certificates - */ -static pgpcert_t *pgpcerts = NULL; - -/* - * OpenPGP packet tags defined in section 4.3 of RFC 2440 - */ -#define PGP_PKT_RESERVED 0 -#define PGP_PKT_PUBKEY_ENC_SESSION_KEY 1 -#define PGP_PKT_SIGNATURE 2 -#define PGP_PKT_SYMKEY_ENC_SESSION_KEY 3 -#define PGP_PKT_ONE_PASS_SIGNATURE_PKT 4 -#define PGP_PKT_SECRET_KEY 5 -#define PGP_PKT_PUBLIC_KEY 6 -#define PGP_PKT_SECRET_SUBKEY 7 -#define PGP_PKT_COMPRESSED_DATA 8 -#define PGP_PKT_SYMKEY_ENC_DATA 9 -#define PGP_PKT_MARKER 10 -#define PGP_PKT_LITERAL_DATA 11 -#define PGP_PKT_TRUST 12 -#define PGP_PKT_USER_ID 13 -#define PGP_PKT_PUBLIC_SUBKEY 14 -#define PGP_PKT_ROOF 15 - -static const char *const pgp_packet_type_name[] = { - "Reserved", - "Public-Key Encrypted Session Key Packet", - "Signature Packet", - "Symmetric-Key Encrypted Session Key Packet", - "One-Pass Signature Packet", - "Secret Key Packet", - "Public Key Packet", - "Secret Subkey Packet", - "Compressed Data Packet", - "Symmetrically Encrypted Data Packet", - "Marker Packet", - "Literal Data Packet", - "Trust Packet", - "User ID Packet", - "Public Subkey Packet" -}; - -/* - * OpenPGP public key algorithms defined in section 9.1 of RFC 2440 - */ -#define PGP_PUBKEY_ALG_RSA 1 -#define PGP_PUBKEY_ALG_RSA_ENC_ONLY 2 -#define PGP_PUBKEY_ALG_RSA_SIGN_ONLY 3 -#define PGP_PUBKEY_ALG_ELGAMAL_ENC_ONLY 16 -#define PGP_PUBKEY_ALG_DSA 17 -#define PGP_PUBKEY_ALG_ECC 18 -#define PGP_PUBKEY_ALG_ECDSA 19 -#define PGP_PUBKEY_ALG_ELGAMAL 20 - -/* - * OpenPGP symmetric key algorithms defined in section 9.2 of RFC 2440 - */ -#define PGP_SYM_ALG_PLAIN 0 -#define PGP_SYM_ALG_IDEA 1 -#define PGP_SYM_ALG_3DES 2 -#define PGP_SYM_ALG_CAST5 3 -#define PGP_SYM_ALG_BLOWFISH 4 -#define PGP_SYM_ALG_SAFER 5 -#define PGP_SYM_ALG_DES 6 -#define PGP_SYM_ALG_AES 7 -#define PGP_SYM_ALG_AES_192 8 -#define PGP_SYM_ALG_AES_256 9 -#define PGP_SYM_ALG_TWOFISH 10 -#define PGP_SYM_ALG_ROOF 11 - -static const char *const pgp_sym_alg_name[] = { - "Plaintext", - "IDEA", - "3DES", - "CAST5", - "Blowfish", - "SAFER", - "DES", - "AES", - "AES-192", - "AES-256", - "Twofish" -}; - -/* - * Size of PGP Key ID - */ -#define PGP_KEYID_SIZE 8 - -const pgpcert_t empty_pgpcert = { - NULL , /* *next */ - 0 , /* installed */ - 0 , /* count */ - { NULL, 0 }, /* certificate */ - 0 , /* created */ - 0 , /* until */ - 0 , /* pubkeyAlgorithm */ - { NULL, 0 }, /* modulus */ - { NULL, 0 }, /* publicExponent */ - "" /* fingerprint */ -}; - -static size_t -pgp_size(chunk_t *blob, int len) -{ - size_t size = 0; - - blob->len -= len; - while (len-- > 0) - size = 256*size + *blob->ptr++; - return size; -} - -/* - * extracts the length of a PGP packet - */ -static size_t -pgp_old_packet_length(chunk_t *blob) -{ - /* bits 0 and 1 define the packet length type */ - int len_type = 0x03 & *blob->ptr++; - - blob->len--; - - /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */ - return pgp_size(blob, (len_type == 0)? 1: len_type << 1); -} - -/* - * extracts PGP packet version (V3 or V4) - */ -static u_char -pgp_version(chunk_t *blob) -{ - u_char version = *blob->ptr++; - blob->len--; - DBG(DBG_PARSING, - DBG_log("L3 - version:"); - DBG_log(" V%d", version) - ) - return version; -} - -/* - * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440 - */ -static bool -parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert) -{ - u_char version = pgp_version(packet); - - if (version < 3 || version > 4) - { - plog("PGP packet version V%d not supported", version); - return FALSE; - } - - /* creation date - 4 bytes */ - cert->created = (time_t)pgp_size(packet, 4); - DBG(DBG_PARSING, - DBG_log("L3 - created:"); - DBG_log(" %s", timetoa(&cert->created, TRUE)) - ) - - if (version == 3) - { - /* validity in days - 2 bytes */ - cert->until = (time_t)pgp_size(packet, 2); - - /* validity of 0 days means that the key never expires */ - if (cert->until > 0) - cert->until = cert->created + 24*3600*cert->until; - - DBG(DBG_PARSING, - DBG_log("L3 - until:"); - DBG_log(" %s", timetoa(&cert->until, TRUE)); - ) - } - - /* public key algorithm - 1 byte */ - DBG(DBG_PARSING, - DBG_log("L3 - public key algorithm:") - ) - - switch (pgp_size(packet, 1)) - { - case PGP_PUBKEY_ALG_RSA: - case PGP_PUBKEY_ALG_RSA_SIGN_ONLY: - cert->pubkeyAlg = PUBKEY_ALG_RSA; - DBG(DBG_PARSING, - DBG_log(" RSA") - ) - /* modulus n */ - cert->modulus.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE; - cert->modulus.ptr = packet->ptr; - packet->ptr += cert->modulus.len; - packet->len -= cert->modulus.len; - DBG(DBG_PARSING, - DBG_log("L3 - modulus:") - ) - DBG_cond_dump_chunk(DBG_RAW, "", cert->modulus); - - /* public exponent e */ - cert->publicExponent.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE; - cert->publicExponent.ptr = packet->ptr; - packet->ptr += cert->publicExponent.len; - packet->len -= cert->publicExponent.len; - DBG(DBG_PARSING, - DBG_log("L3 - public exponent:") - ) - DBG_cond_dump_chunk(DBG_RAW, "", cert->publicExponent); - - if (version == 3) - { - /* a V3 fingerprint is the MD5 hash of modulus and public exponent */ - MD5_CTX context; - MD5Init(&context); - MD5Update(&context, cert->modulus.ptr, cert->modulus.len); - MD5Update(&context, cert->publicExponent.ptr, cert->publicExponent.len); - MD5Final(cert->fingerprint, &context); - } - else - { - plog(" computation of V4 key ID not implemented yet"); - } - break; - case PGP_PUBKEY_ALG_DSA: - cert->pubkeyAlg = PUBKEY_ALG_DSA; - DBG(DBG_PARSING, - DBG_log(" DSA") - ) - plog(" DSA public keys not supported"); - return FALSE; - default: - cert->pubkeyAlg = 0; - DBG(DBG_PARSING, - DBG_log(" other") - ) - plog(" exotic not RSA public keys not supported"); - return FALSE; - } - return TRUE; -} - -/* - * Parse OpenPGP secret key packet defined in section 5.5.3 of RFC 2440 - */ -static bool -parse_pgp_secretkey_packet(chunk_t *packet, RSA_private_key_t *key) -{ - int i, s2k; - pgpcert_t cert = empty_pgpcert; - - if (!parse_pgp_pubkey_packet(packet, &cert)) - return FALSE; - - init_RSA_public_key((RSA_public_key_t *)key, cert.publicExponent - , cert.modulus); - - /* string-to-key usage */ - s2k = pgp_size(packet, 1); - - DBG(DBG_PARSING, - DBG_log("L3 - string-to-key: %d", s2k) - ) - - if (s2k == 255) - { - plog(" string-to-key specifiers not supported"); - return FALSE; - } - - if (s2k >= PGP_SYM_ALG_ROOF) - { - plog(" undefined symmetric key algorithm"); - return FALSE; - } - - /* a known symmetric key algorithm is specified*/ - DBG(DBG_PARSING, - DBG_log(" %s", pgp_sym_alg_name[s2k]) - ) - - /* private key is unencrypted */ - if (s2k == PGP_SYM_ALG_PLAIN) - { - for (i = 2; i < RSA_PRIVATE_FIELD_ELEMENTS; i++) - { - mpz_t u; /* auxiliary variable */ - - /* compute offset to private key component i*/ - MP_INT *n = (MP_INT*)((char *)key + RSA_private_field[i].offset); - - switch (i) - { - case 2: - case 3: - case 4: - { - size_t len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE; - - n_to_mpz(n, packet->ptr, len); - DBG(DBG_PARSING, - DBG_log("L3 - %s:", RSA_private_field[i].name) - ) - DBG_cond_dump(DBG_PRIVATE, "", packet->ptr, len); - packet->ptr += len; - packet->len -= len; - } - break; - case 5: /* dP = d mod (p-1) */ - mpz_init(u); - mpz_sub_ui(u, &key->p, 1); - mpz_mod(n, &key->d, u); - mpz_clear(u); - break; - case 6: /* dQ = d mod (q-1) */ - mpz_init(u); - mpz_sub_ui(u, &key->q, 1); - mpz_mod(n, &key->d, u); - mpz_clear(u); - break; - case 7: /* qInv = (q^-1) mod p */ - mpz_invert(n, &key->q, &key->p); - if (mpz_cmp_ui(n, 0) < 0) - mpz_add(n, n, &key->p); - passert(mpz_cmp(n, &key->p) < 0); - break; - } - } - return TRUE; - } - - plog(" %s encryption not supported", pgp_sym_alg_name[s2k]); - return FALSE; -} - -/* - * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440 - */ -static bool -parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert) -{ - time_t created; - chunk_t keyid; - u_char sig_type; - u_char version = pgp_version(packet); - - /* we parse only V3 signature packets */ - if (version != 3) - return TRUE; - - /* size byte must have the value 5 */ - if (pgp_size(packet, 1) != 5) - { - plog(" size must be 5"); - return FALSE; - } - - /* signature type - 1 byte */ - sig_type = (u_char)pgp_size(packet, 1); - DBG(DBG_PARSING, - DBG_log("L3 - signature type: 0x%2x", sig_type) - ) - - /* creation date - 4 bytes */ - created = (time_t)pgp_size(packet, 4); - DBG(DBG_PARSING, - DBG_log("L3 - created:"); - DBG_log(" %s", timetoa(&cert->created, TRUE)) - ) - - /* key ID of signer - 8 bytes */ - keyid.ptr = packet->ptr; - keyid.len = PGP_KEYID_SIZE; - DBG_cond_dump_chunk(DBG_PARSING, "L3 - key ID of signer", keyid); - - return TRUE; -} - -bool -parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key) -{ - DBG(DBG_PARSING, - DBG_log("L0 - PGP file:") - ) - DBG_cond_dump_chunk(DBG_RAW, "", blob); - - if (cert != NULL) - { - /* parse a PGP certificate file */ - cert->certificate = blob; - time(&cert->installed); - } - else if (key == NULL) - { - /* should not occur, nothing to parse */ - return FALSE; - } - - while (blob.len > 0) - { - chunk_t packet = empty_chunk; - u_char packet_tag = *blob.ptr; - - DBG(DBG_PARSING, - DBG_log("L1 - PGP packet: tag= 0x%2x", packet_tag) - ) - - /* bit 7 must be set */ - if (!(packet_tag & 0x80)) - { - plog(" incorrect Packet Tag"); - return FALSE; - } - - /* bit 6 set defines new packet format */ - if (packet_tag & 0x40) - { - plog(" new PGP packet format not supported"); - return FALSE; - } - else - { - int packet_type = (packet_tag & 0x3C) >> 2; - - packet.len = pgp_old_packet_length(&blob); - packet.ptr = blob.ptr; - blob.ptr += packet.len; - blob.len -= packet.len; - DBG(DBG_PARSING, - DBG_log(" %s (%d), old format, %d bytes", - (packet_type < PGP_PKT_ROOF) ? - pgp_packet_type_name[packet_type] : - "Undefined Packet Type", packet_type, (int)packet.len); - DBG_log("L2 - body:") - ) - DBG_cond_dump_chunk(DBG_RAW, "", packet); - - if (cert != NULL) - { - /* parse a PGP certificate */ - switch (packet_type) - { - case PGP_PKT_PUBLIC_KEY: - if (!parse_pgp_pubkey_packet(&packet, cert)) - return FALSE; - break; - case PGP_PKT_SIGNATURE: - if (!parse_pgp_signature_packet(&packet, cert)) - return FALSE; - break; - case PGP_PKT_USER_ID: - DBG(DBG_PARSING, - DBG_log("L3 - user ID:"); - DBG_log(" '%.*s'", (int)packet.len, packet.ptr) - ) - break; - default: - break; - } - } - else - { - /* parse a PGP private key file */ - switch (packet_type) - { - case PGP_PKT_SECRET_KEY: - if (!parse_pgp_secretkey_packet(&packet, key)) - return FALSE; - break; - default: - break; - } - } - } - } - return TRUE; -} - -/* - * compare two OpenPGP certificates - */ -static bool -same_pgpcert(pgpcert_t *a, pgpcert_t *b) -{ - return a->certificate.len == b->certificate.len && - memcmp(a->certificate.ptr, b->certificate.ptr, b->certificate.len) == 0; -} - -/* - * for each link pointing to the certificate increase the count by one - */ -void -share_pgpcert(pgpcert_t *cert) -{ - if (cert != NULL) - cert->count++; -} - -/* - * select the OpenPGP keyid as ID - */ -void -select_pgpcert_id(pgpcert_t *cert, struct id *end_id) -{ - end_id->kind = ID_KEY_ID; - end_id->name.len = PGP_FINGERPRINT_SIZE; - end_id->name.ptr = cert->fingerprint; - end_id->name.ptr = temporary_cyclic_buffer(); - memcpy(end_id->name.ptr, cert->fingerprint, PGP_FINGERPRINT_SIZE); -} - -/* - * add an OpenPGP user/host certificate to the chained list - */ -pgpcert_t* -add_pgpcert(pgpcert_t *cert) -{ - pgpcert_t *c = pgpcerts; - - while (c != NULL) - { - if (same_pgpcert(c, cert)) /* already in chain, free cert */ - { - free_pgpcert(cert); - return c; - } - c = c->next; - } - - /* insert new cert at the root of the chain */ - cert->next = pgpcerts; - pgpcerts = cert; - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" pgp cert inserted") - ) - return cert; -} - -/* release of a certificate decreases the count by one - " the certificate is freed when the counter reaches zero - */ -void -release_pgpcert(pgpcert_t *cert) -{ - if (cert != NULL && --cert->count == 0) - { - pgpcert_t **pp = &pgpcerts; - while (*pp != cert) - pp = &(*pp)->next; - *pp = cert->next; - free_pgpcert(cert); - } -} - -/* - * free a PGP certificate - */ -void -free_pgpcert(pgpcert_t *cert) -{ - if (cert != NULL) - { - if (cert->certificate.ptr != NULL) - pfree(cert->certificate.ptr); - pfree(cert); - } -} - -/* - * list all PGP end certificates in a chained list - */ -void -list_pgp_end_certs(bool utc) -{ - pgpcert_t *cert = pgpcerts; - time_t now; - - /* determine the current time */ - time(&now); - - if (cert != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of PGP End certificates:"); - whack_log(RC_COMMENT, " "); - } - - while (cert != NULL) - { - unsigned keysize; - char buf[BUF_LEN]; - cert_t c; - - c.type = CERT_PGP; - c.u.pgp = cert; - - whack_log(RC_COMMENT, "%s, count: %d", timetoa(&cert->installed, utc), cert->count); - datatot(cert->fingerprint, PGP_FINGERPRINT_SIZE, 'x', buf, BUF_LEN); - whack_log(RC_COMMENT, " fingerprint: %s", buf); - form_keyid(cert->publicExponent, cert->modulus, buf, &keysize); - whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s", 8*keysize, buf, - (has_private_key(c))? ", has private key" : ""); - whack_log(RC_COMMENT, " created: %s", timetoa(&cert->created, utc)); - whack_log(RC_COMMENT, " until: %s %s", timetoa(&cert->until, utc), - check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE)); - cert = cert->next; - } -} - diff --git a/src/pluto/pgpcert.c b/src/pluto/pgpcert.c new file mode 100644 index 000000000..7fb8232d5 --- /dev/null +++ b/src/pluto/pgpcert.c @@ -0,0 +1,496 @@ +/* Support of OpenPGP certificates + * 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 <string.h> +#include <time.h> + +#include <freeswan.h> + +#include <library.h> +#include <pgp/pgp.h> +#include <crypto/hashers/hasher.h> + +#include "constants.h" +#include "defs.h" +#include "log.h" +#include "id.h" +#include "pgpcert.h" +#include "certs.h" +#include "whack.h" +#include "keys.h" + +/** + * Chained list of OpenPGP end certificates + */ +static pgpcert_t *pgpcerts = NULL; + +/** + * Size of PGP Key ID + */ +#define PGP_KEYID_SIZE 8 + +const pgpcert_t pgpcert_empty = { + NULL , /* next */ + 0 , /* version */ + 0 , /* installed */ + 0 , /* count */ + { NULL, 0 }, /* certificate */ + 0 , /* created */ + 0 , /* until */ + NULL , /* public key */ + NULL /* fingerprint */ +}; + + +/** + * Extracts the length of a PGP packet + */ +static size_t pgp_old_packet_length(chunk_t *blob) +{ + /* bits 0 and 1 define the packet length type */ + int len_type = 0x03 & *blob->ptr++; + + blob->len--; + + /* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */ + return pgp_length(blob, (len_type == 0)? 1: len_type << 1); +} + +/** + * Extracts PGP packet version (V3 or V4) + */ +static u_char pgp_version(chunk_t *blob) +{ + u_char version = *blob->ptr++; + blob->len--; + DBG(DBG_PARSING, + DBG_log("L3 - version:"); + DBG_log(" V%d", version) + ) + return version; +} + +/** + * Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440 + */ +static bool parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert) +{ + time_t created; + chunk_t keyid; + u_char sig_type; + u_char version = pgp_version(packet); + + /* we parse only V3 signature packets */ + if (version != 3) + { + return TRUE; + } + + /* size byte must have the value 5 */ + if (pgp_length(packet, 1) != 5) + { + plog(" size must be 5"); + return FALSE; + } + + /* signature type - 1 byte */ + sig_type = (u_char)pgp_length(packet, 1); + DBG(DBG_PARSING, + DBG_log("L3 - signature type: 0x%2x", sig_type) + ) + + /* creation date - 4 bytes */ + created = (time_t)pgp_length(packet, 4); + DBG(DBG_PARSING, + DBG_log("L3 - created:"); + DBG_log(" %T", &cert->created, TRUE) + ) + + /* key ID of signer - 8 bytes */ + keyid.ptr = packet->ptr; + keyid.len = PGP_KEYID_SIZE; + DBG_cond_dump_chunk(DBG_PARSING, "L3 - key ID of signer", keyid); + + return TRUE; +} + +/** + * Parses the version and validity of an OpenPGP public key packet + */ +static bool parse_pgp_pubkey_version_validity(chunk_t *packet, pgpcert_t *cert) +{ + cert->version = pgp_version(packet); + + if (cert->version < 3 || cert->version > 4) + { + plog("OpenPGP packet version V%d not supported", cert->version); + return FALSE; + } + + /* creation date - 4 bytes */ + cert->created = (time_t)pgp_length(packet, 4); + DBG(DBG_PARSING, + DBG_log("L3 - created:"); + DBG_log(" %T", &cert->created, TRUE) + ) + + if (cert->version == 3) + { + /* validity in days - 2 bytes */ + cert->until = (time_t)pgp_length(packet, 2); + + /* validity of 0 days means that the key never expires */ + if (cert->until > 0) + { + cert->until = cert->created + 24*3600*cert->until; + } + DBG(DBG_PARSING, + DBG_log("L3 - until:"); + DBG_log(" %T", &cert->until, TRUE); + ) + } + return TRUE; +} + +/** + * Parse OpenPGP public key packet defined in section 5.5.2 of RFC 4880 + */ +static bool parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert) +{ + pgp_pubkey_alg_t pubkey_alg; + public_key_t *key; + + if (!parse_pgp_pubkey_version_validity(packet, cert)) + { + return FALSE; + } + + /* public key algorithm - 1 byte */ + pubkey_alg = pgp_length(packet, 1); + DBG(DBG_PARSING, + DBG_log("L3 - public key algorithm:"); + DBG_log(" %N", pgp_pubkey_alg_names, pubkey_alg) + ) + + switch (pubkey_alg) + { + case PGP_PUBKEY_ALG_RSA: + case PGP_PUBKEY_ALG_RSA_SIGN_ONLY: + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + BUILD_BLOB_PGP, *packet, + BUILD_END); + if (key == NULL) + { + return FALSE; + } + cert->public_key = key; + + if (cert->version == 3) + { + cert->fingerprint = key->get_id(key, ID_KEY_ID); + if (cert->fingerprint == NULL) + { + return FALSE; + } + } + else + { + plog(" computation of V4 key ID not implemented yet"); + return FALSE; + } + break; + default: + plog(" non RSA public keys not supported"); + return FALSE; + } + return TRUE; +} + +/* + * Parse OpenPGP secret key packet defined in section 5.5.3 of RFC 4880 + */ +static bool parse_pgp_secretkey_packet(chunk_t *packet, private_key_t **key) +{ + pgp_pubkey_alg_t pubkey_alg; + pgpcert_t cert = pgpcert_empty; + + if (!parse_pgp_pubkey_version_validity(packet, &cert)) + { + return FALSE; + } + + /* public key algorithm - 1 byte */ + pubkey_alg = pgp_length(packet, 1); + DBG(DBG_PARSING, + DBG_log("L3 - public key algorithm:"); + DBG_log(" %N", pgp_pubkey_alg_names, pubkey_alg) + ) + + switch (pubkey_alg) + { + case PGP_PUBKEY_ALG_RSA: + case PGP_PUBKEY_ALG_RSA_SIGN_ONLY: + *key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, + BUILD_BLOB_PGP, *packet, + BUILD_END); + break; + default: + plog(" non RSA private keys not supported"); + return FALSE; + } + return (*key != NULL); +} + +bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key) +{ + DBG(DBG_PARSING, + DBG_log("L0 - PGP file:") + ) + DBG_cond_dump_chunk(DBG_RAW, "", blob); + + if (cert != NULL) + { + /* parse a PGP certificate file */ + cert->certificate = blob; + time(&cert->installed); + } + else if (key == NULL) + { + /* should not occur, nothing to parse */ + return FALSE; + } + + while (blob.len > 0) + { + chunk_t packet = chunk_empty; + u_char packet_tag = *blob.ptr; + + DBG(DBG_PARSING, + DBG_log("L1 - PGP packet: tag= 0x%2x", packet_tag) + ) + + /* bit 7 must be set */ + if (!(packet_tag & 0x80)) + { + plog(" incorrect Packet Tag"); + return FALSE; + } + + /* bit 6 set defines new packet format */ + if (packet_tag & 0x40) + { + plog(" new PGP packet format not supported"); + return FALSE; + } + else + { + int packet_type = (packet_tag & 0x3C) >> 2; + + packet.len = pgp_old_packet_length(&blob); + packet.ptr = blob.ptr; + blob.ptr += packet.len; + blob.len -= packet.len; + DBG(DBG_PARSING, + DBG_log(" %N (%d), old format, %u bytes", + pgp_packet_tag_names, packet_type, + packet_type, packet.len); + DBG_log("L2 - body:") + ) + DBG_cond_dump_chunk(DBG_RAW, "", packet); + + if (cert != NULL) + { + /* parse a PGP certificate */ + switch (packet_type) + { + case PGP_PKT_PUBLIC_KEY: + if (!parse_pgp_pubkey_packet(&packet, cert)) + { + return FALSE; + } + break; + case PGP_PKT_SIGNATURE: + if (!parse_pgp_signature_packet(&packet, cert)) + { + return FALSE; + } + break; + case PGP_PKT_USER_ID: + DBG(DBG_PARSING, + DBG_log("L3 - user ID:"); + DBG_log(" '%.*s'", (int)packet.len, packet.ptr) + ) + break; + default: + break; + } + } + else + { + /* parse a PGP private key file */ + switch (packet_type) + { + case PGP_PKT_SECRET_KEY: + if (!parse_pgp_secretkey_packet(&packet, key)) + { + return FALSE; + } + break; + case PGP_PKT_USER_ID: + DBG(DBG_PARSING, + DBG_log("L3 - user ID:"); + DBG_log(" '%.*s'", (int)packet.len, packet.ptr) + ) + break; + default: + break; + } + + } + } + } + return TRUE; +} + +/** + * Compare two OpenPGP certificates + */ +static bool same_pgpcert(pgpcert_t *a, pgpcert_t *b) +{ + return a->certificate.len == b->certificate.len && + memeq(a->certificate.ptr, b->certificate.ptr, b->certificate.len); +} + +/** + * For each link pointing to the certificate increase the count by one + */ +void share_pgpcert(pgpcert_t *cert) +{ + if (cert != NULL) + { + cert->count++; + } +} + +/** + * Select the OpenPGP keyid as ID + */ +void select_pgpcert_id(pgpcert_t *cert, struct id *end_id) +{ + end_id->kind = ID_KEY_ID; + end_id->name = cert->fingerprint->get_encoding(cert->fingerprint); +} + +/** + * Add an OpenPGP user/host certificate to the chained list + */ +pgpcert_t* add_pgpcert(pgpcert_t *cert) +{ + pgpcert_t *c = pgpcerts; + + while (c != NULL) + { + if (same_pgpcert(c, cert)) /* already in chain, free cert */ + { + free_pgpcert(cert); + return c; + } + c = c->next; + } + + /* insert new cert at the root of the chain */ + cert->next = pgpcerts; + pgpcerts = cert; + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log(" pgp cert inserted") + ) + return cert; +} + +/** + * Release of a certificate decreases the count by one. + * The certificate is freed when the counter reaches zero + */ +void release_pgpcert(pgpcert_t *cert) +{ + if (cert != NULL && --cert->count == 0) + { + pgpcert_t **pp = &pgpcerts; + while (*pp != cert) + { + pp = &(*pp)->next; + } + *pp = cert->next; + free_pgpcert(cert); + } +} + +/** + * Free a PGP certificate + */ +void free_pgpcert(pgpcert_t *cert) +{ + if (cert != NULL) + { + DESTROY_IF(cert->public_key); + DESTROY_IF(cert->fingerprint); + free(cert->certificate.ptr); + free(cert); + } +} + +/** + * List all PGP end certificates in a chained list + */ +void list_pgp_end_certs(bool utc) +{ + pgpcert_t *cert = pgpcerts; + time_t now; + + /* determine the current time */ + time(&now); + + if (cert != NULL) + { + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of PGP End certificates:"); + whack_log(RC_COMMENT, " "); + } + + while (cert != NULL) + { + public_key_t *key = cert->public_key; + cert_t c; + + c.type = CERT_PGP; + c.u.pgp = cert; + + whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, cert->count); + whack_log(RC_COMMENT, " digest: %Y", cert->fingerprint); + whack_log(RC_COMMENT, " created: %T", &cert->created, utc); + whack_log(RC_COMMENT, " until: %T %s", &cert->until, utc, + check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE)); + whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", + key_type_names, key->get_type(key), + key->get_keysize(key) * BITS_PER_BYTE, + has_private_key(c)? ", has private key" : ""); + whack_log(RC_COMMENT, " keyid: %Y", + key->get_id(key, ID_PUBKEY_INFO_SHA1)); + cert = cert->next; + } +} + diff --git a/src/pluto/pgp.h b/src/pluto/pgpcert.h index 514265086..727648391 100644 --- a/src/pluto/pgp.h +++ b/src/pluto/pgpcert.h @@ -1,5 +1,7 @@ /* Support of OpenPGP certificates - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * 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 @@ -10,18 +12,19 @@ * 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. - * - * RCSID $Id: pgp.h 3252 2007-10-06 21:24:50Z andreas $ */ -#ifndef _PGP_H -#define _PGP_H +#ifndef _PGPCERT_H +#define _PGPCERT_H + +#include <crypto/hashers/hasher.h> +#include <credentials/keys/private_key.h> +#include <credentials/keys/public_key.h> -#include "pkcs1.h" /* * Length of PGP V3 fingerprint */ -#define PGP_FINGERPRINT_SIZE MD5_DIGEST_SIZE +#define PGP_FINGERPRINT_SIZE HASH_SIZE_MD5 typedef char fingerprint_t[PGP_FINGERPRINT_SIZE]; @@ -30,20 +33,19 @@ typedef char fingerprint_t[PGP_FINGERPRINT_SIZE]; typedef struct pgpcert pgpcert_t; struct pgpcert { - pgpcert_t *next; - time_t installed; - int count; - chunk_t certificate; - time_t created; - time_t until; - enum pubkey_alg pubkeyAlg; - chunk_t modulus; - chunk_t publicExponent; - fingerprint_t fingerprint; + pgpcert_t *next; + int version; + time_t installed; + int count; + chunk_t certificate; + time_t created; + time_t until; + public_key_t *public_key; + identification_t *fingerprint; }; -extern const pgpcert_t empty_pgpcert; -extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key); +extern const pgpcert_t pgpcert_empty; +extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key); extern void share_pgpcert(pgpcert_t *cert); extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id); extern pgpcert_t* add_pgpcert(pgpcert_t *cert); @@ -51,4 +53,4 @@ extern void list_pgp_end_certs(bool utc); extern void release_pgpcert(pgpcert_t *cert); extern void free_pgpcert(pgpcert_t *cert); -#endif /* _PGP_H */ +#endif /* _PGPCERT_H */ diff --git a/src/pluto/pkcs1.c b/src/pluto/pkcs1.c deleted file mode 100644 index 49a06a8bc..000000000 --- a/src/pluto/pkcs1.c +++ /dev/null @@ -1,676 +0,0 @@ -/* Support of PKCS#1 private key data structures - * Copyright (C) 2005 Jan Hutter, Martin Willi - * Copyright (C) 2002-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. - * - * RCSID $Id: pkcs1.c 3427 2008-01-27 20:17:15Z andreas $ - */ - -#include <stddef.h> -#include <stdlib.h> -#include <string.h> - -#include <freeswan.h> -#include <libsha2/sha2.h> - -#include "constants.h" -#include "defs.h" -#include "mp_defs.h" -#include "asn1.h" -#include <asn1/oid.h> -#include "log.h" -#include "pkcs1.h" -#include "md2.h" -#include "md5.h" -#include "sha1.h" -#include "rnd.h" - -const struct fld RSA_private_field[] = -{ - { "Modulus", offsetof(RSA_private_key_t, pub.n) }, - { "PublicExponent", offsetof(RSA_private_key_t, pub.e) }, - - { "PrivateExponent", offsetof(RSA_private_key_t, d) }, - { "Prime1", offsetof(RSA_private_key_t, p) }, - { "Prime2", offsetof(RSA_private_key_t, q) }, - { "Exponent1", offsetof(RSA_private_key_t, dP) }, - { "Exponent2", offsetof(RSA_private_key_t, dQ) }, - { "Coefficient", offsetof(RSA_private_key_t, qInv) }, -}; - -/* ASN.1 definition of a PKCS#1 RSA private key */ - -static const asn1Object_t privkeyObjects[] = { - { 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ - { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */ - { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */ - { 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */ - { 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */ - { 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */ - { 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */ - { 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */ - { 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */ - { 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT | - ASN1_LOOP }, /* 10 */ - { 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ - { 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */ - { 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */ - { 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */ - { 1, "end opt or loop", ASN1_EOC, ASN1_END } /* 15 */ -}; - -#define PKCS1_PRIV_KEY_VERSION 1 -#define PKCS1_PRIV_KEY_MODULUS 2 -#define PKCS1_PRIV_KEY_PUB_EXP 3 -#define PKCS1_PRIV_KEY_COEFF 9 -#define PKCS1_PRIV_KEY_ROOF 16 - - -/* - * forms the FreeS/WAN keyid from the public exponent e and modulus n - */ -void -form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize) -{ - /* eliminate leading zero bytes in modulus from ASN.1 coding */ - while (n.len > 1 && *n.ptr == 0x00) - { - n.ptr++; n.len--; - } - - /* form the FreeS/WAN keyid */ - keyid[0] = '\0'; /* in case of splitkeytoid failure */ - splitkeytoid(e.ptr, e.len, n.ptr, n.len, keyid, KEYID_BUF); - - /* return the RSA modulus size in octets */ - *keysize = n.len; -} - -/* - * initialize an RSA_public_key_t object - */ -void -init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n) -{ - n_to_mpz(&rsa->e, e.ptr, e.len); - n_to_mpz(&rsa->n, n.ptr, n.len); - - form_keyid(e, n, rsa->keyid, &rsa->k); -} - -#ifdef DEBUG -static void -RSA_show_key_fields(RSA_private_key_t *k, int fieldcnt) -{ - const struct fld *p; - - DBG_log(" keyid: *%s", k->pub.keyid); - - for (p = RSA_private_field; p < &RSA_private_field[fieldcnt]; p++) - { - MP_INT *n = (MP_INT *) ((char *)k + p->offset); - size_t sz = mpz_sizeinbase(n, 16); - char buf[RSA_MAX_OCTETS * 2 + 2]; /* ought to be big enough */ - - passert(sz <= sizeof(buf)); - mpz_get_str(buf, 16, n); - - DBG_log(" %s: 0x%s", p->name, buf); - } -} - -/* debugging info that compromises security! */ -void -RSA_show_private_key(RSA_private_key_t *k) -{ - RSA_show_key_fields(k, elemsof(RSA_private_field)); -} - -void -RSA_show_public_key(RSA_public_key_t *k) -{ - /* Kludge: pretend that it is a private key, but only display the - * first two fields (which are the public key). - */ - passert(offsetof(RSA_private_key_t, pub) == 0); - RSA_show_key_fields((RSA_private_key_t *)k, 2); -} -#endif - -err_t -RSA_private_key_sanity(RSA_private_key_t *k) -{ - /* note that the *last* error found is reported */ - err_t ugh = NULL; - mpz_t t, u, q1; - -#ifdef DEBUG /* debugging info that compromises security */ - DBG(DBG_PRIVATE, RSA_show_private_key(k)); -#endif - - /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets. - * We actually require more (for security). - */ - if (k->pub.k < RSA_MIN_OCTETS) - return RSA_MIN_OCTETS_UGH; - - /* we picked a max modulus size to simplify buffer allocation */ - if (k->pub.k > RSA_MAX_OCTETS) - return RSA_MAX_OCTETS_UGH; - - mpz_init(t); - mpz_init(u); - mpz_init(q1); - - /* check that n == p * q */ - mpz_mul(u, &k->p, &k->q); - if (mpz_cmp(u, &k->pub.n) != 0) - ugh = "n != p * q"; - - /* check that e divides neither p-1 nor q-1 */ - mpz_sub_ui(t, &k->p, 1); - mpz_mod(t, t, &k->pub.e); - if (mpz_cmp_ui(t, 0) == 0) - ugh = "e divides p-1"; - - mpz_sub_ui(t, &k->q, 1); - mpz_mod(t, t, &k->pub.e); - if (mpz_cmp_ui(t, 0) == 0) - ugh = "e divides q-1"; - - /* check that d is e^-1 (mod lcm(p-1, q-1)) */ - /* see PKCS#1v2, aka RFC 2437, for the "lcm" */ - mpz_sub_ui(q1, &k->q, 1); - mpz_sub_ui(u, &k->p, 1); - mpz_gcd(t, u, q1); /* t := gcd(p-1, q-1) */ - mpz_mul(u, u, q1); /* u := (p-1) * (q-1) */ - mpz_divexact(u, u, t); /* u := lcm(p-1, q-1) */ - - mpz_mul(t, &k->d, &k->pub.e); - mpz_mod(t, t, u); - if (mpz_cmp_ui(t, 1) != 0) - ugh = "(d * e) mod (lcm(p-1, q-1)) != 1"; - - /* check that dP is d mod (p-1) */ - mpz_sub_ui(u, &k->p, 1); - mpz_mod(t, &k->d, u); - if (mpz_cmp(t, &k->dP) != 0) - ugh = "dP is not congruent to d mod (p-1)"; - - /* check that dQ is d mod (q-1) */ - mpz_sub_ui(u, &k->q, 1); - mpz_mod(t, &k->d, u); - if (mpz_cmp(t, &k->dQ) != 0) - ugh = "dQ is not congruent to d mod (q-1)"; - - /* check that qInv is (q^-1) mod p */ - mpz_mul(t, &k->qInv, &k->q); - mpz_mod(t, t, &k->p); - if (mpz_cmp_ui(t, 1) != 0) - ugh = "qInv is not conguent ot (q^-1) mod p"; - - mpz_clear(t); - mpz_clear(u); - mpz_clear(q1); - return ugh; -} - -/* - * Check the equality of two RSA public keys - */ -bool -same_RSA_public_key(const RSA_public_key_t *a, const RSA_public_key_t *b) -{ - return a == b - || (a->k == b->k && mpz_cmp(&a->n, &b->n) == 0 && mpz_cmp(&a->e, &b->e) == 0); -} - -/* - * Parses a PKCS#1 private key - */ -bool -pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key) -{ - err_t ugh = NULL; - asn1_ctx_t ctx; - chunk_t object, modulus, exp; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, 0, FALSE, DBG_PRIVATE); - - while (objectID < PKCS1_PRIV_KEY_ROOF) { - - if (!extract_object(privkeyObjects, &objectID, &object, &level, &ctx)) - return FALSE; - - if (objectID == PKCS1_PRIV_KEY_VERSION) - { - if (object.len > 0 && *object.ptr != 0) - { - plog(" wrong PKCS#1 private key version"); - return FALSE; - } - } - else if (objectID >= PKCS1_PRIV_KEY_MODULUS && - objectID <= PKCS1_PRIV_KEY_COEFF) - { - MP_INT *u = (MP_INT *) ((char *)key - + RSA_private_field[objectID - PKCS1_PRIV_KEY_MODULUS].offset); - - n_to_mpz(u, object.ptr, object.len); - - if (objectID == PKCS1_PRIV_KEY_MODULUS) - modulus = object; - else if (objectID == PKCS1_PRIV_KEY_PUB_EXP) - exp = object; - } - objectID++; - } - form_keyid(exp, modulus, key->pub.keyid, &key->pub.k); - ugh = RSA_private_key_sanity(key); - return (ugh == NULL); -} - -/* - * compute a digest over a binary blob - */ -bool -compute_digest(chunk_t tbs, int alg, chunk_t *digest) -{ - switch (alg) - { - case OID_MD2: - case OID_MD2_WITH_RSA: - { - MD2_CTX context; - - MD2Init(&context); - MD2Update(&context, tbs.ptr, tbs.len); - MD2Final(digest->ptr, &context); - digest->len = MD2_DIGEST_SIZE; - return TRUE; - } - case OID_MD5: - case OID_MD5_WITH_RSA: - { - MD5_CTX context; - - MD5Init(&context); - MD5Update(&context, tbs.ptr, tbs.len); - MD5Final(digest->ptr, &context); - digest->len = MD5_DIGEST_SIZE; - return TRUE; - } - case OID_SHA1: - case OID_SHA1_WITH_RSA: - case OID_SHA1_WITH_RSA_OIW: - { - SHA1_CTX context; - - SHA1Init(&context); - SHA1Update(&context, tbs.ptr, tbs.len); - SHA1Final(digest->ptr, &context); - digest->len = SHA1_DIGEST_SIZE; - return TRUE; - } - case OID_SHA256: - case OID_SHA256_WITH_RSA: - { - sha256_context context; - - sha256_init(&context); - sha256_write(&context, tbs.ptr, tbs.len); - sha256_final(&context); - memcpy(digest->ptr, context.sha_out, SHA2_256_DIGEST_SIZE); - digest->len = SHA2_256_DIGEST_SIZE; - return TRUE; - } - case OID_SHA384: - case OID_SHA384_WITH_RSA: - { - sha512_context context; - - sha384_init(&context); - sha512_write(&context, tbs.ptr, tbs.len); - sha512_final(&context); - memcpy(digest->ptr, context.sha_out, SHA2_384_DIGEST_SIZE); - digest->len = SHA2_384_DIGEST_SIZE; - return TRUE; - } - case OID_SHA512: - case OID_SHA512_WITH_RSA: - { - sha512_context context; - - sha512_init(&context); - sha512_write(&context, tbs.ptr, tbs.len); - sha512_final(&context); - memcpy(digest->ptr, context.sha_out, SHA2_512_DIGEST_SIZE); - digest->len = SHA2_512_DIGEST_SIZE; - return TRUE; - } - default: - digest->len = 0; - return FALSE; - } -} - -/* - * compute an RSA signature with PKCS#1 padding - */ -void -sign_hash(const RSA_private_key_t *k, const u_char *hash_val, size_t hash_len - , u_char *sig_val, size_t sig_len) -{ - chunk_t ch; - mpz_t t1, t2; - size_t padlen; - u_char *p = sig_val; - - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("signing hash with RSA Key *%s", k->pub.keyid) - ) - /* PKCS#1 v1.5 8.1 encryption-block formatting */ - *p++ = 0x00; - *p++ = 0x01; /* BT (block type) 01 */ - padlen = sig_len - 3 - hash_len; - memset(p, 0xFF, padlen); - p += padlen; - *p++ = 0x00; - memcpy(p, hash_val, hash_len); - passert(p + hash_len - sig_val == (ptrdiff_t)sig_len); - - /* PKCS#1 v1.5 8.2 octet-string-to-integer conversion */ - n_to_mpz(t1, sig_val, sig_len); /* (could skip leading 0x00) */ - - /* PKCS#1 v1.5 8.3 RSA computation y = x^c mod n - * Better described in PKCS#1 v2.0 5.1 RSADP. - * There are two methods, depending on the form of the private key. - * We use the one based on the Chinese Remainder Theorem. - */ - mpz_init(t2); - - mpz_powm(t2, t1, &k->dP, &k->p); /* m1 = c^dP mod p */ - - mpz_powm(t1, t1, &k->dQ, &k->q); /* m2 = c^dQ mod Q */ - - mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */ - mpz_mod(t2, t2, &k->p); - mpz_mul(t2, t2, &k->qInv); - mpz_mod(t2, t2, &k->p); - - mpz_mul(t2, t2, &k->q); /* m = m2 + h q */ - mpz_add(t1, t1, t2); - - /* PKCS#1 v1.5 8.4 integer-to-octet-string conversion */ - ch = mpz_to_n(t1, sig_len); - memcpy(sig_val, ch.ptr, sig_len); - pfree(ch.ptr); - - mpz_clear(t1); - mpz_clear(t2); -} - -/* - * encrypt data with an RSA public key after padding - */ -chunk_t -RSA_encrypt(const RSA_public_key_t *key, chunk_t in) -{ - u_char padded[RSA_MAX_OCTETS]; - u_char *pos = padded; - int padding = key->k - in.len - 3; - int i; - - if (padding < 8 || key->k > RSA_MAX_OCTETS) - return empty_chunk; - - /* add padding according to PKCS#1 7.2.1 1.+2. */ - *pos++ = 0x00; - *pos++ = 0x02; - - /* pad with pseudo random bytes unequal to zero */ - for (i = 0; i < padding; i++) - { - get_rnd_bytes(pos, padding); - while (!*pos) - { - get_rnd_bytes(pos, 1); - } - pos++; - } - - /* append the padding terminator */ - *pos++ = 0x00; - - /* now add the data */ - memcpy(pos, in.ptr, in.len); - DBG(DBG_RAW, - DBG_dump_chunk("data for rsa encryption:\n", in); - DBG_dump("padded data for rsa encryption:\n", padded, key->k) - ) - - /* convert chunk to integer (PKCS#1 7.2.1 3.a) */ - { - chunk_t out; - mpz_t m, c; - - mpz_init(c); - n_to_mpz(m, padded, key->k); - - /* encrypt(PKCS#1 7.2.1 3.b) */ - mpz_powm(c, m, &key->e, &key->n); - - /* convert integer back to a chunk (PKCS#1 7.2.1 3.c) */ - out = mpz_to_n(c, key->k); - mpz_clear(c); - mpz_clear(m); - - DBG(DBG_RAW, - DBG_dump_chunk("rsa encrypted data:\n", out) - ) - return out; - } -} - -/* - * decrypt data with an RSA private key and remove padding - */ -bool -RSA_decrypt(const RSA_private_key_t *key, chunk_t in, chunk_t *out) -{ - chunk_t padded; - u_char *pos; - mpz_t t1, t2; - - n_to_mpz(t1, in.ptr,in.len); - - /* PKCS#1 v1.5 8.3 RSA computation y = x^c mod n - * Better described in PKCS#1 v2.0 5.1 RSADP. - * There are two methods, depending on the form of the private key. - * We use the one based on the Chinese Remainder Theorem. - */ - mpz_init(t2); - - mpz_powm(t2, t1, &key->dP, &key->p); /* m1 = c^dP mod p */ - mpz_powm(t1, t1, &key->dQ, &key->q); /* m2 = c^dQ mod Q */ - - mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */ - mpz_mod(t2, t2, &key->p); - mpz_mul(t2, t2, &key->qInv); - mpz_mod(t2, t2, &key->p); - - mpz_mul(t2, t2, &key->q); /* m = m2 + h q */ - mpz_add(t1, t1, t2); - - padded = mpz_to_n(t1, key->pub.k); - mpz_clear(t1); - mpz_clear(t2); - - DBG(DBG_PRIVATE, - DBG_dump_chunk("rsa decrypted data with padding:\n", padded) - ) - pos = padded.ptr; - - /* PKCS#1 v1.5 8.1 encryption-block formatting (EB = 00 || 02 || PS || 00 || D) */ - - /* check for hex pattern 00 02 in decrypted message */ - if ((*pos++ != 0x00) || (*(pos++) != 0x02)) - { - plog("incorrect padding - probably wrong RSA key"); - freeanychunk(padded); - return FALSE; - } - padded.len -= 2; - - /* the plaintext data starts after first 0x00 byte */ - while (padded.len-- > 0 && *pos++ != 0x00) - - if (padded.len == 0) - { - plog("no plaintext data"); - freeanychunk(padded); - return FALSE; - } - - clonetochunk(*out, pos, padded.len, "decrypted data"); - freeanychunk(padded); - return TRUE; -} - -/* - * build signatureValue - */ -chunk_t -pkcs1_build_signature(chunk_t tbs, int hash_alg, const RSA_private_key_t *key -, bool bit_string) -{ - - size_t siglen = key->pub.k; - - u_char digest_buf[MAX_DIGEST_LEN]; - chunk_t digest = { digest_buf, MAX_DIGEST_LEN }; - chunk_t digestInfo, alg_id, signatureValue; - u_char *pos; - - switch (hash_alg) - { - case OID_MD5: - case OID_MD5_WITH_RSA: - alg_id = ASN1_md5_id; - break; - case OID_SHA1: - case OID_SHA1_WITH_RSA: - alg_id = ASN1_sha1_id; - break; - default: - return empty_chunk; - } - compute_digest(tbs, hash_alg, &digest); - - /* according to PKCS#1 v2.1 digest must be packaged into - * an ASN.1 structure for encryption - */ - digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm" - , alg_id - , asn1_simple_object(ASN1_OCTET_STRING, digest)); - - /* generate the RSA signature */ - if (bit_string) - { - pos = build_asn1_object(&signatureValue, ASN1_BIT_STRING, 1 + siglen); - *pos++ = 0x00; - } - else - { - pos = build_asn1_object(&signatureValue, ASN1_OCTET_STRING, siglen); - } - sign_hash(key, digestInfo.ptr, digestInfo.len, pos, siglen); - pfree(digestInfo.ptr); - - return signatureValue; -} - -/* - * build a DER-encoded PKCS#1 private key object - */ -chunk_t -pkcs1_build_private_key(const RSA_private_key_t *key) -{ - chunk_t pkcs1 = asn1_wrap(ASN1_SEQUENCE, "cmmmmmmmm" - , ASN1_INTEGER_0 - , asn1_integer_from_mpz(&key->pub.n) - , asn1_integer_from_mpz(&key->pub.e) - , asn1_integer_from_mpz(&key->d) - , asn1_integer_from_mpz(&key->p) - , asn1_integer_from_mpz(&key->q) - , asn1_integer_from_mpz(&key->dP) - , asn1_integer_from_mpz(&key->dQ) - , asn1_integer_from_mpz(&key->qInv)); - - DBG(DBG_PRIVATE, - DBG_dump_chunk("PKCS#1 encoded private key:", pkcs1) - ) - return pkcs1; -} - -/* - * build a DER-encoded PKCS#1 public key object - */ -chunk_t -pkcs1_build_public_key(const RSA_public_key_t *rsa) -{ - return asn1_wrap(ASN1_SEQUENCE, "mm" - , asn1_integer_from_mpz(&rsa->n) - , asn1_integer_from_mpz(&rsa->e)); -} - -/* - * build a DER-encoded publicKeyInfo object - */ -chunk_t -pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa) -{ - chunk_t publicKey; - chunk_t rawKey = pkcs1_build_public_key(rsa); - - u_char *pos = build_asn1_object(&publicKey, ASN1_BIT_STRING - , 1 + rawKey.len); - *pos++ = 0x00; - mv_chunk(&pos, rawKey); - - return asn1_wrap(ASN1_SEQUENCE, "cm" - , ASN1_rsaEncryption_id - , publicKey); -} -void -free_RSA_public_content(RSA_public_key_t *rsa) -{ - mpz_clear(&rsa->n); - mpz_clear(&rsa->e); -} - -void -free_RSA_private_content(RSA_private_key_t *rsak) -{ - free_RSA_public_content(&rsak->pub); - mpz_clear(&rsak->d); - mpz_clear(&rsak->p); - mpz_clear(&rsak->q); - mpz_clear(&rsak->dP); - mpz_clear(&rsak->dQ); - mpz_clear(&rsak->qInv); -} - diff --git a/src/pluto/pkcs1.h b/src/pluto/pkcs1.h deleted file mode 100644 index 16a6f02b9..000000000 --- a/src/pluto/pkcs1.h +++ /dev/null @@ -1,88 +0,0 @@ -/* Support of PKCS#1 private key data structures - * Copyright (C) 2005 Jan Hutter, Martin Willi - * Copyright (C) 2002-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. - * - * RCSID $Id: pkcs1.h 3252 2007-10-06 21:24:50Z andreas $ - */ - -#ifndef _PKCS1_H -#define _PKCS1_H - -#include <gmp.h> /* GNU Multi Precision library */ - -#include "defs.h" - -typedef struct RSA_public_key RSA_public_key_t; - -struct RSA_public_key -{ - char keyid[KEYID_BUF]; /* see ipsec_keyblobtoid(3) */ - - /* length of modulus n in octets: [RSA_MIN_OCTETS, RSA_MAX_OCTETS] */ - unsigned k; - - /* public: */ - MP_INT - n, /* modulus: p * q */ - e; /* exponent: relatively prime to (p-1) * (q-1) [probably small] */ -}; - -typedef struct RSA_private_key RSA_private_key_t; - -struct RSA_private_key { - struct RSA_public_key pub; /* must be at start for RSA_show_public_key */ - - MP_INT - d, /* private exponent: (e^-1) mod ((p-1) * (q-1)) */ - /* help for Chinese Remainder Theorem speedup: */ - p, /* first secret prime */ - q, /* second secret prime */ - dP, /* first factor's exponent: (e^-1) mod (p-1) == d mod (p-1) */ - dQ, /* second factor's exponent: (e^-1) mod (q-1) == d mod (q-1) */ - qInv; /* (q^-1) mod p */ -}; - -struct fld { - const char *name; - size_t offset; -}; - -extern const struct fld RSA_private_field[]; -#define RSA_PRIVATE_FIELD_ELEMENTS 8 - -extern void init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n); -extern bool pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key); -extern chunk_t pkcs1_build_private_key(const RSA_private_key_t *key); -extern chunk_t pkcs1_build_public_key(const RSA_public_key_t *rsa); -extern chunk_t pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa); -extern chunk_t pkcs1_build_signature(chunk_t tbs, int hash_alg - , const RSA_private_key_t *key, bool bit_string); -extern bool compute_digest(chunk_t tbs, int alg, chunk_t *digest); -extern void sign_hash(const RSA_private_key_t *k, const u_char *hash_val - , size_t hash_len, u_char *sig_val, size_t sig_len); -extern chunk_t RSA_encrypt(const RSA_public_key_t *key, chunk_t in); -extern bool RSA_decrypt(const RSA_private_key_t *key, chunk_t in - , chunk_t *out); -extern bool same_RSA_public_key(const RSA_public_key_t *a - , const RSA_public_key_t *b); -extern void form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize); -extern err_t RSA_private_key_sanity(RSA_private_key_t *k); -#ifdef DEBUG -extern void RSA_show_public_key(RSA_public_key_t *k); -extern void RSA_show_private_key(RSA_private_key_t *k); -#endif -extern void free_RSA_public_content(RSA_public_key_t *rsa); -extern void free_RSA_private_content(RSA_private_key_t *rsak); - -#endif /* _PKCS1_H */ diff --git a/src/pluto/pkcs7.c b/src/pluto/pkcs7.c index 60636f385..7248b042f 100644 --- a/src/pluto/pkcs7.c +++ b/src/pluto/pkcs7.c @@ -1,7 +1,8 @@ /* Support of PKCS#7 data structures * Copyright (C) 2005 Jan Hutter, Martin Willi - * Copyright (C) 2002-2005 Andreas Steffen - * Hochschule fuer Technik Rapperswil, Switzerland + * 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 @@ -12,564 +13,562 @@ * 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. - * - * RCSID $Id: pkcs7.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdlib.h> #include <string.h> -#include <libdes/des.h> #include <freeswan.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 "constants.h" #include "defs.h" -#include "asn1.h" -#include <asn1/oid.h> -#include "log.h" #include "x509.h" #include "certs.h" #include "pkcs7.h" -#include "rnd.h" const contentInfo_t empty_contentInfo = { - OID_UNKNOWN , /* type */ - { NULL, 0 } /* content */ + OID_UNKNOWN , /* type */ + { NULL, 0 } /* content */ }; -/* ASN.1 definition of the PKCS#7 ContentInfo type */ - +/** + * 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, "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 -#define PKCS7_INFO_TYPE 1 -#define PKCS7_INFO_CONTENT 2 -#define PKCS7_INFO_ROOF 4 - -/* ASN.1 definition of the PKCS#7 signedData type */ - +/** + * 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, "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_DIGEST_ALG 3 +#define PKCS7_SIGNED_CONTENT_INFO 5 +#define PKCS7_SIGNED_CERT 7 +#define PKCS7_SIGNER_INFO 13 +#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 -#define PKCS7_DIGEST_ALG 3 -#define PKCS7_SIGNED_CONTENT_INFO 5 -#define PKCS7_SIGNED_CERT 7 -#define PKCS7_SIGNER_INFO 13 -#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 -#define PKCS7_SIGNED_ROOF 26 - -/* ASN.1 definition of the PKCS#7 envelopedData type */ - +/** + * 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, "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 -#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 - -/* PKCS7 contentInfo OIDs */ +/** + * PKCS7 contentInfo OIDs + */ static u_char ASN1_pkcs7_data_oid_str[] = { - 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 }; static u_char ASN1_pkcs7_signed_data_oid_str[] = { - 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 }; static u_char ASN1_pkcs7_enveloped_data_oid_str[] = { - 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x03 + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x03 }; static u_char ASN1_pkcs7_signed_enveloped_data_oid_str[] = { - 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x04 + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x04 }; static u_char ASN1_pkcs7_digested_data_oid_str[] = { - 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x05 + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x05 }; static char ASN1_pkcs7_encrypted_data_oid_str[] = { - 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 }; static const chunk_t ASN1_pkcs7_data_oid = - strchunk(ASN1_pkcs7_data_oid_str); + chunk_from_buf(ASN1_pkcs7_data_oid_str); static const chunk_t ASN1_pkcs7_signed_data_oid = - strchunk(ASN1_pkcs7_signed_data_oid_str); + chunk_from_buf(ASN1_pkcs7_signed_data_oid_str); static const chunk_t ASN1_pkcs7_enveloped_data_oid = - strchunk(ASN1_pkcs7_enveloped_data_oid_str); + chunk_from_buf(ASN1_pkcs7_enveloped_data_oid_str); static const chunk_t ASN1_pkcs7_signed_enveloped_data_oid = - strchunk(ASN1_pkcs7_signed_enveloped_data_oid_str); + chunk_from_buf(ASN1_pkcs7_signed_enveloped_data_oid_str); static const chunk_t ASN1_pkcs7_digested_data_oid = - strchunk(ASN1_pkcs7_digested_data_oid_str); + chunk_from_buf(ASN1_pkcs7_digested_data_oid_str); static const chunk_t ASN1_pkcs7_encrypted_data_oid = - strchunk(ASN1_pkcs7_encrypted_data_oid_str); + chunk_from_buf(ASN1_pkcs7_encrypted_data_oid_str); -/* 3DES and DES encryption OIDs */ +/** + * 3DES and DES encryption OIDs + */ static u_char ASN1_3des_ede_cbc_oid_str[] = { - 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07 + 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07 }; static u_char ASN1_des_cbc_oid_str[] = { - 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x07 + 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x07 }; static const chunk_t ASN1_3des_ede_cbc_oid = - strchunk(ASN1_3des_ede_cbc_oid_str); + chunk_from_buf(ASN1_3des_ede_cbc_oid_str); static const chunk_t ASN1_des_cbc_oid = - strchunk(ASN1_des_cbc_oid_str); + chunk_from_buf(ASN1_des_cbc_oid_str); -/* PKCS#7 attribute type OIDs */ +/** + * PKCS#7 attribute type OIDs + */ static u_char ASN1_contentType_oid_str[] = { - 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03 + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03 }; static u_char ASN1_messageDigest_oid_str[] = { - 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04 + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04 }; static const chunk_t ASN1_contentType_oid = - strchunk(ASN1_contentType_oid_str); + chunk_from_buf(ASN1_contentType_oid_str); static const chunk_t ASN1_messageDigest_oid = - strchunk(ASN1_messageDigest_oid_str); + chunk_from_buf(ASN1_messageDigest_oid_str); -/* +/** * Parse PKCS#7 ContentInfo object */ -bool -pkcs7_parse_contentInfo(chunk_t blob, u_int level0, contentInfo_t *cInfo) +bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, contentInfo_t *cInfo) { - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); + asn1_parser_t *parser; + chunk_t object; + int objectID; + bool success = FALSE; - while (objectID < PKCS7_INFO_ROOF) - { - if (!extract_object(contentInfoObjects, &objectID, &object, &level, &ctx)) - return FALSE; + parser = asn1_parser_create(contentInfoObjects, blob); + parser->set_top_level(parser, level0); - if (objectID == PKCS7_INFO_TYPE) + while (parser->iterate(parser, &objectID, &object)) { - cInfo->type = known_oid(object); - if (cInfo->type < OID_PKCS7_DATA - || cInfo->type > OID_PKCS7_ENCRYPTED_DATA) - { - plog("unknown pkcs7 content type"); - return FALSE; - } - } - else if (objectID == PKCS7_INFO_CONTENT) - { - cInfo->content = 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("unknown pkcs7 content type"); + goto end; + } + } + else if (objectID == PKCS7_INFO_CONTENT) + { + cInfo->content = object; + } } - objectID++; - } - return TRUE; + 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, x509cert_t **cert -, chunk_t *attributes, const x509cert_t *cacert) +bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert, + chunk_t *attributes, const x509cert_t *cacert) { - u_char buf[BUF_LEN]; - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int digest_alg = OID_UNKNOWN; - int enc_alg = OID_UNKNOWN; - int signerInfos = 0; - int objectID = 0; - - contentInfo_t cInfo = empty_contentInfo; - chunk_t encrypted_digest = empty_chunk; - - if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) - return FALSE; - - if (cInfo.type != OID_PKCS7_SIGNED_DATA) - { - plog("pkcs7 content type is not signedData"); - return FALSE; - } - - asn1_init(&ctx, cInfo.content, 2, FALSE, DBG_RAW); - - while (objectID < PKCS7_SIGNED_ROOF) - { - if (!extract_object(signedDataObjects, &objectID, &object, &level, &ctx)) - return FALSE; - - switch (objectID) - { - case PKCS7_DIGEST_ALG: - digest_alg = 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: - if (cert != NULL) - { - chunk_t cert_blob; - - x509cert_t *newcert = alloc_thing(x509cert_t - , "pkcs7 wrapped x509cert"); - - clonetochunk(cert_blob, object.ptr, object.len - , "pkcs7 cert blob"); - *newcert = empty_x509cert; - - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log("parsing pkcs7-wrapped certificate") - ) - if (parse_x509cert(cert_blob, level+1, newcert)) - { - newcert->next = *cert; - *cert = newcert; - } - else - { - free_x509cert(newcert); - } - } - break; - case PKCS7_SIGNER_INFO: - signerInfos++; - DBG(DBG_PARSING, - DBG_log(" signer #%d", signerInfos) - ) - break; - case PKCS7_SIGNED_ISSUER: - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'",buf) - ) - break; - case PKCS7_AUTH_ATTRIBUTES: - if (attributes != NULL) - { - *attributes = object; - *attributes->ptr = ASN1_SET; - } - break; - case PKCS7_DIGEST_ALGORITHM: - digest_alg = parse_algorithmIdentifier(object, level, NULL); - break; - case PKCS7_DIGEST_ENC_ALGORITHM: - enc_alg = parse_algorithmIdentifier(object, level, NULL); - break; - case PKCS7_ENCRYPTED_DIGEST: - encrypted_digest = object; - } - objectID++; - } - - /* check the signature only if a cacert is available */ - if (cacert != NULL) - { - if (signerInfos == 0) + u_char buf[BUF_LEN]; + asn1_parser_t *parser; + chunk_t object; + int digest_alg = OID_UNKNOWN; + int enc_alg = OID_UNKNOWN; + int signerInfos = 0; + int objectID; + bool success = FALSE; + + contentInfo_t cInfo = empty_contentInfo; + chunk_t encrypted_digest = chunk_empty; + + if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) { - plog("no signerInfo object found"); - return FALSE; + return FALSE; } - else if (signerInfos > 1) + if (cInfo.type != OID_PKCS7_SIGNED_DATA) { - plog("more than one signerInfo object found"); - return FALSE; + DBG1("pkcs7 content type is not signedData"); + return FALSE; } - if (attributes->ptr == NULL) + + parser = asn1_parser_create(signedDataObjects, blob); + parser->set_top_level(parser, 2); + + while (parser->iterate(parser, &objectID, &object)) { - plog("no authenticatedAttributes object found"); - return FALSE; + u_int level = parser->get_level(parser); + + switch (objectID) + { + 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: + if (cert != NULL) + { + chunk_t cert_blob = chunk_clone(object); + x509cert_t *newcert = malloc_thing(x509cert_t); + + *newcert = empty_x509cert; + + DBG2(" parsing pkcs7-wrapped certificate"); + if (parse_x509cert(cert_blob, level+1, newcert)) + { + newcert->next = *cert; + *cert = newcert; + } + else + { + free_x509cert(newcert); + } + } + break; + case PKCS7_SIGNER_INFO: + signerInfos++; + DBG2(" signer #%d", signerInfos); + break; + case PKCS7_SIGNED_ISSUER: + dntoa(buf, BUF_LEN, object); + DBG2(" '%s'",buf); + 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; + } } - if (!check_signature(*attributes, encrypted_digest, digest_alg - , enc_alg, cacert)) + success = parser->success(parser); + parser->destroy(parser); + if (!success) { - plog("invalid signature"); - return FALSE; + return FALSE; } - else + + /* check the signature only if a cacert is available */ + if (cacert != NULL) { - DBG(DBG_CONTROL, - DBG_log("signature is valid") - ) + public_key_t *key = cacert->public_key; + signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + + if (signerInfos == 0) + { + DBG1("no signerInfo object found"); + return FALSE; + } + else if (signerInfos > 1) + { + DBG1("more than one signerInfo object found"); + return FALSE; + } + if (attributes->ptr == NULL) + { + DBG1("no authenticatedAttributes object found"); + return FALSE; + } + if (enc_alg != OID_RSA_ENCRYPTION) + { + DBG1("only RSA digest encryption supported"); + return FALSE; + } + + /* determine signature scheme */ + scheme = signature_scheme_from_oid(digest_alg); + + if (scheme == SIGN_UNKNOWN) + { + return FALSE; + } + if (key->verify(key, scheme, *attributes, encrypted_digest)) + { + DBG2("signature is valid"); + } + else + { + DBG1("invalid signature"); + return FALSE; + } } - } - return TRUE; + return TRUE; } -/* +/** * Parse a PKCS#7 envelopedData object */ -bool -pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data -, chunk_t serialNumber, const RSA_private_key_t *key) +bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, + chunk_t serialNumber, + private_key_t *key) { - asn1_ctx_t ctx; - chunk_t object; - chunk_t iv = empty_chunk; - chunk_t symmetric_key = empty_chunk; - chunk_t encrypted_content = empty_chunk; - - u_char buf[BUF_LEN]; - u_int level; - u_int total_keys = 3; - int enc_alg = OID_UNKNOWN; - int content_enc_alg = OID_UNKNOWN; - int objectID = 0; - - contentInfo_t cInfo = empty_contentInfo; - *data = empty_chunk; - - if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) - goto failed; - - if (cInfo.type != OID_PKCS7_ENVELOPED_DATA) - { - plog("pkcs7 content type is not envelopedData"); - return FALSE; - } - - asn1_init(&ctx, cInfo.content, 2, FALSE, DBG_RAW); - - while (objectID < PKCS7_ENVELOPED_ROOF) - { - if (!extract_object(envelopedDataObjects, &objectID, &object, &level, &ctx)) - goto failed; - - switch (objectID) - { - case PKCS7_ENVELOPED_VERSION: - if (*object.ptr != 0) + 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; + + u_char buf[BUF_LEN]; + int enc_alg = OID_UNKNOWN; + int content_enc_alg = OID_UNKNOWN; + int objectID; + bool success = FALSE; + + contentInfo_t cInfo = empty_contentInfo; + *data = chunk_empty; + + if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) { - plog("envelopedData version is not 0"); - goto failed; - } - break; - case PKCS7_RECIPIENT_INFO_VERSION: - if (*object.ptr != 0) - { - plog("recipient info version is not 0"); - goto failed; - } - break; - case PKCS7_ISSUER: - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'", buf) - ) - break; - case PKCS7_SERIAL_NUMBER: - if (!same_chunk(serialNumber, object)) - { - plog("serial numbers do not match"); - goto failed; - } - break; - case PKCS7_ENCRYPTION_ALG: - enc_alg = parse_algorithmIdentifier(object, level, NULL); - if (enc_alg != OID_RSA_ENCRYPTION) - { - plog("only rsa encryption supported"); - goto failed; - } - break; - case PKCS7_ENCRYPTED_KEY: - if (!RSA_decrypt(key, object, &symmetric_key)) - { - plog("symmetric key could not be decrypted with rsa"); - goto failed; - } - DBG(DBG_PRIVATE, - DBG_dump_chunk("symmetric key :", symmetric_key) - ) - break; - case PKCS7_CONTENT_TYPE: - if (known_oid(object) != OID_PKCS7_DATA) - { - plog("encrypted content not of type pkcs7 data"); - goto failed; - } - break; - case PKCS7_CONTENT_ENC_ALGORITHM: - content_enc_alg = parse_algorithmIdentifier(object, level, &iv); - - switch (content_enc_alg) - { - case OID_DES_CBC: - total_keys = 1; - break; - case OID_3DES_EDE_CBC: - total_keys = 3; - break; - default: - plog("Only DES and 3DES supported for symmetric encryption"); - goto failed; - } - if (symmetric_key.len != (total_keys * DES_CBC_BLOCK_SIZE)) - { - plog("key length is not %d",(total_keys * DES_CBC_BLOCK_SIZE)); - goto failed; - } - if (!parse_asn1_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV")) - { - plog("IV could not be parsed"); goto failed; - } - if (iv.len != DES_CBC_BLOCK_SIZE) - { - plog("IV has wrong length"); + } + if (cInfo.type != OID_PKCS7_ENVELOPED_DATA) + { + DBG1("pkcs7 content type is not envelopedData"); goto failed; - } - break; - case PKCS7_ENCRYPTED_CONTENT: - encrypted_content = object; - break; } - objectID++; - } - /* decrypt the content */ - { - u_int i; - des_cblock des_key[3], des_iv; - des_key_schedule key_s[3]; + parser = asn1_parser_create(envelopedDataObjects, cInfo.content); + parser->set_top_level(parser, 2); - memcpy((char *)des_key, symmetric_key.ptr, symmetric_key.len); - memcpy((char *)des_iv, iv.ptr, iv.len); - - for (i = 0; i < total_keys; i++) + while (parser->iterate(parser, &objectID, &object)) { - if (des_set_key(&des_key[i], key_s[i])) - { - plog("des key schedule failed"); - goto failed; - } - } + u_int level = parser->get_level(parser); - data->len = encrypted_content.len; - data->ptr = alloc_bytes(data->len, "decrypted data"); + switch (objectID) + { + case PKCS7_ENVELOPED_VERSION: + if (*object.ptr != 0) + { + DBG1("envelopedData version is not 0"); + goto end; + } + break; + case PKCS7_RECIPIENT_INFO_VERSION: + if (*object.ptr != 0) + { + DBG1("recipient info version is not 0"); + goto end; + } + break; + case PKCS7_ISSUER: + dntoa(buf, BUF_LEN, object); + DBG2(" '%s'", buf); + break; + case PKCS7_SERIAL_NUMBER: + if (!chunk_equals(serialNumber, object)) + { + DBG1("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("only rsa encryption supported"); + goto end; + } + break; + case PKCS7_ENCRYPTED_KEY: + if (!key->decrypt(key, object, &symmetric_key)) + { + DBG1("symmetric key could not be decrypted with rsa"); + goto end; + } + DBG4("symmetric key %B", &symmetric_key); + break; + case PKCS7_CONTENT_TYPE: + if (asn1_known_oid(object) != OID_PKCS7_DATA) + { + DBG1("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("unknown content encryption algorithm"); + goto end; + } + if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV")) + { + DBG1("IV could not be parsed"); + goto end; + } + break; + case PKCS7_ENCRYPTED_CONTENT: + encrypted_content = object; + break; + } + } + success = parser->success(parser); - switch (content_enc_alg) +end: + parser->destroy(parser); + if (!success) { - case OID_DES_CBC: - des_cbc_encrypt((des_cblock*)encrypted_content.ptr - , (des_cblock*)data->ptr, data->len - , key_s[0], &des_iv, DES_DECRYPT); - break; - case OID_3DES_EDE_CBC: - des_ede3_cbc_encrypt( (des_cblock*)encrypted_content.ptr - , (des_cblock*)data->ptr, data->len - , key_s[0], key_s[1], key_s[2] - , &des_iv, DES_DECRYPT); + goto failed; } - DBG(DBG_PRIVATE, - DBG_dump_chunk("decrypted content with padding:\n", *data) - ) - } - - /* remove the padding */ - { - u_char *pos = data->ptr + data->len - 1; - u_char pattern = *pos; - size_t padding = pattern; - - if (padding > data->len) + success = FALSE; + + /* decrypt the content */ { - plog("padding greater than data length"); - goto failed; + 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("unsupported content encryption algorithm"); + goto failed; + } + crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size); + if (crypter == NULL) + { + DBG1("crypter %N not available", encryption_algorithm_names, alg); + goto failed; + } + if (symmetric_key.len != crypter->get_key_size(crypter)) + { + DBG1("symmetric key length %d is wrong", symmetric_key.len); + goto failed; + } + if (iv.len != crypter->get_block_size(crypter)) + { + DBG1("IV length %d is wrong", iv.len); + goto failed; + } + crypter->set_key(crypter, symmetric_key); + crypter->decrypt(crypter, encrypted_content, iv, data); + DBG4("decrypted content with padding: %B", data); } - data->len -= padding; - while (padding-- > 0) + /* remove the padding */ { - if (*pos-- != pattern) - { - plog("wrong padding pattern"); - goto failed; - } + u_char *pos = data->ptr + data->len - 1; + u_char pattern = *pos; + size_t padding = pattern; + + if (padding > data->len) + { + DBG1("padding greater than data length"); + goto failed; + } + data->len -= padding; + + while (padding-- > 0) + { + if (*pos-- != pattern) + { + DBG1("wrong padding pattern"); + goto failed; + } + } } - } - freeanychunk(symmetric_key); - return TRUE; + success = TRUE; failed: - freeanychunk(symmetric_key); - pfreeany(data->ptr); - return FALSE; + DESTROY_IF(crypter); + chunk_clear(&symmetric_key); + if (!success) + { + free(data->ptr); + } + return success; } /** @@ -577,12 +576,11 @@ failed: * * @return ASN.1 encoded contentType attribute */ -chunk_t -pkcs7_contentType_attribute(void) +chunk_t pkcs7_contentType_attribute(void) { - return asn1_wrap(ASN1_SEQUENCE, "cm" - , ASN1_contentType_oid - , asn1_simple_object(ASN1_SET, ASN1_pkcs7_data_oid)); + return asn1_wrap(ASN1_SEQUENCE, "cm" + , ASN1_contentType_oid + , asn1_simple_object(ASN1_SET, ASN1_pkcs7_data_oid)); } /** @@ -594,269 +592,228 @@ pkcs7_contentType_attribute(void) * @return ASN.1 encoded messageDigest attribute * */ -chunk_t -pkcs7_messageDigest_attribute(chunk_t content, int digest_alg) +chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg) { - u_char digest_buf[MAX_DIGEST_LEN]; - chunk_t digest = { digest_buf, MAX_DIGEST_LEN }; - - compute_digest(content, digest_alg, &digest); - - return asn1_wrap(ASN1_SEQUENCE, "cm" - , ASN1_messageDigest_oid - , asn1_wrap(ASN1_SET, "m" - , asn1_simple_object(ASN1_OCTET_STRING, digest) - ) - ); + 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, "cm", + ASN1_messageDigest_oid, + 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) +static chunk_t pkcs7_build_contentInfo(contentInfo_t *cInfo) { - chunk_t content_type; - - /* select DER-encoded OID for pkcs7 contentInfo type */ - switch(cInfo->type) - { - case OID_PKCS7_DATA: - content_type = ASN1_pkcs7_data_oid; - break; - case OID_PKCS7_SIGNED_DATA: - content_type = ASN1_pkcs7_signed_data_oid; - break; - case OID_PKCS7_ENVELOPED_DATA: - content_type = ASN1_pkcs7_enveloped_data_oid; - break; - case OID_PKCS7_SIGNED_ENVELOPED_DATA: - content_type = ASN1_pkcs7_signed_enveloped_data_oid; - break; - case OID_PKCS7_DIGESTED_DATA: - content_type = ASN1_pkcs7_digested_data_oid; - break; - case OID_PKCS7_ENCRYPTED_DATA: - content_type = ASN1_pkcs7_encrypted_data_oid; - break; - case OID_UNKNOWN: - default: - fprintf(stderr, "invalid pkcs7 contentInfo type"); - return empty_chunk; - } - - return (cInfo->content.ptr == NULL) - ? asn1_simple_object(ASN1_SEQUENCE, content_type) - : asn1_wrap(ASN1_SEQUENCE, "cm" - , content_type - , asn1_simple_object(ASN1_CONTEXT_C_0, cInfo->content) - ); + chunk_t content_type; + + /* select DER-encoded OID for pkcs7 contentInfo type */ + switch(cInfo->type) + { + case OID_PKCS7_DATA: + content_type = ASN1_pkcs7_data_oid; + break; + case OID_PKCS7_SIGNED_DATA: + content_type = ASN1_pkcs7_signed_data_oid; + break; + case OID_PKCS7_ENVELOPED_DATA: + content_type = ASN1_pkcs7_enveloped_data_oid; + break; + case OID_PKCS7_SIGNED_ENVELOPED_DATA: + content_type = ASN1_pkcs7_signed_enveloped_data_oid; + break; + case OID_PKCS7_DIGESTED_DATA: + content_type = ASN1_pkcs7_digested_data_oid; + break; + case OID_PKCS7_ENCRYPTED_DATA: + content_type = ASN1_pkcs7_encrypted_data_oid; + break; + case OID_UNKNOWN: + default: + DBG1("invalid pkcs7 contentInfo type"); + return chunk_empty; + } + + return (cInfo->content.ptr == NULL) + ? asn1_simple_object(ASN1_SEQUENCE, content_type) + : asn1_wrap(ASN1_SEQUENCE, "cm" + , content_type + , asn1_simple_object(ASN1_CONTEXT_C_0, cInfo->content) + ); } -/* +/** * build issuerAndSerialNumber object */ -chunk_t -pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert) +chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert) { - return asn1_wrap(ASN1_SEQUENCE, "cm" - , cert->issuer - , asn1_simple_object(ASN1_INTEGER, cert->serialNumber)); + return asn1_wrap(ASN1_SEQUENCE, "cm" + , cert->issuer + , asn1_integer("c", cert->serialNumber)); } -/* +/** * create a signed pkcs7 contentInfo object */ -chunk_t -pkcs7_build_signedData(chunk_t data, chunk_t attributes, const x509cert_t *cert -, int digest_alg, const RSA_private_key_t *key) +chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, + const x509cert_t *cert, int digest_alg, + private_key_t *key) { - contentInfo_t pkcs7Data, signedData; - chunk_t authenticatedAttributes, encryptedDigest, signerInfo, cInfo; - - chunk_t digestAlgorithm = asn1_algorithmIdentifier(digest_alg); - - if (attributes.ptr != NULL) - { - encryptedDigest = pkcs1_build_signature(attributes, digest_alg - , key, FALSE); - clonetochunk(authenticatedAttributes, attributes.ptr, attributes.len - , "authenticatedAttributes"); - *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; - } - else - { - encryptedDigest = (data.ptr == NULL)? empty_chunk - : pkcs1_build_signature(data, digest_alg, key, FALSE); - authenticatedAttributes = empty_chunk; - } - - signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmcmcm" - , ASN1_INTEGER_1 - , pkcs7_build_issuerAndSerialNumber(cert) - , digestAlgorithm - , authenticatedAttributes - , ASN1_rsaEncryption_id - , encryptedDigest); - - pkcs7Data.type = OID_PKCS7_DATA; - pkcs7Data.content = (data.ptr == NULL)? empty_chunk - : asn1_simple_object(ASN1_OCTET_STRING, data); - - signedData.type = OID_PKCS7_SIGNED_DATA; - signedData.content = asn1_wrap(ASN1_SEQUENCE, "cmmmm" - , ASN1_INTEGER_1 - , asn1_simple_object(ASN1_SET, digestAlgorithm) - , pkcs7_build_contentInfo(&pkcs7Data) - , asn1_simple_object(ASN1_CONTEXT_C_0, cert->certificate) - , asn1_wrap(ASN1_SET, "m", signerInfo)); - - cInfo = pkcs7_build_contentInfo(&signedData); - DBG(DBG_RAW, - DBG_dump_chunk("signedData:\n", cInfo) - ) - - freeanychunk(pkcs7Data.content); - freeanychunk(signedData.content); - return cInfo; + contentInfo_t pkcs7Data, signedData; + chunk_t authenticatedAttributes, encryptedDigest, signerInfo, cInfo; + + chunk_t digestAlgorithm = asn1_algorithmIdentifier(digest_alg); + + if (attributes.ptr != NULL) + { + encryptedDigest = x509_build_signature(attributes, digest_alg, key, + FALSE); + authenticatedAttributes = chunk_clone(attributes); + *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; + } + else + { + encryptedDigest = (data.ptr == NULL)? chunk_empty + : x509_build_signature(data, digest_alg, key, FALSE); + authenticatedAttributes = chunk_empty; + } + + signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmcmcm" + , ASN1_INTEGER_1 + , pkcs7_build_issuerAndSerialNumber(cert) + , digestAlgorithm + , 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); + + signedData.type = OID_PKCS7_SIGNED_DATA; + signedData.content = asn1_wrap(ASN1_SEQUENCE, "cmmmm" + , ASN1_INTEGER_1 + , asn1_simple_object(ASN1_SET, digestAlgorithm) + , pkcs7_build_contentInfo(&pkcs7Data) + , asn1_simple_object(ASN1_CONTEXT_C_0, cert->certificate) + , asn1_wrap(ASN1_SET, "m", signerInfo)); + + cInfo = pkcs7_build_contentInfo(&signedData); + DBG3("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, const x509cert_t *cert, int cipher) +chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_alg) { - bool des_check_key_save; - des_key_schedule ks[3]; - des_cblock key[3], des_iv, des_iv_buf; - - chunk_t iv = { (u_char *)des_iv_buf, DES_CBC_BLOCK_SIZE }; - chunk_t out; - chunk_t cipher_oid; - - u_int total_keys, i; - size_t padding = pad_up(data.len, DES_CBC_BLOCK_SIZE); - - RSA_public_key_t public_key; - - init_RSA_public_key(&public_key, cert->publicExponent - , cert->modulus); - - if (padding == 0) - padding += DES_CBC_BLOCK_SIZE; - - out.len = data.len + padding; - out.ptr = alloc_bytes(out.len, "DES-encrypted output"); - - DBG(DBG_CONTROL, - DBG_log("padding %d bytes of data to multiple DES block size of %d bytes" - , (int)data.len, (int)out.len) - ) - - /* copy data */ - memcpy(out.ptr, data.ptr, data.len); - /* append padding */ - memset(out.ptr + data.len, padding, padding); - - DBG(DBG_RAW, - DBG_dump_chunk("Padded unencrypted data:\n", out) - ) - - /* select OID and keylength for specified cipher */ - switch (cipher) - { - case OID_DES_CBC: - total_keys = 1; - cipher_oid = ASN1_des_cbc_oid; - break; - case OID_3DES_EDE_CBC: - default: - total_keys = 3; - cipher_oid = ASN1_3des_ede_cbc_oid; - } - DBG(DBG_CONTROLMORE, - DBG_log("pkcs7 encryption cipher: %s", oid_names[cipher].name) - ) - - /* generate a strong random key for DES/3DES */ - des_check_key_save = des_check_key; - des_check_key = TRUE; - for (i = 0; i < total_keys;i++) - { - for (;;) + 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) { - get_rnd_bytes((char*)key[i], DES_CBC_BLOCK_SIZE); - des_set_odd_parity(&key[i]); - if (!des_set_key(&key[i], ks[i])) - break; - plog("weak DES key discarded - we try again"); + DBG1("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("symmetric encryption key %B", &symmetricKey); + rng->destroy(rng); + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + rng->allocate_bytes(rng, crypter->get_block_size(crypter), &iv); + DBG4("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("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("padded unencrypted data %B", &in); + + /* symmetric encryption of data object */ + crypter->set_key(crypter, symmetricKey); + crypter->encrypt(crypter, in, iv, &out); + crypter->destroy(crypter); + DBG3("encrypted data %B", &out); + + cert->public_key->encrypt(cert->public_key, symmetricKey, &protectedKey); + + /* 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, "cmm" + , ASN1_pkcs7_data_oid + , 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, "cmcm" + , 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("envelopedData %B", &cInfo); + + free(envelopedData.content.ptr); + free(symmetricKey.ptr); + free(in.ptr); + free(iv.ptr); + return cInfo; } - DBG(DBG_PRIVATE, - DBG_dump("DES key:", key[i], 8) - ) - } - des_check_key = des_check_key_save; - - /* generate an iv for DES/3DES CBC */ - get_rnd_bytes(des_iv, DES_CBC_BLOCK_SIZE); - memcpy(iv.ptr, des_iv, DES_CBC_BLOCK_SIZE); - DBG(DBG_RAW, - DBG_dump_chunk("DES IV :", iv) - ) - - /* encryption using specified cipher */ - switch (cipher) - { - case OID_DES_CBC: - des_cbc_encrypt((des_cblock*)out.ptr, (des_cblock*)out.ptr, out.len - , ks[0], &des_iv, DES_ENCRYPT); - break; - case OID_3DES_EDE_CBC: - default: - des_ede3_cbc_encrypt((des_cblock*)out.ptr, (des_cblock*)out.ptr, out.len - , ks[0], ks[1], ks[2], &des_iv, DES_ENCRYPT); - } - DBG(DBG_RAW, - DBG_dump_chunk("Encrypted data:\n", out)); - - /* build pkcs7 enveloped data object */ - { - chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "cm" - , cipher_oid - , asn1_simple_object(ASN1_OCTET_STRING, iv)); - - chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "cmm" - , ASN1_pkcs7_data_oid - , contentEncryptionAlgorithm - , asn1_wrap(ASN1_CONTEXT_S_0, "m", out)); - - chunk_t plainKey = { (u_char *)key, DES_CBC_BLOCK_SIZE * total_keys }; - - chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m" - , RSA_encrypt(&public_key, plainKey)); - - chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmcm" - , ASN1_INTEGER_0 - , pkcs7_build_issuerAndSerialNumber(cert) - , ASN1_rsaEncryption_id - , 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); - DBG(DBG_RAW, - DBG_dump_chunk("envelopedData:\n", cInfo) - ) - - free_RSA_public_content(&public_key); - freeanychunk(envelopedData.content); - return cInfo; - } } diff --git a/src/pluto/pkcs7.h b/src/pluto/pkcs7.h index a577f8022..028822dfe 100644 --- a/src/pluto/pkcs7.h +++ b/src/pluto/pkcs7.h @@ -1,6 +1,7 @@ /* Support of PKCS#7 data structures * Copyright (C) 2005 Jan Hutter, Martin Willi - * Copyright (C) 2002-2005 Andreas Steffen + * Copyright (C) 2002-2009 Andreas Steffen + * * Hochschule fuer Technik Rapperswil, Switzerland * * This program is free software; you can redistribute it and/or modify it @@ -12,15 +13,14 @@ * 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. - * - * RCSID $Id: pkcs7.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _PKCS7_H #define _PKCS7_H +#include <crypto/crypters/crypter.h> +#include <credentials/keys/private_key.h> #include "defs.h" -#include "pkcs1.h" #include "x509.h" /* Access structure for a PKCS#7 ContentInfo object */ @@ -28,24 +28,24 @@ typedef struct contentInfo contentInfo_t; struct contentInfo { - int type; - chunk_t content; + 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 - , x509cert_t **cert, chunk_t *attributes, const x509cert_t *cacert); -extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data - , chunk_t serialNumber, const RSA_private_key_t *key); +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, + x509cert_t **cert, chunk_t *attributes, const x509cert_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(const x509cert_t *cert); -extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes - ,const x509cert_t *cert, int digest_alg, const RSA_private_key_t *key); -extern chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert - , int cipher); +extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, + const x509cert_t *cert, int digest_alg, private_key_t *key); +extern chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, + int enc_alg); #endif /* _PKCS7_H */ diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c index a39934f1f..39367cafa 100644 --- a/src/pluto/plutomain.c +++ b/src/pluto/plutomain.c @@ -1,6 +1,7 @@ /* Pluto main program * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. + * 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 @@ -11,8 +12,6 @@ * 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. - * - * RCSID $Id: plutomain.c 4313 2008-08-29 09:24:14Z martin $ */ #include <stdio.h> @@ -27,7 +26,7 @@ #include <fcntl.h> #include <getopt.h> #include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ +#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ #include <sys/queue.h> #include <sys/prctl.h> #include <pwd.h> @@ -39,6 +38,16 @@ #include <freeswan.h> +#include <library.h> +#include <debug.h> +#include <utils/enumerator.h> +#include <utils/optionsfrom.h> + +#ifdef INTEGRITY_TEST +#include <fips/fips.h> +#include <fips/fips_signature.h> +#endif /* INTEGRITY_TEST */ + #include <pfkeyv2.h> #include <pfkey.h> @@ -51,91 +60,88 @@ #include "connections.h" #include "foodgroups.h" #include "packet.h" -#include "demux.h" /* needs 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 "rnd.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 "ipsec_doi.h" /* needs demux.h and state.h */ #include "ocsp.h" #include "crl.h" #include "fetch.h" #include "xauth.h" -#include "sha1.h" -#include "md5.h" -#include "crypto.h" /* requires sha1.h and md5.h */ +#include "crypto.h" #include "nat_traversal.h" #include "virtual.h" +#include "timer.h" +#include "vendor.h" -static void -usage(const char *mess) +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]" - " [--noklips]" - " [--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>]" + if (mess != NULL && *mess != '\0') + fprintf(stderr, "%s\n", mess); + fprintf(stderr + , "Usage: pluto" + " [--help]" + " [--version]" + " [--optionsfrom <filename>]" + " \\\n\t" + "[--nofork]" + " [--stderrlog]" + " [--noklips]" + " [--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-klips]" - " [--debug-dns]" - " \\\n\t" - "[--debug-oppo]" - " [--debug-controlmore]" - " [--debug-private]" + " \\\n\t" + "[--debug-none]" + " [--debug-all]" + " \\\n\t" + "[--debug-raw]" + " [--debug-crypt]" + " [--debug-parsing]" + " [--debug-emitting]" + " \\\n\t" + "[--debug-control]" + " [--debug-lifecycle]" + " [--debug-klips]" + " [--debug-dns]" + " \\\n\t" + "[--debug-oppo]" + " [--debug-controlmore]" + " [--debug-private]" + " [--debug-natt]" #endif - " [ --debug-natt]" - " \\\n\t" - "[--nat_traversal] [--keep_alive <delay_sec>]" - " \\\n\t" - "[--force_keepalive] [--disable_port_floating]" - " \\\n\t" - "[--virtual_private <network_list>]" - "\n" - "strongSwan %s\n" - , ipsec_version_code()); - exit_pluto(mess == NULL? 0 : 1); + " \\\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); } @@ -150,53 +156,51 @@ static char pluto_lock[sizeof(ctl_addr.sun_path)] = DEFAULT_CTLBASE LOCK_SUFFIX; static bool pluto_lock_created = FALSE; /* create lockfile, or die in the attempt */ -static int -create_lock(void) +static int create_lock(void) { - int fd = open(pluto_lock, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC - , S_IRUSR | S_IRGRP | S_IROTH); + int fd = open(pluto_lock, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC + , S_IRUSR | S_IRGRP | S_IROTH); - if (fd < 0) - { - if (errno == EEXIST) + if (fd < 0) { - fprintf(stderr, "pluto: lock file \"%s\" already exists\n" - , pluto_lock); - exit_pluto(10); + if (errno == EEXIST) + { + fprintf(stderr, "pluto: lock file \"%s\" already exists\n" + , pluto_lock); + exit_pluto(10); + } + else + { + fprintf(stderr + , "pluto: unable to create lock file \"%s\" (%d %s)\n" + , pluto_lock, errno, strerror(errno)); + exit_pluto(1); + } } - else - { - fprintf(stderr - , "pluto: unable to create lock file \"%s\" (%d %s)\n" - , pluto_lock, errno, strerror(errno)); - exit_pluto(1); - } - } - pluto_lock_created = TRUE; - return fd; + pluto_lock_created = TRUE; + return fd; } -static bool -fill_lock(int lockfd, pid_t pid) +static bool fill_lock(int lockfd, pid_t pid) { - char buf[30]; /* holds "<pid>\n" */ - int len = snprintf(buf, sizeof(buf), "%u\n", (unsigned int) pid); - bool ok = len > 0 && write(lockfd, buf, len) == len; + char buf[30]; /* holds "<pid>\n" */ + int len = snprintf(buf, sizeof(buf), "%u\n", (unsigned int) pid); + bool ok = len > 0 && write(lockfd, buf, len) == len; - close(lockfd); - return ok; + close(lockfd); + return ok; } -static void -delete_lock(void) +static void delete_lock(void) { - if (pluto_lock_created) - { - delete_ctl_socket(); - unlink(pluto_lock); /* is noting failure useful? */ - } + if (pluto_lock_created) + { + delete_ctl_socket(); + unlink(pluto_lock); /* is noting failure useful? */ + } } + /* by default pluto sends certificate requests to its peers */ bool no_cr_send = FALSE; @@ -223,459 +227,504 @@ bool pkcs11_proxy = FALSE; */ static const char *pkcs11_init_args = NULL; -int -main(int argc, char **argv) +/* options read by optionsfrom */ +options_t *options; + +/** + * Log loaded plugins + */ +static void print_plugins() +{ + char buf[BUF_LEN], *plugin; + int len = 0; + enumerator_t *enumerator; + + buf[0] = '\0'; + enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); + while (len < BUF_LEN && enumerator->enumerate(enumerator, &plugin)) + { + len += snprintf(&buf[len], BUF_LEN-len, "%s ", plugin); + } + enumerator->destroy(enumerator); + DBG1("loaded plugins: %s", buf); +} + +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; - int lockfd; + 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; + int lockfd; #ifdef CAPABILITIES - cap_t caps; - int keep[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE }; + cap_t caps; + int keep[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE }; #endif /* CAPABILITIES */ - /* 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' }, - { "noklips", no_argument, NULL, 'n' }, - { "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' }, + /* initialize library and optionsfrom */ + library_init(STRONGSWAN_CONF); + 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' }, + { "noklips", no_argument, NULL, 'n' }, + { "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' }, #ifdef USE_LWRES - { "lwdnsq", required_argument, NULL, 'a' }, + { "lwdnsq", required_argument, NULL, 'a' }, #else /* !USE_LWRES */ - { "adns", required_argument, NULL, 'a' }, + { "adns", required_argument, NULL, 'a' }, #endif /* !USE_LWRES */ - { "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' }, + { "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_KLIPS + 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 }, + { "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_KLIPS + 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("%s%s\n", ipsec_version_string(), - compile_time_interop_options); - for (; *sp != NULL; sp++) - puts(*sp); - } - exit_pluto(0); - break; /* not actually reached */ - - case '+': /* --optionsfrom <filename> */ - optionsfrom(optarg, &argc, &argv, optind, stderr); - /* does not return on error */ - continue; - - case 'd': /* --nofork*/ - fork_desired = FALSE; - continue; - - case 'e': /* --stderrlog */ - log_to_stderr_desired = TRUE; - continue; - - case 'n': /* --noklips */ - no_klips = 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; - - case 'a': /* --adns <pathname> */ - pluto_adns_option = optarg; - continue; - - 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; + { 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 'n': /* --noklips */ + no_klips = 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; + + case 'a': /* --adns <pathname> */ + pluto_adns_option = optarg; + continue; + + 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 'N': /* --debug-none */ + base_debugging = DBG_NONE; + continue; - case 'A': /* --debug-all */ - base_debugging = DBG_ALL; - 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: + 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 + if (c >= DBG_OFFSET) + { + base_debugging |= c - DBG_OFFSET; + continue; + } +# undef DBG_OFFSET #endif - bad_case(c); + bad_case(c); + } + break; } - break; - } - if (optind != argc) - usage("unexpected argument"); - reset_debugging(); - lockfd = create_lock(); + if (optind != argc) + usage("unexpected argument"); + reset_debugging(); + lockfd = create_lock(); - /* select between logging methods */ + /* select between logging methods */ - if (log_to_stderr_desired) - log_to_syslog = FALSE; - else - log_to_stderr = FALSE; + if (log_to_stderr_desired) + { + log_to_syslog = FALSE; + } + else + { + log_to_stderr = FALSE; + } - /* set the logging function of pfkey debugging */ + /* set the logging function of pfkey debugging */ #ifdef DEBUG - pfkey_debug_func = DBG_log; + pfkey_debug_func = DBG_log; #else - pfkey_debug_func = NULL; + 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) + /* 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. + */ { - fprintf(stderr, "pluto: %s", ugh); - exit_pluto(1); + err_t ugh = init_ctl_socket(); + + if (ugh != NULL) + { + fprintf(stderr, "pluto: %s", ugh); + exit_pluto(1); + } } - } - /* If not suppressed, do daemon fork */ + /* If not suppressed, do daemon fork */ - if (fork_desired) - { + if (fork_desired) { - pid_t pid = fork(); + { + 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, after filling PID into lock file. + * must not use exit_pluto: lock would be removed! + */ + exit(fill_lock(lockfd, pid)? 0 : 1); + } + } + + 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 */ + (void) fill_lock(lockfd, getpid()); + fprintf(stdout, "Pluto initialized\n"); + fflush(stdout); + } - if (pid < 0) - { - int e = errno; + /* Close everything but ctl_fd and (if needed) stderr. + * There is some danger that a library that we don't know + * about is using some fd that we don't know about. + * I guess we'll soon find out. + */ + { + int i; + + for (i = getdtablesize() - 1; i >= 0; i--) /* Bad hack */ + { + if ((!log_to_stderr || i != 2) && i != ctl_fd) + close(i); + } + + /* make sure that stdin, stdout, stderr are reserved */ + if (open("/dev/null", O_RDONLY) != 0) + abort(); + if (dup2(0, 1) != 1) + abort(); + if (!log_to_stderr && dup2(0, 2) != 2) + abort(); + } - fprintf(stderr, "pluto: fork failed (%d %s)\n", - errno, strerror(e)); - exit_pluto(1); - } + init_constants(); + init_log("pluto"); - if (pid != 0) - { - /* parent: die, after filling PID into lock file. - * must not use exit_pluto: lock would be removed! - */ - exit(fill_lock(lockfd, pid)? 0 : 1); - } - } + /* 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 (setsid() < 0) - { - int e = errno; + /* load plugins, further infrastructure may need it */ + lib->plugins->load(lib->plugins, IPSEC_PLUGINDIR, + lib->settings->get_str(lib->settings, "pluto.load", PLUGINS)); + print_plugins(); - fprintf(stderr, "setsid() failed in main(). Errno %d: %s\n", - errno, strerror(e)); - exit_pluto(1); +#ifdef INTEGRITY_TEST + DBG1("integrity test of libstrongswan code"); + if (fips_verify_hmac_signature(hmac_key, hmac_signature)) + { + DBG1(" integrity test passed"); } - } - else - { - /* no daemon fork: we have to fill in lock file */ - (void) fill_lock(lockfd, getpid()); - fprintf(stdout, "Pluto initialized\n"); - fflush(stdout); - } - - /* Close everything but ctl_fd and (if needed) stderr. - * There is some danger that a library that we don't know - * about is using some fd that we don't know about. - * I guess we'll soon find out. - */ - { - int i; - - for (i = getdtablesize() - 1; i >= 0; i--) /* Bad hack */ + else { - if ((!log_to_stderr || i != 2) && i != ctl_fd) - close(i); + DBG1(" integrity test failed"); + abort(); } - - /* make sure that stdin, stdout, stderr are reserved */ - if (open("/dev/null", O_RDONLY) != 0) - abort(); - if (dup2(0, 1) != 1) - abort(); - if (!log_to_stderr && dup2(0, 2) != 2) - abort(); - } - - 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 Pluto (strongSwan Version %s%s)" - , ipsec_version_code() - , compile_time_interop_options); - - 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); /* load and initialize PKCS #11 module */ - xauth_init(); /* load and initialize XAUTH module */ - init_rnd_pool(); - init_secret(); - init_states(); - init_crypto(); - init_demux(); - init_kernel(); - init_adns(); - init_id(); - init_fetch(); - - /* drop unneeded capabilities and change UID/GID */ - - prctl(PR_SET_KEEPCAPS, 1); - +#endif /* INTEGRITY_TEST */ + + 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); + xauth_init(); + init_secret(); + init_states(); + init_crypto(); + init_demux(); + init_kernel(); + init_adns(); + init_id(); + init_fetch(); + + /* drop unneeded capabilities and change UID/GID */ + prctl(PR_SET_KEEPCAPS, 1); + #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(); + 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(); - } - } + 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 CAPABILITIES - caps = cap_init(); - cap_set_flag(caps, CAP_EFFECTIVE, 2, keep, CAP_SET); - cap_set_flag(caps, CAP_INHERITABLE, 2, keep, CAP_SET); - cap_set_flag(caps, CAP_PERMITTED, 2, keep, CAP_SET); - if (cap_set_proc(caps) != 0) - { - plog("unable to drop daemon capabilities"); - abort(); - } - cap_free(caps); + caps = cap_init(); + cap_set_flag(caps, CAP_EFFECTIVE, 2, keep, CAP_SET); + cap_set_flag(caps, CAP_INHERITABLE, 2, keep, CAP_SET); + cap_set_flag(caps, CAP_PERMITTED, 2, keep, CAP_SET); + if (cap_set_proc(caps) != 0) + { + plog("unable to drop daemon capabilities"); + abort(); + } + cap_free(caps); #endif /* CAPABILITIES */ - /* loading X.509 CA certificates */ - load_authcerts("CA cert", CA_CERT_PATH, AUTH_CA); - /* loading X.509 AA certificates */ - load_authcerts("AA cert", AA_CERT_PATH, AUTH_AA); - /* loading X.509 OCSP certificates */ - load_authcerts("OCSP cert", OCSP_CERT_PATH, AUTH_OCSP); - /* loading X.509 CRLs */ - load_crls(); - /* loading attribute certificates (experimental) */ - load_acerts(); - - daily_log_event(); - call_server(); - return -1; /* Shouldn't ever reach this */ + /* loading X.509 CA certificates */ + load_authcerts("CA cert", CA_CERT_PATH, AUTH_CA); + /* loading X.509 AA certificates */ + load_authcerts("AA cert", AA_CERT_PATH, AUTH_AA); + /* loading X.509 OCSP certificates */ + load_authcerts("OCSP cert", OCSP_CERT_PATH, AUTH_OCSP); + /* loading X.509 CRLs */ + load_crls(); + /* loading attribute certificates (experimental) */ + load_acerts(); + + daily_log_event(); + call_server(); + return -1; /* Shouldn't ever reach this */ } /* leave pluto, with status. @@ -686,31 +735,33 @@ main(int argc, char **argv) * 1 general discomfort * 10 lock file exists */ -void -exit_pluto(int status) +void exit_pluto(int status) { - reset_globals(); /* needed because we may be called in odd state */ - free_preshared_secrets(); - free_remembered_public_keys(); - delete_every_connection(); - 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_acerts(); /* free chain of X.509 attribute certificates */ - free_ca_infos(); /* free chain of X.509 CA information records */ - free_ocsp(); /* free ocsp cache */ - free_ifaces(); - scx_finalize(); /* finalize and unload PKCS #11 module */ - xauth_finalize(); /* finalize and unload XAUTH module */ - stop_adns(); - free_md_pool(); - delete_lock(); -#ifdef LEAK_DETECTIVE - report_leaks(); -#endif /* LEAK_DETECTIVE */ - close_log(); - exit(status); + reset_globals(); /* needed because we may be called in odd state */ + free_preshared_secrets(); + free_remembered_public_keys(); + delete_every_connection(); + 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_acerts(); /* free chain of X.509 attribute certificates */ + free_ca_infos(); /* free chain of X.509 CA information records */ + free_ocsp(); /* free ocsp cache */ + free_ifaces(); + scx_finalize(); /* finalize and unload PKCS #11 module */ + xauth_finalize(); /* finalize and unload XAUTH module */ + stop_adns(); + free_md_pool(); + free_crypto(); + free_id(); /* free myids */ + free_events(); /* free remaining events */ + free_vendorid(); /* free all vendor id records */ + delete_lock(); + options->destroy(options); + library_deinit(); + close_log(); + exit(status); } /* diff --git a/src/pluto/primegen.c b/src/pluto/primegen.c deleted file mode 100644 index 159490345..000000000 --- a/src/pluto/primegen.c +++ /dev/null @@ -1,593 +0,0 @@ -/* primegen.c - prime number generator - * Copyright (C) 1998 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG 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. - * - * GnuPG 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * *********************************************************************** - * The algorithm used to generate practically save primes is due to - * Lim and Lee as described in the CRYPTO '97 proceedings (ISBN3540633847) - * page 260. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifdef PLUTO -#include <gmp.h> -#include <freeswan.h> -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "rnd.h" -#include "gcryptfix.h" -#else /*! PLUTO */ -/* #include <assert.h> */ -/* #include <config.h> */ -/* #include "util.h" */ -/* #include "mpi.h" */ -/* #include "cipher.h" */ -#endif /* !PLUTO */ - -static int no_of_small_prime_numbers; -static MPI gen_prime( unsigned nbits, int mode, int randomlevel ); -static int check_prime( MPI prime, MPI val_2 ); -static int is_prime( MPI n, unsigned steps, int *count ); -static void m_out_of_n( char *array, int m, int n ); - - -static void -progress( int c ) -{ - fputc( c, stderr ); -} - - -/**************** - * Generate a prime number (stored in secure memory) - */ -MPI -generate_secret_prime( unsigned nbits ) -{ - MPI prime; - - prime = gen_prime( nbits, 1, 2 ); - progress('\n'); - return prime; -} - -MPI -generate_public_prime( unsigned nbits ) -{ - MPI prime; - - prime = gen_prime( nbits, 0, 2 ); - progress('\n'); - return prime; -} - - -/**************** - * We do not need to use the strongest RNG because we gain no extra - * security from it - The prime number is public and we could also - * offer the factors for those who are willing to check that it is - * indeed a strong prime. - * - * mode 0: Standard - * 1: Make sure that at least one factor is of size qbits. - */ -MPI -generate_elg_prime( int mode, unsigned pbits, unsigned qbits, - MPI g, MPI **ret_factors ) -{ - int n; /* number of factors */ - int m; /* number of primes in pool */ - unsigned fbits; /* length of prime factors */ - MPI *factors; /* current factors */ - MPI *pool; /* pool of primes */ - MPI q; /* first prime factor (variable)*/ - MPI prime; /* prime test value */ - MPI q_factor; /* used for mode 1 */ - byte *perms = NULL; - int i, j; - int count1, count2; - unsigned nprime; - unsigned req_qbits = qbits; /* the requested q bits size */ - MPI val_2 = mpi_alloc_set_ui( 2 ); - - /* find number of needed prime factors */ - for(n=1; (pbits - qbits - 1) / n >= qbits; n++ ) - ; - n--; - if( !n || (mode==1 && n < 2) ) - log_fatal("can't gen prime with pbits=%u qbits=%u\n", pbits, qbits ); - if( mode == 1 ) { - n--; - fbits = (pbits - 2*req_qbits -1) / n; - qbits = pbits - req_qbits - n*fbits; - } - else { - fbits = (pbits - req_qbits -1) / n; - qbits = pbits - n*fbits; - } - if( DBG_CIPHER ) - log_debug("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n", - pbits, req_qbits, qbits, fbits, n ); - prime = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB ); - q = gen_prime( qbits, 0, 1 ); - q_factor = mode==1? gen_prime( req_qbits, 0, 1 ) : NULL; - - /* allocate an array to hold the factors + 2 for later usage */ -#ifdef PLUTO - m_alloc_ptrs_clear(factors, n+2); -#else - factors = m_alloc_clear( (n+2) * sizeof *factors ); -#endif - - /* make a pool of 3n+5 primes (this is an arbitrary value) */ - m = n*3+5; - if( mode == 1 ) - m += 5; /* need some more for DSA */ - if( m < 25 ) - m = 25; -#ifdef PLUTO - m_alloc_ptrs_clear(pool, m); -#else - pool = m_alloc_clear( m * sizeof *pool ); -#endif - - /* permutate over the pool of primes */ - count1=count2=0; - do { - next_try: - if( !perms ) { - /* allocate new primes */ - for(i=0; i < m; i++ ) { - mpi_free(pool[i]); - pool[i] = NULL; - } - /* init m_out_of_n() */ -#ifdef PLUTO - perms = alloc_bytes( m, "perms" ); -#else - perms = m_alloc_clear( m ); -#endif - for(i=0; i < n; i++ ) { - perms[i] = 1; - pool[i] = gen_prime( fbits, 0, 1 ); - factors[i] = pool[i]; - } - } - else { - m_out_of_n( perms, n, m ); - for(i=j=0; i < m && j < n ; i++ ) - if( perms[i] ) { - if( !pool[i] ) - pool[i] = gen_prime( fbits, 0, 1 ); - factors[j++] = pool[i]; - } - if( i == n ) { - m_free(perms); perms = NULL; - progress('!'); - goto next_try; /* allocate new primes */ - } - } - - mpi_set( prime, q ); - mpi_mul_ui( prime, prime, 2 ); - if( mode == 1 ) - mpi_mul( prime, prime, q_factor ); - for(i=0; i < n; i++ ) - mpi_mul( prime, prime, factors[i] ); - mpi_add_ui( prime, prime, 1 ); - nprime = mpi_get_nbits(prime); - if( nprime < pbits ) { - if( ++count1 > 20 ) { - count1 = 0; - qbits++; - progress('>'); - q = gen_prime( qbits, 0, 1 ); - goto next_try; - } - } - else - count1 = 0; - if( nprime > pbits ) { - if( ++count2 > 20 ) { - count2 = 0; - qbits--; - progress('<'); - q = gen_prime( qbits, 0, 1 ); - goto next_try; - } - } - else - count2 = 0; - } while( !(nprime == pbits && check_prime( prime, val_2 )) ); - - if( DBG_CIPHER ) { - progress('\n'); - log_mpidump( "prime : ", prime ); - log_mpidump( "factor q: ", q ); - if( mode == 1 ) - log_mpidump( "factor q0: ", q_factor ); - for(i=0; i < n; i++ ) - log_mpidump( "factor pi: ", factors[i] ); - log_debug("bit sizes: prime=%u, q=%u", mpi_get_nbits(prime), mpi_get_nbits(q) ); - if( mode == 1 ) - fprintf(stderr, ", q0=%u", mpi_get_nbits(q_factor) ); - for(i=0; i < n; i++ ) - fprintf(stderr, ", p%d=%u", i, mpi_get_nbits(factors[i]) ); - progress('\n'); - } - - if( ret_factors ) { /* caller wants the factors */ -#ifdef PLUTO - m_alloc_ptrs_clear(*ret_factors, n+2); -#else - *ret_factors = m_alloc_clear( (n+2) * sizeof **ret_factors); -#endif - if( mode == 1 ) { - i = 0; - (*ret_factors)[i++] = mpi_copy( q_factor ); - for(; i <= n; i++ ) - (*ret_factors)[i] = mpi_copy( factors[i] ); - } - else { - for(; i < n; i++ ) - (*ret_factors)[i] = mpi_copy( factors[i] ); - } - } - - if( g ) { /* create a generator (start with 3)*/ - MPI tmp = mpi_alloc( mpi_get_nlimbs(prime) ); - MPI b = mpi_alloc( mpi_get_nlimbs(prime) ); - MPI pmin1 = mpi_alloc( mpi_get_nlimbs(prime) ); - - if( mode == 1 ) - BUG(); /* not yet implemented */ - factors[n] = q; - factors[n+1] = mpi_alloc_set_ui(2); - mpi_sub_ui( pmin1, prime, 1 ); - mpi_set_ui(g,2); - do { - mpi_add_ui(g, g, 1); - if( DBG_CIPHER ) { -#ifdef PLUTO - log_mpidump("checking g: ", g); -#else - log_debug("checking g: "); - mpi_print( stderr, g, 1 ); -#endif - } - else - progress('^'); - for(i=0; i < n+2; i++ ) { - /*fputc('~', stderr);*/ - mpi_fdiv_q(tmp, pmin1, factors[i] ); - /* (no mpi_pow(), but it is okay to use this with mod prime) */ - mpi_powm(b, g, tmp, prime ); - if( !mpi_cmp_ui(b, 1) ) - break; - } - if( DBG_CIPHER ) - progress('\n'); - } while( i < n+2 ); - mpi_free(factors[n+1]); - mpi_free(tmp); - mpi_free(b); - mpi_free(pmin1); - } - if( !DBG_CIPHER ) - progress('\n'); - - m_free( factors ); /* (factors are shallow copies) */ - for(i=0; i < m; i++ ) - mpi_free( pool[i] ); - m_free( pool ); - m_free(perms); - mpi_free(val_2); - return prime; -} - - - -static MPI -gen_prime( unsigned nbits, int secret, int randomlevel ) -{ - unsigned nlimbs; - MPI prime, ptest, pminus1, val_2, val_3, result; - int i; - unsigned x, step; - unsigned count1, count2; - int *mods; - - if( 0 && DBG_CIPHER ) - log_debug("generate a prime of %u bits ", nbits ); - - if( !no_of_small_prime_numbers ) { - for(i=0; small_prime_numbers[i]; i++ ) - no_of_small_prime_numbers++; - } - mods = m_alloc( no_of_small_prime_numbers * sizeof *mods ); - /* make nbits fit into MPI implementation */ - nlimbs = (nbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB; - val_2 = mpi_alloc_set_ui( 2 ); - val_3 = mpi_alloc_set_ui( 3); - prime = secret? mpi_alloc_secure( nlimbs ): mpi_alloc( nlimbs ); - result = mpi_alloc_like( prime ); - pminus1= mpi_alloc_like( prime ); - ptest = mpi_alloc_like( prime ); - count1 = count2 = 0; - for(;;) { /* try forvever */ - int dotcount=0; - - /* generate a random number */ - { char *p = get_random_bits( nbits, randomlevel, secret ); - mpi_set_buffer( prime, p, (nbits+7)/8, 0 ); - m_free(p); - } - - /* set high order bit to 1, set low order bit to 1 */ - mpi_set_highbit( prime, nbits-1 ); - mpi_set_bit( prime, 0 ); - - /* calculate all remainders */ - for(i=0; (x = small_prime_numbers[i]); i++ ) - mods[i] = mpi_fdiv_r_ui(NULL, prime, x); - - /* now try some primes starting with prime */ - for(step=0; step < 20000; step += 2 ) { - /* check against all the small primes we have in mods */ - count1++; - for(i=0; (x = small_prime_numbers[i]); i++ ) { - while( mods[i] + step >= x ) - mods[i] -= x; - if( !(mods[i] + step) ) - break; - } - if( x ) - continue; /* found a multiple of an already known prime */ - - mpi_add_ui( ptest, prime, step ); - - /* do a faster Fermat test */ - count2++; - mpi_sub_ui( pminus1, ptest, 1); - mpi_powm( result, val_2, pminus1, ptest ); - if( !mpi_cmp_ui( result, 1 ) ) { /* not composite */ - /* perform stronger tests */ - if( is_prime(ptest, 5, &count2 ) ) { - if( !mpi_test_bit( ptest, nbits-1 ) ) { - progress('\n'); - log_debug("overflow in prime generation\n"); - break; /* step loop, continue with a new prime */ - } - - mpi_free(val_2); - mpi_free(val_3); - mpi_free(result); - mpi_free(pminus1); - mpi_free(prime); - m_free(mods); - return ptest; - } - } - if( ++dotcount == 10 ) { - progress('.'); - dotcount = 0; - } - } - progress(':'); /* restart with a new random value */ - } -} - -/**************** - * Returns: true if this may be a prime - */ -static int -check_prime( MPI prime, MPI val_2 ) -{ - int i; - unsigned x; - int count=0; - - /* check against small primes */ - for(i=0; (x = small_prime_numbers[i]); i++ ) { - if( mpi_divisible_ui( prime, x ) ) - return 0; - } - - /* a quick fermat test */ - { - MPI result = mpi_alloc_like( prime ); - MPI pminus1 = mpi_alloc_like( prime ); - mpi_sub_ui( pminus1, prime, 1); - mpi_powm( result, val_2, pminus1, prime ); - mpi_free( pminus1 ); - if( mpi_cmp_ui( result, 1 ) ) { /* if composite */ - mpi_free( result ); - progress('.'); - return 0; - } - mpi_free( result ); - } - - /* perform stronger tests */ - if( is_prime(prime, 5, &count ) ) - return 1; /* is probably a prime */ - progress('.'); - return 0; -} - - -/**************** - * Return true if n is probably a prime - */ -static int -is_prime( MPI n, unsigned steps, int *count ) -{ - MPI x = mpi_alloc( mpi_get_nlimbs( n ) ); - MPI y = mpi_alloc( mpi_get_nlimbs( n ) ); - MPI z = mpi_alloc( mpi_get_nlimbs( n ) ); - MPI nminus1 = mpi_alloc( mpi_get_nlimbs( n ) ); - MPI a2 = mpi_alloc_set_ui( 2 ); - MPI q; - unsigned i, j, k; - int rc = 0; - unsigned nbits = mpi_get_nbits( n ); - - mpi_sub_ui( nminus1, n, 1 ); - - /* find q and k, so that n = 1 + 2^k * q */ - q = mpi_copy( nminus1 ); - k = mpi_trailing_zeros( q ); - mpi_tdiv_q_2exp(q, q, k); - - for(i=0 ; i < steps; i++ ) { - ++*count; - if( !i ) { - mpi_set_ui( x, 2 ); - } - else { - /*mpi_set_bytes( x, nbits-1, get_random_byte, 0 );*/ - { char *p = get_random_bits( nbits, 0, 0 ); - mpi_set_buffer( x, p, (nbits+7)/8, 0 ); - m_free(p); - } - /* make sure that the number is smaller than the prime - * and keep the randomness of the high bit */ - if( mpi_test_bit( x, nbits-2 ) ) { - mpi_set_highbit( x, nbits-2 ); /* clear all higher bits */ - } - else { - mpi_set_highbit( x, nbits-2 ); - mpi_clear_bit( x, nbits-2 ); - } - assert( mpi_cmp( x, nminus1 ) < 0 && mpi_cmp_ui( x, 1 ) > 0 ); - } - mpi_powm( y, x, q, n); - if( mpi_cmp_ui(y, 1) && mpi_cmp( y, nminus1 ) ) { - for( j=1; j < k && mpi_cmp( y, nminus1 ); j++ ) { - mpi_powm(y, y, a2, n); - if( !mpi_cmp_ui( y, 1 ) ) - goto leave; /* not a prime */ - } - if( mpi_cmp( y, nminus1 ) ) - goto leave; /* not a prime */ - } - progress('+'); - } - rc = 1; /* may be a prime */ - - leave: - mpi_free( x ); - mpi_free( y ); - mpi_free( z ); - mpi_free( nminus1 ); - mpi_free( q ); - - return rc; -} - - -static void -m_out_of_n( char *array, int m, int n ) -{ - int i=0, i1=0, j=0, jp=0, j1=0, k1=0, k2=0; - - if( !m || m >= n ) - return; - - if( m == 1 ) { /* special case */ - for(i=0; i < n; i++ ) - if( array[i] ) { - array[i++] = 0; - if( i >= n ) - i = 0; - array[i] = 1; - return; - } - BUG(); - } - - for(j=1; j < n; j++ ) { - if( array[n-1] == array[n-j-1] ) - continue; - j1 = j; - break; - } - - if( m & 1 ) { /* m is odd */ - if( array[n-1] ) { - if( j1 & 1 ) { - k1 = n - j1; - k2 = k1+2; - if( k2 > n ) - k2 = n; - goto leave; - } - goto scan; - } - k2 = n - j1 - 1; - if( k2 == 0 ) { - k1 = i; - k2 = n - j1; - } - else if( array[k2] && array[k2-1] ) - k1 = n; - else - k1 = k2 + 1; - } - else { /* m is even */ - if( !array[n-1] ) { - k1 = n - j1; - k2 = k1 + 1; - goto leave; - } - - if( !(j1 & 1) ) { - k1 = n - j1; - k2 = k1+2; - if( k2 > n ) - k2 = n; - goto leave; - } - scan: - jp = n - j1 - 1; - for(i=1; i <= jp; i++ ) { - i1 = jp + 2 - i; - if( array[i1-1] ) { - if( array[i1-2] ) { - k1 = i1 - 1; - k2 = n - j1; - } - else { - k1 = i1 - 1; - k2 = n + 1 - j1; - } - goto leave; - } - } - k1 = 1; - k2 = n + 1 - m; - } - leave: - array[k1-1] = !array[k1-1]; - array[k2-1] = !array[k2-1]; -} - diff --git a/src/pluto/rcv_whack.c b/src/pluto/rcv_whack.c index 00fed63ea..013deb446 100644 --- a/src/pluto/rcv_whack.c +++ b/src/pluto/rcv_whack.c @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: rcv_whack.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdio.h> @@ -27,7 +25,7 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ +#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ #include <sys/queue.h> #include <fcntl.h> @@ -42,17 +40,17 @@ #include "smartcard.h" #include "connections.h" #include "foodgroups.h" -#include "whack.h" /* needs connections.h */ +#include "whack.h" /* needs connections.h */ #include "packet.h" -#include "demux.h" /* needs packet.h */ +#include "demux.h" /* needs packet.h */ #include "state.h" -#include "ipsec_doi.h" /* needs demux.h and 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 "adns.h" /* needs <resolv.h> */ +#include "dnskey.h" /* needs keys.h and adns.h */ #include "server.h" #include "fetch.h" #include "ocsp.h" @@ -63,186 +61,186 @@ /* helper variables and function to decode strings from whack message */ static char *next_str - , *str_roof; + , *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; - } + 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, + ka_TXT, #ifdef USE_KEYRR - ka_KEY, + ka_KEY, #endif - ka_roof /* largest value + 1 */ + ka_roof /* largest value + 1 */ }; struct key_add_common { - int refCount; - char *diag[ka_roof]; - int whack_fd; - bool success; + 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; + struct adns_continuation ac; /* common prefix */ + struct key_add_common *common; /* common data */ + enum key_add_attempt lookingfor; }; static void key_add_ugh(const struct id *keyid, err_t ugh) { - char name[BUF_LEN]; /* longer IDs will be truncated in message */ + char name[BUF_LEN]; /* longer IDs will be truncated in message */ - (void)idtoa(keyid, name, sizeof(name)); - loglog(RC_NOKEY - , "failure to fetch key for %s from DNS: %s", name, ugh); + (void)idtoa(keyid, name, sizeof(name)); + loglog(RC_NOKEY + , "failure to fetch key for %s from DNS: %s", name, ugh); } /* last one out: turn out the lights */ static void key_add_merge(struct key_add_common *oc, const struct id *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]); + if (oc->refCount == 0) + { + enum key_add_attempt kaa; - for (kaa = ka_TXT; kaa != ka_roof; kaa++) - pfreeany(oc->diag[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]); - close(oc->whack_fd); - pfree(oc); - } + for (kaa = ka_TXT; kaa != ka_roof; kaa++) + { + free(oc->diag[kaa]); + } + close(oc->whack_fd); + free(oc); + } } 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, "key add error"); - } - else - { - oc->success = TRUE; - transfer_to_public_keys(kc->ac.gateways_from_dns + 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 + , &kc->ac.keys_from_dns #endif /* USE_KEYRR */ - ); - } + ); + } - oc->refCount--; - key_add_merge(oc, &ac->id); - whack_log_fd = NULL_FD; + oc->refCount--; + key_add_merge(oc, &ac->id); + whack_log_fd = NULL_FD; } static void key_add_request(const whack_message_t *msg) { - struct id keyid; - err_t ugh = atoid(msg->keyid, &keyid, FALSE); - - if (ugh != NULL) - { - loglog(RC_BADID, "bad --keyid \"%s\": %s", msg->keyid, ugh); - } - else - { - if (!msg->whack_addkey) - delete_public_keys(&keyid, msg->pubkey_alg - , empty_chunk, empty_chunk); - - if (msg->keyval.len == 0) - { - struct key_add_common *oc - = alloc_thing(struct key_add_common - , "key add common things"); - enum key_add_attempt kaa; - - /* 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 - = alloc_thing(struct key_add_continuation - , "key add continuation"); - - oc->diag[kaa] = NULL; - oc->refCount++; - kc->common = oc; - kc->lookingfor = kaa; - switch (kaa) + struct id keyid; + err_t ugh = atoid(msg->keyid, &keyid, FALSE); + + if (ugh != NULL) + { + loglog(RC_BADID, "bad --keyid \"%s\": %s", msg->keyid, ugh); + } + else + { + if (!msg->whack_addkey) + delete_public_keys(&keyid, msg->pubkey_alg + , chunk_empty, chunk_empty); + + if (msg->keyval.len == 0) { - case ka_TXT: - ugh = start_adns_query(&keyid - , &keyid /* same */ - , T_TXT - , key_add_continue - , &kc->ac); - break; + struct key_add_common *oc = malloc_thing(struct key_add_common); + enum key_add_attempt kaa; + + /* 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; + + switch (kaa) + { + case ka_TXT: + ugh = start_adns_query(&keyid + , &keyid /* same */ + , T_TXT + , key_add_continue + , &kc->ac); + break; #ifdef USE_KEYRR - case ka_KEY: - ugh = start_adns_query(&keyid - , NULL - , T_KEY - , key_add_continue - , &kc->ac); - break; + case ka_KEY: + ugh = start_adns_query(&keyid + , NULL + , T_KEY + , key_add_continue + , &kc->ac); + break; #endif /* USE_KEYRR */ - default: - bad_case(kaa); /* suppress gcc warning */ + default: + bad_case(kaa); /* suppress gcc warning */ + } + if (ugh != NULL) + { + oc->diag[kaa] = clone_str(ugh); + oc->refCount--; + } + } + + /* Done launching queries. + * Handle total failure case. + */ + key_add_merge(oc, &keyid); } - if (ugh != NULL) + else { - oc->diag[kaa] = clone_str(ugh, "early key add failure"); - oc->refCount--; + if (!add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg, msg->keyval, + &pubkeys)) + { + loglog(RC_LOG_SERIOUS, "failed to add public key"); + } } - } - - /* Done launching queries. - * Handle total failure case. - */ - key_add_merge(oc, &keyid); } - else - { - ugh = add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg - , &msg->keyval, &pubkeys); - if (ugh != NULL) - loglog(RC_LOG_SERIOUS, "%s", ugh); - } - } } /* Handle a kernel request. Supposedly, there's a message in @@ -251,430 +249,431 @@ key_add_request(const whack_message_t *msg) 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; - } + 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)); + n = read(whackfd, &msg, sizeof(msg)); - if (n == -1) - { - log_errno((e, "read() failed in whack_handle()")); - close(whackfd); - return; - } + if (n == -1) + { + log_errno((e, "read() failed in whack_handle()")); + close(whackfd); + return; + } - whack_log_fd = whackfd; + whack_log_fd = whackfd; - /* sanity check message */ - { - err_t ugh = NULL; + /* sanity check message */ + { + err_t ugh = NULL; - next_str = msg.string; - str_roof = (char *)&msg + n; + next_str = msg.string; + str_roof = (char *)&msg + n; - if ((size_t)n < offsetof(whack_message_t, whack_shutdown) + sizeof(msg.whack_shutdown)) + 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 compatability. */ + 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.virt) /* string 7 */ + || !unpack_str(&msg.right.id) /* string 8 */ + || !unpack_str(&msg.right.cert) /* string 9 */ + || !unpack_str(&msg.right.ca) /* string 10 */ + || !unpack_str(&msg.right.groups) /* string 11 */ + || !unpack_str(&msg.right.updown) /* string 12 */ + || !unpack_str(&msg.right.virt) /* string 13 */ + || !unpack_str(&msg.keyid) /* string 14 */ + || !unpack_str(&msg.myid) /* string 15 */ + || !unpack_str(&msg.cacert) /* string 16 */ + || !unpack_str(&msg.ldaphost) /* string 17 */ + || !unpack_str(&msg.ldapbase) /* string 18 */ + || !unpack_str(&msg.crluri) /* string 19 */ + || !unpack_str(&msg.crluri2) /* string 20 */ + || !unpack_str(&msg.ocspuri) /* string 21 */ + || !unpack_str(&msg.ike) /* string 22 */ + || !unpack_str(&msg.esp) /* string 23 */ + || !unpack_str(&msg.sc_data) /* string 24 */ + || 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) { - ugh = builddiag("ignoring runt message from whack: got %d bytes", (int)n); +#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) + { + struct connection *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); } - else if (msg.magic != WHACK_MAGIC) + + if (msg.whack_deletestate) { - if (msg.magic == WHACK_BASIC_MAGIC) - { - /* Only shutdown command. Simpler inter-version compatability. */ - if (msg.whack_shutdown) + 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 { - plog("shutting down"); - exit_pluto(0); /* delete lock and leave, with 0 status */ + delete_state(st); } - 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.virt) /* string 7 */ - || !unpack_str(&msg.right.id) /* string 8 */ - || !unpack_str(&msg.right.cert) /* string 9 */ - || !unpack_str(&msg.right.ca) /* string 10 */ - || !unpack_str(&msg.right.groups) /* string 11 */ - || !unpack_str(&msg.right.updown) /* string 12 */ - || !unpack_str(&msg.right.virt) /* string 13 */ - || !unpack_str(&msg.keyid) /* string 14 */ - || !unpack_str(&msg.myid) /* string 15 */ - || !unpack_str(&msg.cacert) /* string 16 */ - || !unpack_str(&msg.ldaphost) /* string 17 */ - || !unpack_str(&msg.ldapbase) /* string 18 */ - || !unpack_str(&msg.crluri) /* string 19 */ - || !unpack_str(&msg.crluri2) /* string 20 */ - || !unpack_str(&msg.ocspuri) /* string 21 */ - || !unpack_str(&msg.ike) /* string 22 */ - || !unpack_str(&msg.esp) /* string 23 */ - || !unpack_str(&msg.sc_data) /* string 24 */ - || str_roof - next_str != (ptrdiff_t)msg.keyval.len) /* check chunk */ - { - ugh = "message from whack contains bad string"; } - else + + 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(); + reset_adns_restart_count(); + set_myFQDN(); + find_ifaces(); + load_preshared_secrets(NULL_FD); + load_groups(); + } + if (msg.whack_unlisten) { - msg.keyval.ptr = next_str; /* grab chunk */ + plog("no longer listening for IKE messages"); + listening = FALSE; } - if (ugh != NULL) + if (msg.whack_reread & REREAD_SECRETS) { - if (*ugh != '\0') - loglog(RC_BADWHACKMESSAGE, "%s", ugh); - whack_log_fd = NULL_FD; - close(whackfd); - return; + load_preshared_secrets(whackfd); } - } - 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) - { - struct connection *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))); - } + if (msg.whack_reread & REREAD_CACERTS) + { + load_authcerts("CA cert", CA_CERT_PATH, AUTH_CA); } -#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 (msg.whack_reread & REREAD_AACERTS) + { + load_authcerts("AA cert", AA_CERT_PATH, AUTH_AA); + } - if (st == NULL) + if (msg.whack_reread & REREAD_OCSPCERTS) { - loglog(RC_UNKNOWN_NAME, "no state #%lu to delete" - , msg.whack_deletestateno); + load_authcerts("OCSP cert", OCSP_CERT_PATH, AUTH_OCSP); } - else + + if (msg.whack_reread & REREAD_ACERTS) { - 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(); - reset_adns_restart_count(); - 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 cert", CA_CERT_PATH, AUTH_CA); - } - - if (msg.whack_reread & REREAD_AACERTS) - { - load_authcerts("AA cert", AA_CERT_PATH, AUTH_AA); - } - - if (msg.whack_reread & REREAD_OCSPCERTS) - { - load_authcerts("OCSP cert", OCSP_CERT_PATH, AUTH_OCSP); - } - - if (msg.whack_reread & REREAD_ACERTS) - { - load_acerts(); - } - - if (msg.whack_reread & REREAD_CRLS) - { - load_crls(); - } - - if (msg.whack_purgeocsp) - { - free_ocsp_fetch(); - free_ocsp_cache(); - } - - if (msg.whack_list & LIST_ALGS) - { - ike_alg_list(); - kernel_alg_list(); - } + load_acerts(); + } + + if (msg.whack_reread & REREAD_CRLS) + { + load_crls(); + } + + if (msg.whack_purgeocsp) + { + free_ocsp_fetch(); + free_ocsp_cache(); + } + if (msg.whack_list & LIST_PUBKEYS) - { - list_public_keys(msg.whack_utc); - } - - if (msg.whack_list & LIST_CERTS) - { - list_certs(msg.whack_utc); - } - - if (msg.whack_list & LIST_CACERTS) - { - list_authcerts("CA", AUTH_CA, msg.whack_utc); - } - - if (msg.whack_list & LIST_AACERTS) - { - list_authcerts("AA", AUTH_AA, msg.whack_utc); - } - - if (msg.whack_list & LIST_OCSPCERTS) - { - list_authcerts("OCSP", AUTH_OCSP, msg.whack_utc); - } - - if (msg.whack_list & LIST_ACERTS) - { - list_acerts(msg.whack_utc); - } - - if (msg.whack_list & LIST_GROUPS) - { - list_groups(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_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"); + { + list_public_keys(msg.whack_utc); } - else + + if (msg.whack_list & LIST_CERTS) { - struct connection *c = con_by_name(msg.name, TRUE); + list_certs(msg.whack_utc); + } - 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_list & LIST_CACERTS) + { + list_authcerts("CA", AUTH_CA, msg.whack_utc); } - } - if (msg.whack_unroute) - { - if (msg.name == NULL) + if (msg.whack_list & LIST_AACERTS) { - whack_log(RC_UNKNOWN_NAME - , "whack --unroute requires a connection name"); + list_authcerts("AA", AUTH_AA, msg.whack_utc); } - else + + if (msg.whack_list & LIST_OCSPCERTS) { - struct connection *c = con_by_name(msg.name, TRUE); + list_authcerts("OCSP", AUTH_OCSP, msg.whack_utc); + } - if (c != NULL && c->ikev1) - { - struct spd_route *sr; - int fail = 0; + if (msg.whack_list & LIST_ACERTS) + { + list_acerts(msg.whack_utc); + } - set_cur_connection(c); + if (msg.whack_list & LIST_GROUPS) + { + list_groups(msg.whack_utc); + } - 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_list & LIST_CAINFOS) + { + list_ca_infos(msg.whack_utc); } - } - if (msg.whack_initiate) - { - if (!listening) + if (msg.whack_list & LIST_CRLS) { - whack_log(RC_DEAF, "need --listen before --initiate"); + list_crls(msg.whack_utc, strict_crl_policy); + list_crl_fetch_requests(msg.whack_utc); } - else if (msg.name == NULL) + + if (msg.whack_list & LIST_OCSP) { - whack_log(RC_UNKNOWN_NAME - , "whack --initiate requires a connection name"); + list_ocsp_cache(msg.whack_utc, strict_crl_policy); + list_ocsp_fetch_requests(msg.whack_utc); } - else + + if (msg.whack_list & LIST_CARDS) { - initiate_connection(msg.name - , msg.whack_async? NULL_FD : dup_any(whackfd)); + scx_list(msg.whack_utc); } - } - 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_list & LIST_ALGS) + { + ike_alg_list(); + kernel_alg_list(); + } - if (msg.whack_terminate) - { - if (msg.name == NULL) + if (msg.whack_key) { - whack_log(RC_UNKNOWN_NAME - , "whack --terminate requires a connection name"); + /* add a public key */ + key_add_request(&msg); } - else + + if (msg.whack_route) { - terminate_connection(msg.name); + 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 + { + struct connection *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_status) - show_status(msg.whack_statusall, msg.name); + if (msg.whack_unroute) + { + if (msg.name == NULL) + { + whack_log(RC_UNKNOWN_NAME + , "whack --unroute requires a connection name"); + } + else + { + struct connection *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_shutdown) - { - plog("shutting down"); - exit_pluto(0); /* delete lock and leave, with 0 status */ - } + 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_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)"); - } + 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 */ + } - whack_log_fd = NULL_FD; - close(whackfd); + 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); } /* diff --git a/src/pluto/rcv_whack.h b/src/pluto/rcv_whack.h index e0582202f..66edaaf80 100644 --- a/src/pluto/rcv_whack.h +++ b/src/pluto/rcv_whack.h @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: rcv_whack.h 3252 2007-10-06 21:24:50Z andreas $ */ extern void whack_handle(int kernelfd); diff --git a/src/pluto/rnd.c b/src/pluto/rnd.c deleted file mode 100644 index 7941034d8..000000000 --- a/src/pluto/rnd.c +++ /dev/null @@ -1,250 +0,0 @@ -/* randomness machinery - * 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. - * - * RCSID $Id: rnd.c 3252 2007-10-06 21:24:50Z andreas $ - */ - -/* A true random number generator (we hope) - * - * Under LINUX ("linux" predefined), use /dev/urandom. - * Under OpenBSD ("__OpenBSD__" predefined), use arc4random(). - * Otherwise use our own random number generator based on clock skew. - * I (ADK) first heard of the idea from John Ioannidis, who heard it - * from Matt Blaze and/or Jack Lacy. - * ??? Why is mixing need for linux but not OpenBSD? - */ - -/* Pluto's uses of randomness: - * - * - Setting up the "secret_of_the_day". This changes every hour! 20 - * bytes a shot. It is used in building responder cookies. - * - * - generating initiator cookies (8 bytes, once per Phase 1 initiation). - * - * - 32 bytes per DH local secret. Once per Main Mode exchange and once - * per Quick Mode Exchange with PFS. (Size is our choice, with - * tradeoffs.) - * - * - 16 bytes per nonce we generate. Once per Main Mode exchange and - * once per Quick Mode exchange. (Again, we choose the size.) - * - * - 4 bytes per SPI number that we generate. We choose the SPIs for all - * inbound SPIs, one to three per IPSEC SA (one for AH (rare, probably) - * one for ESP (almost always), and one for tunnel (very common)). - * I don't actually know how the kernel would generate these numbers -- - * currently Pluto generates them; this isn't the way things will be - * done in the future. - * - * - 4 bytes per Message ID we need to generate. One per Quick Mode - * exchange. Eventually, one per informational exchange. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <unistd.h> -#include <errno.h> -#include <sys/time.h> -#include <fcntl.h> - -#include <freeswan.h> - -#include "sha1.h" -#include "constants.h" -#include "defs.h" -#include "rnd.h" -#include "log.h" -#include "timer.h" - -#ifdef linux -# define USE_DEV_RANDOM 1 -# define RANDOM_PATH DEV_URANDOM -#else -# ifdef __OpenBSD__ -# define USE_ARC4RANDOM -# else -# define USE_CLOCK_SLEW -# endif -#endif - -#ifdef USE_ARC4RANDOM - -#define get_rnd_byte() (arc4random() % 256) - -#else /**** start of large #else ****/ - -#ifdef USE_DEV_RANDOM -static int random_fd = NULL_FD; -#endif - -#define RANDOM_POOL_SIZE SHA1_DIGEST_SIZE -static u_char random_pool[RANDOM_POOL_SIZE]; - -#ifdef USE_DEV_RANDOM - -/* Generate (what we hope is) a true random byte using /dev/urandom */ -static u_char -generate_rnd_byte(void) -{ - u_char c; - - if (read(random_fd, &c, sizeof(c)) == -1) - exit_log_errno((e, "read() failed in get_rnd_byte()")); - - return c; -} - -#else /* !USE_DEV_RANDOM */ - -/* Generate (what we hope is) a true random byte using the clock skew trick. - * Note: this code is not maintained! In particular, LINUX signal(2) - * semantics changed with glibc2 (and not for the better). It isn't clear - * that this code will work. We keep the code because someday it might - * come in handy. - */ -# error "This code is not maintained. Please define USE_DEV_RANDOM." - -static volatile sig_atomic_t i, j, k; - -/* timer signal handler */ -static void -rnd_handler(int ignore_me UNUSED) -{ - k <<= 1; /* Shift left by 1 */ - j++; - k |= (i & 0x1); /* Get lsbit of counter */ - - if (j != 8) - signal(SIGVTALRM, rnd_handler); -} - -static u_char -generate_rnd_byte(void) -{ - struct itimerval tmval, ntmval; - -# ifdef NEVER /* ??? */ -# ifdef linux - int mask = siggetmask(); - - mask |= SIGVTALRM; - sigsetmask(mask); -# endif -# endif - - i = 0; - j = 0; - - ntmval.it_interval.tv_sec = 0; - ntmval.it_interval.tv_usec = 1; - ntmval.it_value.tv_sec = 0; - ntmval.it_value.tv_usec = 1; - signal(SIGVTALRM, rnd_handler); - setitimer(ITIMER_VIRTUAL, &ntmval, &tmval); - - while (j != 8) - i++; - - setitimer(ITIMER_VIRTUAL, &tmval, &ntmval); - signal(SIGVTALRM, SIG_IGN); - -# ifdef NEVER /* ??? */ -# ifdef linux - mask ^= SIGVTALRM; - sigsetmask(mask); -# endif -# endif - - return k; -} - -#endif /* !USE_DEV_RANDOM */ - -static void -mix_pool(void) -{ - SHA1_CTX ctx; - - SHA1Init(&ctx); - SHA1Update(&ctx, random_pool, RANDOM_POOL_SIZE); - SHA1Final(random_pool, &ctx); -} - -/* - * Get a single random byte. - */ -static u_char -get_rnd_byte(void) -{ - random_pool[RANDOM_POOL_SIZE - 1] = generate_rnd_byte(); - random_pool[0] = generate_rnd_byte(); - mix_pool(); - return random_pool[0]; -} - -#endif /* !USE_ARC4RANDOM */ /**** end of large #else ****/ - -void -get_rnd_bytes(u_char *buffer, int length) -{ - int i; - - for (i = 0; i < length; i++) - buffer[i] = get_rnd_byte(); -} - -/* - * Initialize the random pool. - */ -void -init_rnd_pool(void) -{ -#ifndef USE_ARC4RANDOM -# ifdef USE_DEV_RANDOM - DBG(DBG_KLIPS, DBG_log("opening %s", RANDOM_PATH)); - random_fd = open(RANDOM_PATH, O_RDONLY); - if (random_fd == -1) - exit_log_errno((e, "open of %s failed in init_rnd_pool()", RANDOM_PATH)); - fcntl(random_fd, F_SETFD, FD_CLOEXEC); -# endif - - get_rnd_bytes(random_pool, RANDOM_POOL_SIZE); - mix_pool(); -#endif /* !USE_ARC4RANDOM */ - - /* start of rand(3) on the right foot */ - { - unsigned int seed; - - get_rnd_bytes((void *)&seed, sizeof(seed)); - srand(seed); - } -} - -u_char secret_of_the_day[SHA1_DIGEST_SIZE]; - -#ifndef NO_PLUTO - -void -init_secret(void) -{ - /* - * Generate the secret value for responder cookies, and - * schedule an event for refresh. - */ - get_rnd_bytes(secret_of_the_day, sizeof(secret_of_the_day)); - event_schedule(EVENT_REINIT_SECRET, EVENT_REINIT_SECRET_DELAY, NULL); -} - -#endif /* NO_PLUTO */ diff --git a/src/pluto/rnd.h b/src/pluto/rnd.h deleted file mode 100644 index e32b68b47..000000000 --- a/src/pluto/rnd.h +++ /dev/null @@ -1,21 +0,0 @@ -/* randomness machinery - * 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. - * - * RCSID $Id: rnd.h 3252 2007-10-06 21:24:50Z andreas $ - */ - -extern u_char secret_of_the_day[SHA1_DIGEST_SIZE]; - -extern void get_rnd_bytes(u_char *buffer, int length); -extern void init_rnd_pool(void); -extern void init_secret(void); diff --git a/src/pluto/server.c b/src/pluto/server.c index b0e158503..21f65f4f8 100644 --- a/src/pluto/server.c +++ b/src/pluto/server.c @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: server.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdio.h> @@ -27,7 +25,7 @@ #include <sys/socket.h> #include <sys/un.h> #ifdef SOLARIS -# include <sys/sockio.h> /* for Solaris 2.6: defines SIOCGIFCONF */ +# include <sys/sockio.h> /* for Solaris 2.6: defines SIOCGIFCONF */ #endif #include <netinet/in.h> #include <arpa/inet.h> @@ -38,7 +36,7 @@ #include <net/if.h> #include <sys/ioctl.h> #include <resolv.h> -#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ +#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */ #include <sys/queue.h> #include <freeswan.h> @@ -55,9 +53,9 @@ #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 "adns.h" /* needs <resolv.h> */ +#include "dnskey.h" /* needs keys.h and adns.h */ +#include "whack.h" /* for RC_LOG_SERIOUS */ #include <pfkeyv2.h> #include <pfkey.h> @@ -68,10 +66,10 @@ * Server main loop and socket initialization routines. */ -static const int on = TRUE; /* by-reference parameter; constant, we hope */ +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 */ +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 */ @@ -86,121 +84,121 @@ struct sockaddr_un info_addr= { AF_UNIX, DEFAULT_CTLBASE INFO_SUFFIX }; 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)); + 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); + /* 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? */ +bool listening = FALSE; /* should we pay attention to IKE messages? */ -struct iface *interfaces = NULL; /* public interfaces */ +struct iface *interfaces = NULL; /* public interfaces */ /* Initialize the interface sockets. */ static void mark_ifaces_dead(void) { - struct iface *p; + struct iface *p; - for (p = interfaces; p != NULL; p = p->next) - p->change = IFN_DELETE; + 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; + 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) + for (p = interfaces; p != NULL; p = p->next) { - some_new = TRUE; + 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 (some_dead) { - if (p->change == IFN_DELETE) - { - *pp = p->next; /* advance *pp */ - pfree(p->vname); - pfree(p->rname); - close(p->fd); - pfree(p); - } - else - { - pp = &p->next; /* advance pp */ - } + 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(); + + /* 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(); + 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; + ip_address addr; + char name[IFNAMSIZ + 20]; /* what would be a safe size? */ + struct raw_iface *next; }; /* Called to handle --interface <ifname> @@ -212,15 +210,15 @@ static int pluto_ifn_roof = 0; bool use_interface(const char *rifn) { - if (pluto_ifn_roof >= (int)elemsof(pluto_ifn)) - { - return FALSE; - } - else - { - pluto_ifn[pluto_ifn_roof++] = rifn; - return TRUE; - } + if (pluto_ifn_roof >= (int)countof(pluto_ifn)) + { + return FALSE; + } + else + { + pluto_ifn[pluto_ifn_roof++] = rifn; + return TRUE; + } } #ifndef IPSECDEVPREFIX @@ -230,538 +228,542 @@ use_interface(const char *rifn) 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(PF_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 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(PF_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 */ { - int i; + ip_address any; - 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 */ + 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()")); } - /* 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 */ + /* Get local interfaces. See netdevice(7). */ + ifconf.ifc_len = sizeof(buf); + ifconf.ifc_buf = (void *) buf; + zero(buf); - /* ignore unconfigured interfaces */ - if (rs->sin_addr.s_addr == 0) - continue; + if (ioctl(master_sock, SIOCGIFCONF, &ifconf) == -1) + exit_log_errno((e, "ioctl(SIOCGIFCONF) in find_raw_ifaces4()")); - happy(initaddr((const void *)&rs->sin_addr, sizeof(struct in_addr) - , AF_INET, &ri.addr)); + /* 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; - DBG(DBG_CONTROL, DBG_log("found %s with address %s" - , ri.name, ip_str(&ri.addr))); - ri.next = rifaces; - rifaces = clone_thing(ri, "struct raw_iface"); - } + /* ignore all but AF_INET interfaces */ + if (rs->sin_family != AF_INET) + continue; /* not interesting */ - close(master_sock); + /* build a NUL-terminated copy of the rname field */ + memcpy(ri.name, buf[j].ifr_name, IFNAMSIZ); + ri.name[IFNAMSIZ] = '\0'; - return rifaces; + /* 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 (;;) + /* 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) { - 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, "struct raw_iface"); - } + 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); } - fclose(proc_sock); - } - return rifaces; + return rifaces; } #if 1 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; + 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; - } + if (fd < 0) + { + log_errno((e, "socket() in process_raw_ifaces()")); + return -1; + } #if 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); + /* 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); + } } - } -#endif - - 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 -#if defined(linux) && defined(KERNEL26_SUPPORT) - if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) - { - 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) + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { - level = IPPROTO_IPV6; - opt = IPV6_IPSEC_POLICY; + log_errno((e, "fcntl(,, FD_CLOEXEC) in process_raw_ifaces()")); + close(fd); + return -1; } - else + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR + , (const void *)&on, sizeof(on)) < 0) { - level = IPPROTO_IP; - opt = IP_IPSEC_POLICY; + log_errno((e, "setsockopt SO_REUSEADDR in process_raw_ifaces()")); + close(fd); + return -1; } - if (setsockopt(fd, level, opt - , &policy, sizeof(policy)) < 0) + /* 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 IPSEC_POLICY in process_raw_ifaces()")); - close(fd); - return -1; + log_errno((e, "setsockopt IP_RECVERR in process_raw_ifaces()")); + close(fd); + return -1; } +#endif - policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; + /* 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 - if (setsockopt(fd, level, opt - , &policy, sizeof(policy)) < 0) +#if defined(linux) && defined(KERNEL26_SUPPORT) + if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) { - log_errno((e, "setsockopt IPSEC_POLICY in process_raw_ifaces()")); - close(fd); - return -1; + 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; + } } - } #endif - 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; + 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; } #endif static void process_raw_ifaces(struct raw_iface *rifaces) { - struct raw_iface *ifp; - - /* Find all virtual/real interface pairs. - * For each real interface... - */ - for (ifp = rifaces; ifp != NULL; ifp = ifp->next) - { - struct raw_iface *v = NULL; /* matching ipsecX interface */ - struct raw_iface fake_v; - bool after = FALSE; /* has vfp passed ifp on the list? */ - bool bad = FALSE; - struct raw_iface *vfp; - - /* ignore if virtual (ipsec*) interface */ - if (strncmp(ifp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX)-1) == 0) - continue; - - for (vfp = rifaces; vfp != NULL; vfp = vfp->next) + struct raw_iface *ifp; + + /* Find all virtual/real interface pairs. + * For each real interface... + */ + for (ifp = rifaces; ifp != NULL; ifp = ifp->next) { - if (vfp == ifp) - { - after = TRUE; - } - else if (sameaddr(&ifp->addr, &vfp->addr)) - { - /* Different entries with matching IP addresses. - * Many interesting cases. - */ - if (strncmp(vfp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX)-1) == 0) + struct raw_iface *v = NULL; /* matching ipsecX interface */ + struct raw_iface fake_v; + bool after = FALSE; /* has vfp passed ifp on the list? */ + bool bad = FALSE; + struct raw_iface *vfp; + + /* ignore if virtual (ipsec*) interface */ + if (strneq(ifp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX)-1)) { - if (v != NULL && !streq(v->name, vfp->name)) - { - loglog(RC_LOG_SERIOUS - , "ipsec interfaces %s and %s share same address %s" - , v->name, vfp->name, ip_str(&ifp->addr)); - bad = TRUE; - } - else - { - v = vfp; /* current winner */ - } + continue; } - else + + for (vfp = rifaces; vfp != NULL; vfp = vfp->next) { - /* ugh: a second real interface with the same IP address - * "after" allows us to avoid double reporting. - */ -#if defined(linux) && defined(KERNEL26_SUPPORT) - if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) - { - if (after) + if (vfp == ifp) { - bad = TRUE; - break; + after = TRUE; } - continue; - } + else if (sameaddr(&ifp->addr, &vfp->addr)) + { + /* Different entries with matching IP addresses. + * Many interesting cases. + */ + if (strneq(vfp->name, IPSECDEVPREFIX, sizeof(IPSECDEVPREFIX)-1)) + { + if (v != NULL && !streq(v->name, vfp->name)) + { + loglog(RC_LOG_SERIOUS + , "ipsec interfaces %s and %s share same address %s" + , v->name, vfp->name, ip_str(&ifp->addr)); + bad = TRUE; + } + else + { + v = vfp; /* current winner */ + } + } + else + { + /* ugh: a second real interface with the same IP address + * "after" allows us to avoid double reporting. + */ +#if defined(linux) && defined(KERNEL26_SUPPORT) + if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) + { + if (after) + { + bad = TRUE; + break; + } + continue; + } #endif - if (after) - { - loglog(RC_LOG_SERIOUS - , "IP interfaces %s and %s share address %s!" - , ifp->name, vfp->name, ip_str(&ifp->addr)); - } - bad = TRUE; + if (after) + { + loglog(RC_LOG_SERIOUS + , "IP interfaces %s and %s share address %s!" + , ifp->name, vfp->name, ip_str(&ifp->addr)); + } + bad = TRUE; + } + } } - } - } - if (bad) - continue; + if (bad) + continue; #if defined(linux) && defined(KERNEL26_SUPPORT) - if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) - { - v = ifp; - goto add_entry; - } + if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) + { + v = ifp; + goto add_entry; + } #endif - /* what if we didn't find a virtual interface? */ - if (v == NULL) - { - if (no_klips) - { - /* kludge for testing: invent a virtual device */ - static const char fvp[] = "virtual"; - fake_v = *ifp; - passert(sizeof(fake_v.name) > sizeof(fvp)); - strcpy(fake_v.name, fvp); - addrtot(&ifp->addr, 0, fake_v.name + sizeof(fvp) - 1 - , sizeof(fake_v.name) - (sizeof(fvp) - 1)); - v = &fake_v; - } - else - { - DBG(DBG_CONTROL, - DBG_log("IP interface %s %s has no matching ipsec* interface -- ignored" - , ifp->name, ip_str(&ifp->addr))); - continue; - } - } + /* what if we didn't find a virtual interface? */ + if (v == NULL) + { + if (no_klips) + { + /* kludge for testing: invent a virtual device */ + static const char fvp[] = "virtual"; + fake_v = *ifp; + passert(sizeof(fake_v.name) > sizeof(fvp)); + strcpy(fake_v.name, fvp); + addrtot(&ifp->addr, 0, fake_v.name + sizeof(fvp) - 1 + , sizeof(fake_v.name) - (sizeof(fvp) - 1)); + v = &fake_v; + } + else + { + DBG(DBG_CONTROL, + DBG_log("IP interface %s %s has no matching ipsec* interface -- ignored" + , ifp->name, ip_str(&ifp->addr))); + continue; + } + } - /* We've got all we need; see if this is a new thing: - * search old interfaces list. - */ + /* We've got all we need; see if this is a new thing: + * search old interfaces list. + */ #if defined(linux) && defined(KERNEL26_SUPPORT) add_entry: #endif - { - 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 = alloc_thing(struct iface, "struct iface"); - q->rname = clone_str(ifp->name, "real device name"); - q->vname = clone_str(v->name, "virtual device 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 = alloc_thing(struct iface, "struct iface"); - q->rname = clone_str(ifp->name, "real device name"); - q->vname = clone_str(v->name, "virtual device 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; - } + struct iface **p = &interfaces; - /* 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)) + for (;;) { - q->change = IFN_KEEP; - } - } - break; + 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 (;;) */ } - - /* try again */ - p = &q->next; - } /* for (;;) */ } - } - /* delete the raw interfaces list */ - while (rifaces != NULL) - { - struct raw_iface *t = rifaces; + /* delete the raw interfaces list */ + while (rifaces != NULL) + { + struct raw_iface *t = rifaces; - rifaces = t->next; - pfree(t); - } + rifaces = t->next; + free(t); + } } void find_ifaces(void) { - mark_ifaces_dead(); - process_raw_ifaces(find_raw_ifaces4()); - process_raw_ifaces(find_raw_ifaces6()); + mark_ifaces_dead(); + process_raw_ifaces(find_raw_ifaces4()); + process_raw_ifaces(find_raw_ifaces6()); - free_dead_ifaces(); /* ditch remaining old entries */ + free_dead_ifaces(); /* ditch remaining old entries */ - if (interfaces == NULL) - loglog(RC_LOG_SERIOUS, "no public interfaces found"); + if (interfaces == NULL) + loglog(RC_LOG_SERIOUS, "no public interfaces found"); } void show_ifaces_status(void) { - struct iface *p; + 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))); + 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 %s" - , bitnamesof(debug_bit_names, cur_debugging)); + whack_log(RC_COMMENT, "debug options: %s" + , bitnamesof(debug_bit_names, cur_debugging)); #endif } @@ -770,7 +772,7 @@ static volatile sig_atomic_t sighupflag = FALSE; static void huphandler(int sig UNUSED) { - sighupflag = TRUE; + sighupflag = TRUE; } static volatile sig_atomic_t sigtermflag = FALSE; @@ -778,7 +780,7 @@ static volatile sig_atomic_t sigtermflag = FALSE; static void termhandler(int sig UNUSED) { - sigtermflag = TRUE; + sigtermflag = TRUE; } /* call_server listens for incoming ISAKMP packets and Whack messages, @@ -787,206 +789,206 @@ termhandler(int sig UNUSED) void call_server(void) { - struct iface *ifp; + struct iface *ifp; - /* catch SIGHUP and SIGTERM */ - { - int r; - struct sigaction act; + /* 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); + passert(r == 0); + } - 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); + for (;;) + { + fd_set readfds; + fd_set writefds; + int ndes; - act.sa_handler = &termhandler; - r = sigaction(SIGTERM, &act, NULL); - passert(r == 0); - } + /* wait for next interesting thing */ - for (;;) - { - fd_set readfds; - fd_set writefds; - int ndes; + for (;;) + { + long next_time = next_event(); /* time to any pending timer event */ + int maxfd = ctl_fd; - /* wait for next interesting thing */ + if (sigtermflag) + exit_pluto(0); - 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); - - /* 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); - } + 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); + + /* 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); + } #ifdef KLIPS - if (!no_klips) - { - int fd = *kernel_ops->async_fdp; - - if (kernel_ops->process_queue) - kernel_ops->process_queue(); - if (maxfd < fd) - maxfd = fd; - passert(!FD_ISSET(fd, &readfds)); - FD_SET(fd, &readfds); - } + if (!no_klips) + { + int fd = *kernel_ops->async_fdp; + + if (kernel_ops->process_queue) + kernel_ops->process_queue(); + if (maxfd < fd) + maxfd = fd; + passert(!FD_ISSET(fd, &readfds)); + FD_SET(fd, &readfds); + } #endif - 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 */ + 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); + } + } - struct timeval tm; + if (next_time == -1) + { + /* select without timer */ - tm.tv_sec = next_time; - tm.tv_usec = 0; - ndes = select(maxfd + 1, &readfds, &writefds, NULL, &tm); - } + 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 */ - if (ndes != -1) - break; /* success */ + struct timeval tm; - if (errno != EINTR) - exit_log_errno((e, "select() failed in call_server()")); + tm.tv_sec = next_time; + tm.tv_usec = 0; + ndes = select(maxfd + 1, &readfds, &writefds, NULL, &tm); + } - /* retry if terminated by signal */ - } + if (ndes != -1) + break; /* success */ - /* figure out what is interesting */ + if (errno != EINTR) + exit_log_errno((e, "select() failed in call_server()")); - if (ndes == 0) - { - /* timer event */ + /* retry if terminated by signal */ + } - DBG(DBG_CONTROL, - DBG_log(BLANK_FORMAT); - DBG_log("*time to handle event")); + /* figure out what is interesting */ - handle_timer_event(); - passert(GLOBALS_ARE_RESET()); - } - else - { - /* at least one file descriptor is ready */ - - 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--; - } + 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 */ + + 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--; + } #ifdef KLIPS - if (!no_klips && FD_ISSET(*kernel_ops->async_fdp, &readfds)) - { - passert(ndes > 0); - DBG(DBG_CONTROL, - DBG_log(BLANK_FORMAT); - DBG_log("*received kernel message")); - kernel_ops->process_msg(); - passert(GLOBALS_ARE_RESET()); - ndes--; - } + if (!no_klips && FD_ISSET(*kernel_ops->async_fdp, &readfds)) + { + passert(ndes > 0); + DBG(DBG_CONTROL, + DBG_log(BLANK_FORMAT); + DBG_log("*received kernel message")); + kernel_ops->process_msg(); + passert(GLOBALS_ARE_RESET()); + ndes--; + } #endif - 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--; + 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); } - } - - 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); } - } } /* diff --git a/src/pluto/server.h b/src/pluto/server.h index d0d46a5f4..b8123f6dc 100644 --- a/src/pluto/server.h +++ b/src/pluto/server.h @@ -10,20 +10,18 @@ * 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. - * - * RCSID $Id: server.h 3252 2007-10-06 21:24:50Z andreas $ */ -extern int ctl_fd; /* file descriptor of control (whack) socket */ -extern struct sockaddr_un ctl_addr; /* address of control (whack) socket */ +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 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? */ +extern bool listening; /* should we pay attention to IKE messages? */ /* interface: a terminal point for IKE traffic, IPsec transport mode @@ -35,16 +33,16 @@ extern bool listening; /* should we pay attention to IKE messages? */ * 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; + 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 struct iface *interfaces; /* public interfaces */ extern bool use_interface(const char *rifn); extern void find_ifaces(void); diff --git a/src/pluto/sha1.c b/src/pluto/sha1.c deleted file mode 100644 index bbf062876..000000000 --- a/src/pluto/sha1.c +++ /dev/null @@ -1,193 +0,0 @@ -/* -SHA-1 in C -By Steve Reid <steve@edmweb.com> -100% Public Domain - -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ -/* #define SHA1HANDSOFF * Copies data before messing with it. */ - -#define SHA1HANDSOFF - -#include <string.h> -#include <sys/types.h> /* for u_int*_t */ -#include <endian.h> /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */ - -#include "sha1.h" - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#if BYTE_ORDER == LITTLE_ENDIAN -#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#elif BYTE_ORDER == BIG_ENDIAN -#define blk0(i) block->l[i] -#else -#error "Endianness not defined!" -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]) -{ -u_int32_t a, b, c, d, e; -typedef union { - unsigned char c[64]; - u_int32_t l[16]; -} CHAR64LONG16; -#ifdef SHA1HANDSOFF -CHAR64LONG16 block[1]; /* use array to appear as a pointer */ - memcpy(block, buffer, 64); -#else - /* The following had better never be used because it causes the - * pointer-to-const buffer to be cast into a pointer to non-const. - * And the result is written through. I threw a "const" in, hoping - * this will cause a diagnostic. - */ -CHAR64LONG16* block = (const CHAR64LONG16*)buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -#ifdef SHA1HANDSOFF - memset(block, '\0', sizeof(block)); -#endif -} - - -/* SHA1Init - Initialize new context */ - -void SHA1Init(SHA1_CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len) -{ -u_int32_t i; -u_int32_t j; - - j = context->count[0]; - if ((context->count[0] += len << 3) < j) - context->count[1]++; - context->count[1] += (len>>29); - j = (j >> 3) & 63; - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); - } - j = 0; - } - else i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} - - -/* Add padding and return the message digest. */ - -void SHA1Final(unsigned char digest[20], SHA1_CTX* context) -{ -unsigned i; -unsigned char finalcount[8]; -unsigned char c; - -#if 0 /* untested "improvement" by DHR */ - /* Convert context->count to a sequence of bytes - * in finalcount. Second element first, but - * big-endian order within element. - * But we do it all backwards. - */ - unsigned char *fcp = &finalcount[8]; - - for (i = 0; i < 2; i++) - { - u_int32_t t = context->count[i]; - int j; - - for (j = 0; j < 4; t >>= 8, j++) - *--fcp = (unsigned char) t - } -#else - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } -#endif - c = 0200; - SHA1Update(context, &c, 1); - while ((context->count[0] & 504) != 448) { - c = 0000; - SHA1Update(context, &c, 1); - } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) { - digest[i] = (unsigned char) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - /* Wipe variables */ - memset(context, '\0', sizeof(*context)); - memset(&finalcount, '\0', sizeof(finalcount)); -} diff --git a/src/pluto/sha1.h b/src/pluto/sha1.h deleted file mode 100644 index 64b3d2f5d..000000000 --- a/src/pluto/sha1.h +++ /dev/null @@ -1,16 +0,0 @@ -/* -SHA-1 in C -By Steve Reid <steve@edmweb.com> -100% Public Domain -*/ - -typedef struct { - u_int32_t state[5]; - u_int32_t count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - -void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]); -void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len); -void SHA1Final(unsigned char digest[20], SHA1_CTX* context); diff --git a/src/pluto/smallprime.c b/src/pluto/smallprime.c deleted file mode 100644 index 87497d096..000000000 --- a/src/pluto/smallprime.c +++ /dev/null @@ -1,122 +0,0 @@ -/* smallprime.c - List of small primes - * Copyright (C) 1998 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG 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. - * - * GnuPG 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifdef PLUTO -#include <gmp.h> -#include <freeswan.h> -#include "constants.h" -#include "defs.h" -#include "gcryptfix.h" -#else -/* #include <config.h> */ -/* #include <stdio.h> */ -/* #include <stdlib.h> */ -/* #include "util.h" */ -/* #include "types.h" */ -#endif - -/* Note: 2 is not included because it can be tested more easily - * by looking at bit 0. The last entry in this list is marked by a zero - */ -ushort -small_prime_numbers[] = { - 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, - 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, - 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, - 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, - 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, - 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, - 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, - 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, - 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, - 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, - 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, - 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, - 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, - 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, - 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, - 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, - 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, - 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, - 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, - 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, - 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, - 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, - 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, - 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, - 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, - 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, - 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, - 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, - 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, - 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, - 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, - 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, - 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, - 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, - 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, - 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, - 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, - 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, - 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, - 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, - 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, - 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, - 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, - 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, - 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, - 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, - 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, - 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, - 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, - 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, - 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, - 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, - 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, - 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, - 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, - 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, - 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, - 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, - 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, - 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, - 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, - 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, - 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, - 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, - 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, - 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, - 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, - 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, - 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, - 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, - 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, - 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, - 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, - 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, - 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, - 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, - 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, - 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, - 4957, 4967, 4969, 4973, 4987, 4993, 4999, - 0 -}; - - diff --git a/src/pluto/smartcard.c b/src/pluto/smartcard.c index 937c3f93a..7e4452d89 100644 --- a/src/pluto/smartcard.c +++ b/src/pluto/smartcard.c @@ -6,7 +6,7 @@ * Copyright (C) 2005 Michael Joosten * * Copyright (C) 2005 Andreas Steffen - * Hochschule für Technik Rapperswil, Switzerland + * 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 @@ -17,8 +17,6 @@ * 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. - * - * RCSID $Id: smartcard.c 3686 2008-03-28 11:48:14Z martin $ */ #include <stdio.h> @@ -30,7 +28,9 @@ #include <dlfcn.h> #include <freeswan.h> -#include <ipsec_policy.h> + +#include <asn1/asn1.h> +#include <credentials/keys/public_key.h> #include "constants.h" @@ -40,7 +40,6 @@ #endif #include "defs.h" -#include "mp_defs.h" #include "log.h" #include "x509.h" #include "ca.h" @@ -50,7 +49,7 @@ #include "whack.h" #include "fetch.h" -#define DEFAULT_BASE 16 +#define DEFAULT_BASE 16 /* chained list of smartcard records */ static smartcard_t *smartcards = NULL; @@ -59,30 +58,30 @@ static smartcard_t *smartcards = NULL; static int sc_number = 0; const smartcard_t empty_sc = { - NULL , /* next */ - 0 , /* last_load */ - { CERT_NONE, {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 */ + NULL , /* next */ + 0 , /* last_load */ + { CERT_NONE, {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 */ +#ifdef SMARTCARD /* compile with smartcard support */ -#define SCX_MAGIC 0xd00bed00 +#define SCX_MAGIC 0xd00bed00 struct scx_pkcs11_module { - u_int _magic; - void *handle; + u_int _magic; + void *handle; }; typedef struct scx_pkcs11_module scx_pkcs11_module_t; @@ -95,292 +94,292 @@ 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" - }; + "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" - }; + "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" - }; + "CKR_DATA_INVALID", + "CKR_DATA_LEN_RANGE" + }; static const char *const pkcs11_return_name_30[] = { - "CKR_DEVICE_ERROR", - "CKR_DEVICE_MEMORY", - "CKR_DEVICE_REMOVED" - }; + "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" - }; + "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" - }; + "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" - }; + "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" - }; + "CKR_MECHANISM_INVALID", + "CKR_MECHANISM_PARAM_INVALID" + }; static const char *const pkcs11_return_name_80[] = { - "CKR_OBJECT_HANDLE_INVALID" - }; + "CKR_OBJECT_HANDLE_INVALID" + }; static const char *const pkcs11_return_name_90[] = { - "CKR_OPERATION_ACTIVE", - "CKR_OPERATION_NOT_INITIALIZED" - }; + "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" - }; + "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" - }; + "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" - }; + "CKR_SIGNATURE_INVALID", + "CKR_SIGNATURE_LEN_RANGE" + }; static const char *const pkcs11_return_name_D0[] = { - "CKR_TEMPLATE_INCOMPLETE", - "CKR_TEMPLATE_INCONSISTENT" - }; + "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" - }; + "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" - }; + "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" - }; + "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" - }; + "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" - }; + "CKR_RANDOM_SEED_NOT_SUPPORTED", + "CKR_RANDOM_NO_RNG" + }; static const char *const pkcs11_return_name_130[] = { - "CKR_DOMAIN_PARAMS_INVALID" - }; + "CKR_DOMAIN_PARAMS_INVALID" + }; static const char *const pkcs11_return_name_150[] = { - "CKR_BUFFER_TOO_SMALL" - }; + "CKR_BUFFER_TOO_SMALL" + }; static const char *const pkcs11_return_name_160[] = { - "CKR_SAVED_STATE_INVALID" - }; + "CKR_SAVED_STATE_INVALID" + }; static const char *const pkcs11_return_name_170[] = { - "CKR_INFORMATION_SENSITIVE" - }; + "CKR_INFORMATION_SENSITIVE" + }; static const char *const pkcs11_return_name_180[] = { - "CKR_STATE_UNSAVEABLE" - }; + "CKR_STATE_UNSAVEABLE" + }; static const char *const pkcs11_return_name_190[] = { - "CKR_CRYPTOKI_NOT_INITIALIZED", - "CKR_CRYPTOKI_ALREADY_INITIALIZED" - }; + "CKR_CRYPTOKI_NOT_INITIALIZED", + "CKR_CRYPTOKI_ALREADY_INITIALIZED" + }; static const char *const pkcs11_return_name_1A0[] = { - "CKR_MUTEX_BAD", - "CKR_MUTEX_NOT_LOCKED" - }; + "CKR_MUTEX_BAD", + "CKR_MUTEX_NOT_LOCKED" + }; static const char *const pkcs11_return_name_200[] = { - "CKR_FUNCTION_REJECTED" - }; + "CKR_FUNCTION_REJECTED" + }; static const char *const pkcs11_return_name_vendor[] = { - "CKR_VENDOR_DEFINED" - }; + "CKR_VENDOR_DEFINED" + }; static enum_names pkcs11_return_names_vendor = - { CKR_VENDOR_DEFINED, CKR_VENDOR_DEFINED - , pkcs11_return_name_vendor, NULL }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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 }; + { 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}; + { 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}; + { CKR_OK, CKR_CANT_LOCK + , pkcs11_return_name, &pkcs11_return_names_10}; /* * Unload a PKCS#11 module. @@ -390,49 +389,49 @@ static enum_names pkcs11_return_names = static CK_RV scx_unload_pkcs11_module(scx_pkcs11_module_t *mod) { - if (!mod || mod->_magic != SCX_MAGIC) - return CKR_ARGUMENTS_BAD; + if (!mod || mod->_magic != SCX_MAGIC) + return CKR_ARGUMENTS_BAD; - if (dlclose(mod->handle) < 0) - return CKR_FUNCTION_FAILED; + if (dlclose(mod->handle) < 0) + return CKR_FUNCTION_FAILED; - memset(mod, 0, sizeof(*mod)); - pfree(mod); - return CKR_OK; + 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; + 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; + if (name == NULL || *name == '\0') + return NULL; - /* Try to load PKCS#11 library module*/ - handle = dlopen(name, RTLD_NOW); - if (handle == NULL) - return NULL; + /* Try to load PKCS#11 library module*/ + handle = dlopen(name, RTLD_NOW); + if (handle == NULL) + return NULL; - mod = alloc_thing(scx_pkcs11_module_t, "scx_pkcs11_module"); - mod->_magic = SCX_MAGIC; - mod->handle = handle; + 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; + 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; + rv = c_get_function_list(funcs); + if (rv == CKR_OK) + return mod; failed: scx_unload_pkcs11_module(mod); - return NULL; + return NULL; } /* @@ -442,78 +441,78 @@ static bool scx_find_cert_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object , smartcard_t *sc, cert_t *cert) { - size_t hex_len, label_len; - u_char *hex_id = NULL; - chunk_t blob; - x509cert_t *x509cert; - - CK_ATTRIBUTE attr[] = { - { CKA_ID, NULL_PTR, 0L }, - { CKA_LABEL, NULL_PTR, 0L }, - { CKA_VALUE, NULL_PTR, 0L } - }; - - /* initialize the return argument */ - *cert = empty_cert; - - /* 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 FALSE; - } - - pfreeany(sc->label); - - hex_id = alloc_bytes(attr[0].ulValueLen, "hex id"); - hex_len = attr[0].ulValueLen; - sc->label = alloc_bytes(attr[1].ulValueLen + 1, "sc label"); - label_len = attr[1].ulValueLen; - blob.ptr = alloc_bytes(attr[2].ulValueLen, "x509cert blob"); - 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)); - pfree(hex_id); - pfreeany(sc->label); - pfree(blob.ptr); - return FALSE; - } + size_t hex_len, label_len; + u_char *hex_id = NULL; + chunk_t blob; + x509cert_t *x509cert; + + CK_ATTRIBUTE attr[] = { + { CKA_ID, NULL_PTR, 0L }, + { CKA_LABEL, NULL_PTR, 0L }, + { CKA_VALUE, NULL_PTR, 0L } + }; + + /* initialize the return argument */ + *cert = cert_empty; + + /* 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 FALSE; + } + + 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 FALSE; + } - pfreeany(sc->id); + free(sc->id); - /* convert id from hex to ASCII */ - sc->id = alloc_bytes(2*hex_len + 1, " sc id"); - datatot(hex_id, hex_len, 16, sc->id, 2*hex_len + 1); - pfree(hex_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'; + /* safeguard in case the label is not null terminated */ + sc->label[label_len] = '\0'; - /* parse the retrieved cert */ - x509cert = alloc_thing(x509cert_t, "x509cert"); - *x509cert = empty_x509cert; - x509cert->smartcard = TRUE; + /* parse the retrieved cert */ + x509cert = malloc_thing(x509cert_t); + *x509cert = empty_x509cert; + x509cert->smartcard = TRUE; - if (!parse_x509cert(blob, 0, x509cert)) - { - plog("failed to load cert from smartcard, error in X.509 certificate"); - free_x509cert(x509cert); - return FALSE; - } - cert->type = CERT_X509_SIGNATURE; - cert->u.x509 = x509cert; - return TRUE; + if (!parse_x509cert(blob, 0, x509cert)) + { + plog("failed to load cert from smartcard, error in X.509 certificate"); + free_x509cert(x509cert); + return FALSE; + } + cert->type = CERT_X509_SIGNATURE; + cert->u.x509 = x509cert; + return TRUE; } /* @@ -522,96 +521,96 @@ scx_find_cert_object(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object 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; - err_t ugh; - time_t valid_until; - smartcard_t *sc; - x509cert_t *cert; + CK_RV rv; + CK_OBJECT_CLASS class = CKO_CERTIFICATE; + CK_ATTRIBUTE attr[] = {{ CKA_CLASS, &class, sizeof(class) }}; - rv = pkcs11_functions->C_FindObjects(session, &object, 1, &obj_count); + rv = pkcs11_functions->C_FindObjectsInit(session, attr, 1); 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 = alloc_thing(smartcard_t, "smartcard"); - *sc = empty_sc; - sc->any_slot = FALSE; - sc->slot = slot; - - if (!scx_find_cert_object(session, object, sc, &sc->last_cert)) - { - scx_free(sc); - continue; + plog("error in C_FindObjectsInit: %s" + , enum_show(&pkcs11_return_names, rv)); + return; } - 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 */ - cert = sc->last_cert.u.x509; - valid_until = cert->notAfter; - ugh = check_validity(cert, &valid_until); - if (ugh != NULL) - { - plog(" %s", ugh); - free_x509cert(cert); - scx_free(sc); - continue; - } - else + for (;;) { - DBG(DBG_CONTROL, - DBG_log(" certificate is valid") - ) + CK_OBJECT_HANDLE object; + CK_ULONG obj_count = 0; + err_t ugh; + time_t valid_until; + smartcard_t *sc; + x509cert_t *cert; + + 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; + + if (!scx_find_cert_object(session, object, sc, &sc->last_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 */ + cert = sc->last_cert.u.x509; + valid_until = cert->notAfter; + ugh = check_validity(cert, &valid_until); + if (ugh != NULL) + { + plog(" %s", ugh); + free_x509cert(cert); + scx_free(sc); + continue; + } + else + { + DBG(DBG_CONTROL, + DBG_log(" certificate is valid") + ) + } + + sc = scx_add(sc); + + /* put end entity and ca certificates into different chains */ + if (cert->isCA) + { + sc->last_cert.u.x509 = add_authcert(cert, AUTH_CA); + } + else + { + add_x509_public_key(cert, valid_until, DAL_LOCAL); + sc->last_cert.u.x509 = add_x509cert(cert); + } + + share_cert(sc->last_cert); + time(&sc->last_load); } - sc = scx_add(sc); - - /* put end entity and ca certificates into different chains */ - if (cert->isCA) - { - sc->last_cert.u.x509 = add_authcert(cert, AUTH_CA); - } - else + rv = pkcs11_functions->C_FindObjectsFinal(session); + if (rv != CKR_OK) { - add_x509_public_key(cert, valid_until, DAL_LOCAL); - sc->last_cert.u.x509 = add_x509cert(cert); + plog("error in C_FindObjectsFinal: %s" + , enum_show(&pkcs11_return_names, rv)); } - - share_cert(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)); - } } /* @@ -620,74 +619,74 @@ scx_find_cert_objects(CK_SLOT_ID slot, CK_SESSION_HANDLE session) 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 *)alloc_bytes(slot_count * sizeof(CK_SLOT_ID), "slots"); - - 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)); - pfreeany(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); + CK_RV rv; + CK_SLOT_ID_PTR slots = NULL_PTR; + CK_ULONG slot_count = 0; + CK_ULONG i; - if (rv != CKR_OK) + if (!scx_initialized) { - 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; + plog("pkcs11 module not initialized"); + return; } - rv = pkcs11_functions->C_OpenSession(slot - , CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &session); + /* 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("failed to open a session on slot %lu: %s" - , slot, enum_show(&pkcs11_return_names, rv)); - continue; + plog("error in C_GetSlotList: %s", enum_show(&pkcs11_return_names, rv)); + free(slots); + return; } - 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) + /* look in every slot for certificate objects */ + for (i = 0; i < slot_count; i++) { - plog("error in C_CloseSession: %s" - , enum_show(&pkcs11_return_names, rv)); + 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)); + } } - } - pfreeany(slots); + free(slots); } #endif @@ -701,52 +700,52 @@ void scx_init(const char* module, const char *init_args) { #ifdef SMARTCARD - CK_C_INITIALIZE_ARGS args = { .pReserved = (char *)init_args, }; - CK_RV rv; + 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 (scx_initialized) + { + plog("weird - pkcs11 module seems already to be initialized"); + return; + } - if (module == NULL) + if (module == NULL) #ifdef PKCS11_DEFAULT_LIB - module = PKCS11_DEFAULT_LIB; + module = PKCS11_DEFAULT_LIB; #else - { - plog("no pkcs11 module defined"); - return; - } + { + 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(); + 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 } @@ -757,27 +756,27 @@ 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") - ) + 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 } @@ -787,7 +786,7 @@ scx_finalize(void) bool scx_on_smartcard(const char *filename) { - return strncmp(filename, SCX_TOKEN, strlen(SCX_TOKEN)) == 0; + return strneq(filename, SCX_TOKEN, strlen(SCX_TOKEN)); } #ifdef SMARTCARD @@ -795,55 +794,55 @@ scx_on_smartcard(const char *filename) * 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) +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; - } + size_t len; + char buf[BUF_LEN]; + CK_RV rv; + CK_ULONG obj_count = 0; + CK_ULONG attr_count = 1; - 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; - } + CK_ATTRIBUTE attr[] = { + { CKA_CLASS, &class, sizeof(class) }, + { CKA_ID, &buf, 0L } + }; - rv = pkcs11_functions->C_FindObjectsFinal(session); - if (rv != CKR_OK) - { - plog("error in C_FindObjectsFinal: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; - } + 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; + } - return (obj_count != 0); + 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); } /* @@ -852,54 +851,54 @@ scx_pkcs11_find_object( CK_SESSION_HANDLE session, 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)); + 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; - } - 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 @@ -910,74 +909,74 @@ bool scx_establish_context(smartcard_t *sc) { #ifdef SMARTCARD - bool id_found = FALSE; - - if (!scx_initialized) - { - plog("pkcs11 module not initialized"); - return FALSE; - } + bool id_found = 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; + if (!scx_initialized) + { + plog("pkcs11 module not initialized"); + return FALSE; + } - /* read size, always returns CKR_OK ! */ - rv = pkcs11_functions->C_GetSlotList(FALSE, NULL_PTR, &slot_count); + if (sc->session_opened) + { + DBG(DBG_CONTROL | DBG_CRYPT, + DBG_log("pkcs11 session #%ld already open", sc->session) + ) + return TRUE; + } - /* allocate memory for the slots */ - slots = (CK_SLOT_ID *)alloc_bytes(slot_count * sizeof(CK_SLOT_ID), "slots"); + if (!sc->any_slot) + id_found = scx_find_cert_id_in_slot(sc, sc->slot); - rv = pkcs11_functions->C_GetSlotList(FALSE, slots, &slot_count); - if (rv != CKR_OK) + if (!id_found) { - plog("error in C_GetSlotList: %s" - , enum_show(&pkcs11_return_names, rv)); - pfreeany(slots); - return FALSE; - } + 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); + } - /* look in every slot for a certificate with a given object ID */ - for (i = 0; i < slot_count; i++) + if (id_found) { - slot = slots[i]; - id_found = scx_find_cert_id_in_slot(sc, slot); - if (id_found) - break; - } - pfreeany(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; + 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; + plog("warning: SMARTCARD support is deactivated in pluto/Makefile!"); + return FALSE; #endif } @@ -988,41 +987,41 @@ bool scx_login(smartcard_t *sc) { #ifdef SMARTCARD - CK_RV rv; + 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; + } - if (sc->logged_in) - { + 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 already done", sc->session) + DBG_log("pkcs11 session #%ld login successful", sc->session) ) + sc->logged_in = TRUE; 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 @@ -1035,17 +1034,17 @@ scx_login(smartcard_t *sc) 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; + 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 @@ -1057,27 +1056,27 @@ void scx_release_context(smartcard_t *sc) { #ifdef SMARTCARD - CK_RV rv; - - if (!scx_initialized) - return; + CK_RV rv; - if (sc->session_opened) - { - if (sc->logged_in) - scx_logout(sc); + if (!scx_initialized) + return; - 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) - ) - } + 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 } @@ -1088,64 +1087,64 @@ bool scx_load_cert(const char *filename, smartcard_t **scp, cert_t *cert , bool *cached) { -#ifdef SMARTCARD /* compile with smartcard support */ - CK_OBJECT_HANDLE object; +#ifdef SMARTCARD /* compile with smartcard support */ + CK_OBJECT_HANDLE object; - const char *number_slot_id = filename + strlen(SCX_TOKEN); + const char *number_slot_id = filename + strlen(SCX_TOKEN); - smartcard_t *sc = scx_add(scx_parse_number_slot_id(number_slot_id)); + smartcard_t *sc = scx_add(scx_parse_number_slot_id(number_slot_id)); - /* return the smartcard object */ - *scp = sc; + /* return the smartcard object */ + *scp = sc; - /* is there a cached smartcard certificate? */ - *cached = sc->last_cert.type != CERT_NONE - && (time(NULL) - sc->last_load) < SCX_CERT_CACHE_INTERVAL; + /* is there a cached smartcard certificate? */ + *cached = sc->last_cert.type != CERT_NONE + && (time(NULL) - sc->last_load) < SCX_CERT_CACHE_INTERVAL; - if (*cached) - { - *cert = sc->last_cert; - plog(" using cached cert from smartcard #%d (%s, id: %s, label: '%s')" - , sc->number - , scx_print_slot(sc, "") - , sc->id - , sc->label); - return TRUE; - } + if (*cached) + { + *cert = sc->last_cert; + plog(" using cached cert from smartcard #%d (%s, id: %s, label: '%s')" + , sc->number + , scx_print_slot(sc, "") + , sc->id + , sc->label); + return TRUE; + } - if (!scx_establish_context(sc)) - { - scx_release_context(sc); - return FALSE; - } + if (!scx_establish_context(sc)) + { + scx_release_context(sc); + return FALSE; + } - /* find the certificate object */ - if (!scx_pkcs11_find_object(sc->session, &object, CKO_CERTIFICATE, sc->id)) - { - scx_release_context(sc); - return FALSE; - } + /* find the certificate object */ + if (!scx_pkcs11_find_object(sc->session, &object, CKO_CERTIFICATE, sc->id)) + { + scx_release_context(sc); + return FALSE; + } - /* retrieve the certificate object */ - if (!scx_find_cert_object(sc->session, object, sc, cert)) - { - scx_release_context(sc); - return FALSE; - } + /* retrieve the certificate object */ + if (!scx_find_cert_object(sc->session, object, sc, cert)) + { + scx_release_context(sc); + return FALSE; + } - if (!pkcs11_keep_state) - scx_release_context(sc); + 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); + plog(" loaded cert from smartcard #%d (%s, id: %s, label: '%s')" + , sc->number + , scx_print_slot(sc, "") + , sc->id + , sc->label); - return TRUE; + return TRUE; #else - plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!"); - return FALSE; + plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!"); + return FALSE; #endif } @@ -1162,58 +1161,58 @@ scx_load_cert(const char *filename, smartcard_t **scp, cert_t *cert smartcard_t* scx_parse_number_slot_id(const char *number_slot_id) { - int len = strlen(number_slot_id); - smartcard_t *sc = alloc_thing(smartcard_t, "smartcard"); - - /* 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, "key id"); - return sc; + 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; } /* @@ -1223,49 +1222,49 @@ bool scx_verify_pin(smartcard_t *sc) { #ifdef SMARTCARD - CK_RV rv; - - if (!sc->pinpad) - sc->valid = FALSE; + CK_RV rv; + + if (!sc->pinpad) + sc->valid = FALSE; - if (sc->pin.ptr == NULL) - { - plog("unable to verify without PIN"); - return 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; - } + /* 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); + 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; + sc->valid = FALSE; #endif - return sc->valid; + return sc->valid; } /* @@ -1276,105 +1275,105 @@ 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; - } + 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; - 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) + if (!scx_pkcs11_find_object(sc->session, &object, CKO_PRIVATE_KEY, sc->id)) { - plog("error in C_SignInit: %s" - , enum_show(&pkcs11_return_names, rv)); - return FALSE; + plog("unable to find private key with id '%s'", sc->id); + return FALSE; } - rv = pkcs11_functions->C_Sign(sc->session, (CK_BYTE_PTR)in, inlen - , out, &siglen); + rv = pkcs11_functions->C_GetAttributeValue(sc->session, object, attr, 2); 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); + 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") + ) - rv = pkcs11_functions->C_DecryptInit(sc->session, &mech, object); - if (rv != CKR_OK) + if (sign_flag) { - 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; - } + 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; + if (siglen > (CK_ULONG)outlen) + { + plog("signature length (%lu) larger than allocated buffer (%d)" + , siglen, (int)outlen); + return FALSE; + } + return TRUE; #else - return FALSE; + return FALSE; #endif } @@ -1386,132 +1385,146 @@ 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; - } + 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 (!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) - { - RSA_public_key_t rsa; - chunk_t plain_text = {(u_char*)in, inlen}; - chunk_t cipher_text; - - DBG(DBG_CONTROL, - DBG_log("doing RSA encryption in software") - ) - attr[0].pValue = alloc_bytes(attr[0].ulValueLen, "modulus"); - attr[1].pValue = alloc_bytes(attr[1].ulValueLen, "exponent"); - - 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)); - pfree(attr[0].pValue); - pfree(attr[1].pValue); + 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; - } - rsa.k = attr[0].ulValueLen; - n_to_mpz(&rsa.n, attr[0].pValue, attr[0].ulValueLen); - n_to_mpz(&rsa.e, attr[1].pValue, attr[1].ulValueLen); - pfree(attr[0].pValue); - pfree(attr[1].pValue); - - cipher_text = RSA_encrypt(&rsa, plain_text); - free_RSA_public_content(&rsa); - 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; - freeanychunk(cipher_text); - if (!pkcs11_keep_state) + } + + if (!encrypt_flag) + { + plog("public key cannot be used for encryption"); scx_release_context(sc); - return TRUE; + return FALSE; } - else + + /* there must be enough space left for the PKCS#1 v1.5 padding */ + if (inlen > attr[0].ulValueLen - 11) { - 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); + 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, 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; + } + } - *outlen = (size_t)len; - return TRUE; + 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; + return FALSE; #endif } /* @@ -1522,70 +1535,70 @@ 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; - } + 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; + } - 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 (!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; + } - 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); + 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; + } - *outlen = (size_t)len; - return TRUE; + 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; + return FALSE; #endif } @@ -1597,92 +1610,92 @@ 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; + 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 = ""; + const char *number_slot_id = ""; - err_t ugh = ttodata(msg, 0, inbase, inbuf, sizeof(inbuf), &inlen); + 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); + /* 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 = (strncmp(keyid, SCX_TOKEN, strlen(SCX_TOKEN)) == 0) - ? 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; + 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; } /* @@ -1692,32 +1705,32 @@ 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}}; + CK_RV rv; + CK_OBJECT_HANDLE object; + CK_ATTRIBUTE attr[] = {{ CKA_MODULUS, NULL_PTR, 0}}; - if (!sc->logged_in) - return FALSE; + 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; - } + 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 */ + return attr[0].ulValueLen; /*Return key length in bytes */ #else - return 0; + return 0; #endif } @@ -1728,54 +1741,55 @@ bool scx_get_pin(smartcard_t *sc, int whackfd) { #ifdef SMARTCARD - char pin[BUF_LEN]; - int i, n; + 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); + 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) + for (i = 0; i < SCX_MAX_PIN_TRIALS; i++) { - whack_log(RC_LOG_SERIOUS, "read(whackfd) failed"); - return FALSE; + 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 (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)) - { - clonetochunk(sc->pin, pin, strlen(pin), "pin"); - break; - } - - /* wrong pin - we try another round */ - sc->pin = empty_chunk; - } - - if (sc->valid) - whack_log(RC_SUCCESS, "valid PIN"); - else - whack_log(RC_LOG_SERIOUS, "invalid PIN, too many trials"); + 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!"); + sc->valid = FALSE; + whack_log(RC_LOG_SERIOUS, "SMARTCARD support is deactivated in pluto/Makefile!"); #endif - return sc->valid; + return sc->valid; } @@ -1785,13 +1799,13 @@ scx_get_pin(smartcard_t *sc, int whackfd) void scx_free_pin(chunk_t *pin) { - if (pin->ptr != NULL) - { - /* clear pin field in memory */ - memset(pin->ptr, '\0', pin->len); - pfree(pin->ptr); - *pin = empty_chunk; - } + if (pin->ptr != NULL) + { + /* clear pin field in memory */ + memset(pin->ptr, '\0', pin->len); + free(pin->ptr); + *pin = chunk_empty; + } } /* @@ -1800,14 +1814,14 @@ scx_free_pin(chunk_t *pin) void scx_free(smartcard_t *sc) { - if (sc != NULL) - { - scx_release_context(sc); - pfreeany(sc->id); - pfreeany(sc->label); - scx_free_pin(&sc->pin); - pfree(sc); - } + if (sc != NULL) + { + scx_release_context(sc); + free(sc->id); + free(sc->label); + scx_free_pin(&sc->pin); + free(sc); + } } /* release of a smartcard record decreases the count by one @@ -1816,15 +1830,15 @@ scx_free(smartcard_t *sc) 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; - release_cert(sc->last_cert); - scx_free(sc); - } + if (sc != NULL && --sc->count == 0) + { + smartcard_t **pp = &smartcards; + while (*pp != sc) + pp = &(*pp)->next; + *pp = sc->next; + release_cert(sc->last_cert); + scx_free(sc); + } } /* @@ -1833,17 +1847,17 @@ scx_release(smartcard_t *sc) 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); - } + 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 @@ -1852,8 +1866,8 @@ scx_same(smartcard_t *a, smartcard_t *b) void scx_share(smartcard_t *sc) { - if (sc != NULL) - sc->count++; + if (sc != NULL) + sc->count++; } /* @@ -1862,28 +1876,28 @@ scx_share(smartcard_t *sc) 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; + 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; } /* @@ -1892,15 +1906,15 @@ scx_add(smartcard_t *smartcard) smartcard_t* scx_get(x509cert_t *cert) { - smartcard_t *sc = smartcards; - - while (sc != NULL) - { - if (sc->last_cert.u.x509 == cert) - return sc; - sc = sc->next; - } - return NULL; + smartcard_t *sc = smartcards; + + while (sc != NULL) + { + if (sc->last_cert.u.x509 == cert) + return sc; + sc = sc->next; + } + return NULL; } /* @@ -1909,13 +1923,13 @@ scx_get(x509cert_t *cert) char * scx_print_slot(smartcard_t *sc, const char *whitespace) { - char *buf = temporary_cyclic_buffer(); + 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; + if (sc->any_slot) + snprintf(buf, BUF_LEN, "any slot"); + else + snprintf(buf, BUF_LEN, "slot: %s%lu", whitespace, sc->slot); + return buf; } /* @@ -1924,39 +1938,39 @@ scx_print_slot(smartcard_t *sc, const char *whitespace) void scx_list(bool utc) { - smartcard_t *sc = smartcards; - - if (sc != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of Smartcard Objects:"); - whack_log(RC_COMMENT, " "); - } - - while (sc != NULL) - { - whack_log(RC_COMMENT, "%s, #%d, count: %d" - , timetoa(&sc->last_load, utc) - , sc->number - , sc->count); - 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.type == CERT_X509_SIGNATURE) - { - char buf[BUF_LEN]; - - dntoa(buf, BUF_LEN, sc->last_cert.u.x509->subject); - whack_log(RC_COMMENT, " subject: '%s'", buf); - } - sc = sc->next; - } + smartcard_t *sc = smartcards; + + if (sc != NULL) + { + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of Smartcard Objects:"); + whack_log(RC_COMMENT, " "); + } + + while (sc != NULL) + { + whack_log(RC_COMMENT, "%T, #%d, count: %d" + , &sc->last_load, utc + , sc->number + , sc->count); + 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.type == CERT_X509_SIGNATURE) + { + char buf[BUF_LEN]; + + dntoa(buf, BUF_LEN, sc->last_cert.u.x509->subject); + whack_log(RC_COMMENT, " subject: '%s'", buf); + } + sc = sc->next; + } } diff --git a/src/pluto/smartcard.h b/src/pluto/smartcard.h index 69510171c..60a0fccfc 100644 --- a/src/pluto/smartcard.h +++ b/src/pluto/smartcard.h @@ -12,8 +12,6 @@ * 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. - * - * RCSID $Id: smartcard.h 4709 2008-11-27 10:20:25Z martin $ */ #ifndef _SMARTCARD_H @@ -21,19 +19,19 @@ #include "certs.h" -#define SCX_TOKEN "%smartcard" -#define SCX_CERT_CACHE_INTERVAL 60 /* seconds */ -#define SCX_MAX_PIN_TRIALS 3 +#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_NONE = 0, + SC_OP_ENCRYPT = 1, + SC_OP_DECRYPT = 2, + SC_OP_SIGN = 3, } sc_op_t; #endif /* SC_OP_T */ @@ -42,21 +40,21 @@ typedef enum { 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; + 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; @@ -78,17 +76,17 @@ extern bool scx_establish_context(smartcard_t *sc); extern bool scx_login(smartcard_t *sc); extern bool scx_on_smartcard(const char *filename); extern bool scx_load_cert(const char *filename, smartcard_t **scp - , cert_t *cert, bool *cached); + , cert_t *cert, 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); + , 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); + , 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); + , 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); + , 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); diff --git a/src/pluto/spdb.c b/src/pluto/spdb.c index 9d1bf8843..b8f4a3c23 100644 --- a/src/pluto/spdb.c +++ b/src/pluto/spdb.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: spdb.c 3845 2008-04-18 17:00:30Z andreas $ */ #include <stdio.h> @@ -23,7 +21,6 @@ #include <sys/queue.h> #include <freeswan.h> -#include <ipsec_policy.h> #include "constants.h" #include "defs.h" @@ -36,16 +33,14 @@ #include "log.h" #include "spdb.h" #include "whack.h" -#include "sha1.h" -#include "md5.h" -#include "crypto.h" /* requires sha1.h and md5.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, elemsof(x) /* Array Description */ +#define AD(x) x, countof(x) /* Array Description */ #define AD_NULL NULL, 0 /**************** Oakely (main mode) SA database ****************/ @@ -53,7 +48,7 @@ /* array of proposals to be conjoined (can only be one for Oakley) */ static struct db_prop oakley_pc[] = - { { PROTO_ISAKMP, AD_NULL } }; + { { PROTO_ISAKMP, AD_NULL } }; /* array of proposal conjuncts (can only be one) */ @@ -67,131 +62,131 @@ struct db_sa oakley_sadb = { AD(oakley_props) }; /* arrays of attributes for transforms */ static struct db_attr espsha1_attr[] = { - { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 }, - }; + { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 }, + }; static struct db_attr ah_HMAC_SHA1_attr[] = { - { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 }, - }; + { 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) }, - }; + { ESP_3DES, AD(espsha1_attr) }, + }; static struct db_trans esp_trans[] = { - { ESP_3DES, AD_NULL }, - }; + { ESP_3DES, AD_NULL }, + }; #ifdef SUPPORT_ESP_NULL static struct db_trans espnull_trans[] = { - { ESP_NULL, AD(espsha1_attr) }, - }; + { ESP_NULL, AD(espsha1_attr) }, + }; #endif /* SUPPORT_ESP_NULL */ static struct db_trans ah_trans[] = { - { AH_SHA, AD(ah_HMAC_SHA1_attr) }, - }; + { AH_SHA, AD(ah_HMAC_SHA1_attr) }, + }; static struct db_trans ipcomp_trans[] = { - { IPCOMP_DEFLATE, AD_NULL }, - }; + { IPCOMP_DEFLATE, AD_NULL }, + }; /* arrays of proposals to be conjoined */ static struct db_prop ah_pc[] = { - { PROTO_IPSEC_AH, AD(ah_trans) }, - }; + { PROTO_IPSEC_AH, AD(ah_trans) }, + }; #ifdef SUPPORT_ESP_NULL static struct db_prop espnull_pc[] = { - { PROTO_IPSEC_ESP, AD(espnull_trans) }, - }; + { PROTO_IPSEC_ESP, AD(espnull_trans) }, + }; #endif /* SUPPORT_ESP_NULL */ static struct db_prop esp_pc[] = { - { PROTO_IPSEC_ESP, AD(espa_trans) }, - }; + { 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) }, - }; + { PROTO_IPSEC_AH, AD(ah_trans) }, + { PROTO_IPSEC_ESP, AD(esp_trans) }, + }; static struct db_prop compress_pc[] = { - { PROTO_IPCOMP, AD(ipcomp_trans) }, - }; + { PROTO_IPCOMP, AD(ipcomp_trans) }, + }; static struct db_prop ah_compress_pc[] = { - { PROTO_IPSEC_AH, AD(ah_trans) }, - { PROTO_IPCOMP, AD(ipcomp_trans) }, - }; + { 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) }, - }; + { 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) }, - }; + { 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) }, - }; + { 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) }, + { AD(ah_pc) }, #ifdef SUPPORT_ESP_NULL - { AD(espnull_pc) } + { AD(espnull_pc) } #endif - }; + }; static struct db_prop_conj esp_props[] = - { { AD(esp_pc) } }; + { { AD(esp_pc) } }; static struct db_prop_conj ah_esp_props[] = - { { AD(ah_esp_pc) } }; + { { AD(ah_esp_pc) } }; static struct db_prop_conj compress_props[] = { - { AD(compress_pc) }, - }; + { AD(compress_pc) }, + }; static struct db_prop_conj ah_compress_props[] = { - { AD(ah_compress_pc) }, + { AD(ah_compress_pc) }, #ifdef SUPPORT_ESP_NULL - { AD(espnull_compress_pc) } + { AD(espnull_compress_pc) } #endif - }; + }; static struct db_prop_conj esp_compress_props[] = - { { AD(esp_compress_pc) } }; + { { AD(esp_compress_pc) } }; static struct db_prop_conj ah_esp_compress_props[] = - { { AD(ah_esp_compress_pc) } }; + { { 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 */ - }; + { 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 @@ -204,41 +199,41 @@ out_attr(int type , 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; + 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. @@ -251,336 +246,336 @@ out_sa(pb_stream *outs , 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; + 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; + 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++) + /* SA header out */ { - 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[256]=""; - - alg_info_snprint(buf, sizeof (buf), - (struct alg_info *)st->st_connection->alg_info_esp); - DBG_log(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[256]=""; - - alg_info_snprint(buf, sizeof (buf), - (struct alg_info *)st->st_connection->alg_info_ike); - DBG_log(buf); - } - ) - db_ctx = ike_alg_db_new(st->st_connection->alg_info_ike, 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); + struct isakmp_sa sa; - /* 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 FALSE; - *spi_generated = TRUE; - } - if (!out_raw((u_char *)spi_ptr, IPSEC_DOI_SPI_SIZE - , &proposal_pbs, "SPI")) + 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 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; + /* 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); - 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 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 + */ - /* Within tranform: Attributes. */ + for (pcn = 0; pcn != sadb->prop_conj_cnt; pcn++) + { + struct db_prop_conj *pc = &sadb->prop_conjs[pcn]; + int pn; - /* 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) + for (pn = 0; pn != pc->prop_cnt; pn++) { - passert(!oakley_mode); - passert(st->st_pfs_group != &unset_group); - out_attr(GROUP_DESCRIPTION, st->st_pfs_group->group - , attr_desc, attr_val_descs - , &trans_pbs); - } + 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); + } + } - /* 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)) + if (oakley_mode && p->protoid == PROTO_ISAKMP) { - /* 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"); + 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 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 tranform: 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 + out_attr(ENCAPSULATION_MODE #ifdef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT - , NAT_T_ENCAPSULATION_MODE(st, st->st_policy) + , 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) + /* 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); + , 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); } - - close_output_pbs(&trans_pbs); - } - close_output_pbs(&proposal_pbs); + /* end of a conjunction of proposals */ } - /* end of a conjunction of proposals */ - } - close_output_pbs(&sa_pbs); - ret = TRUE; + 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); + if (db_ctx) + db_destroy(db_ctx); #endif - return ret; + return ret; } /* Handle long form of duration attribute. @@ -590,27 +585,27 @@ return_out: 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 -= 1; /* portable way to get to maximum value */ - 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; + 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 -= 1; /* portable way to get to maximum value */ + 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 @@ -621,99 +616,99 @@ decode_long_duration(pb_stream *pbs) */ 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) + , 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 DOI_NOT_SUPPORTED; - } - - /* Situation */ - if (!in_struct(ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) - return 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 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 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 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 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 PAYLOAD_MALFORMED; - } - else - { - loglog(RC_LOG_SERIOUS, "invalid SPI size (%u) in Oakley Proposal" - , (unsigned)proposal->isap_spisize); - return INVALID_SPI; - } - return NOTHING_WRONG; + /* 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 DOI_NOT_SUPPORTED; + } + + /* Situation */ + if (!in_struct(ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) + return 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 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 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 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 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 PAYLOAD_MALFORMED; + } + else + { + loglog(RC_LOG_SERIOUS, "invalid SPI size (%u) in Oakley Proposal" + , (unsigned)proposal->isap_spisize); + return INVALID_SPI; + } + return NOTHING_WRONG; } static struct { - u_int8_t *start; - u_int8_t *cur; - u_int8_t *roof; + u_int8_t *start; + u_int8_t *cur; + u_int8_t *roof; } backup; /* @@ -722,9 +717,9 @@ static struct { void backup_pbs(pb_stream *pbs) { - backup.start = pbs->start; - backup.cur = pbs->cur; - backup.roof = pbs->roof; + backup.start = pbs->start; + backup.cur = pbs->cur; + backup.roof = pbs->roof; } /* @@ -733,9 +728,9 @@ backup_pbs(pb_stream *pbs) void restore_pbs(pb_stream *pbs) { - pbs->start = backup.start; - pbs->cur = backup.cur; - pbs->roof = backup.roof; + pbs->start = backup.start; + pbs->cur = backup.cur; + pbs->roof = backup.roof; } /* @@ -743,90 +738,93 @@ restore_pbs(pb_stream *pbs) */ notification_t parse_isakmp_policy(pb_stream *proposal_pbs - , u_int notrans - , lset_t *policy) + , u_int notrans + , lset_t *policy) { - int last_transnum = -1; + int last_transnum = -1; - *policy = LEMPTY; + *policy = LEMPTY; - while (notrans--) - { - pb_stream trans_pbs; - u_char *attr_start; - size_t attr_len; - struct isakmp_transform trans; + 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 BAD_PROPOSAL_SYNTAX; + if (!in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs)) + return 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 BAD_PROPOSAL_SYNTAX; - } - last_transnum = trans.isat_transnum; + if (trans.isat_transnum <= last_transnum) + { + /* picky, picky, picky */ + loglog(RC_LOG_SERIOUS, "Transform Numbers are not monotonically increasing" + " in Oakley Proposal"); + return 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 INVALID_TRANSFORM_ID; - } + 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 INVALID_TRANSFORM_ID; + } - attr_start = trans_pbs.cur; - attr_len = pbs_left(&trans_pbs); + 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; + /* 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 BAD_PROPOSAL_SYNTAX; + if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs)) + return BAD_PROPOSAL_SYNTAX; - passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); + 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: - *policy |= POLICY_RSASIG; - 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; + 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; + } } - break; - default: - break; - } } - } - DBG(DBG_CONTROL|DBG_PARSING, - DBG_log("preparse_isakmp_policy: peer requests %s authentication" - , prettypolicy(*policy)) - ) - return NOTHING_WRONG; + DBG(DBG_CONTROL|DBG_PARSING, + DBG_log("preparse_isakmp_policy: peer requests %s authentication" + , prettypolicy(*policy)) + ) + return NOTHING_WRONG; } /* @@ -835,22 +833,22 @@ parse_isakmp_policy(pb_stream *proposal_pbs static err_t find_preshared_key(struct state* st) { - err_t ugh = NULL; - struct connection *c = st->st_connection; + err_t ugh = NULL; + struct connection *c = st->st_connection; - if (get_preshared_secret(c) == NULL) - { - char my_id[BUF_LEN], his_id[BUF_LEN]; + if (get_preshared_secret(c) == NULL) + { + char my_id[BUF_LEN], his_id[BUF_LEN]; - idtoa(&c->spd.this.id, my_id, sizeof(my_id)); - if (his_id_was_instantiated(c)) - strcpy(his_id, "%any"); - else - idtoa(&c->spd.that.id, his_id, sizeof(his_id)); - ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'" - , my_id, his_id); - } - return ugh; + idtoa(&c->spd.this.id, my_id, sizeof(my_id)); + if (his_id_was_instantiated(c)) + strcpy(his_id, "%any"); + else + idtoa(&c->spd.that.id, his_id, sizeof(his_id)); + ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'" + , my_id, his_id); + } + return ugh; } /* Parse the body of an ISAKMP SA Payload (i.e. Phase 1 / Main Mode). @@ -864,429 +862,432 @@ find_preshared_key(struct state* st) */ 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) + , pb_stream *proposal_pbs + , struct isakmp_proposal *proposal + , pb_stream *r_sa_pbs + , struct state *st + , bool initiator) { - struct connection *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; - err_t ugh = NULL; /* set to diagnostic when problem detected */ + struct connection *c = st->st_connection; + unsigned no_trans_left; - /* initialize only optional field in ta */ - ta.life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT; /* When this SA expires (seconds) */ + /* for each transform payload... */ + no_trans_left = proposal->isap_notrans; - if (no_trans_left == 0) + for (;;) { - loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload"); - return 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 */ + 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; + err_t ugh = NULL; /* set to diagnostic when problem detected */ - while (pbs_left(&trans_pbs) != 0) - { - struct isakmp_attribute a; - pb_stream attr_pbs; - u_int32_t val; /* room for larger values */ + /* initialize only optional field in ta */ + ta.life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT; /* When this SA expires (seconds) */ - if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs)) - return BAD_PROPOSAL_SYNTAX; + if (no_trans_left == 0) + { + loglog(RC_LOG_SERIOUS, "number of Transform Payloads disagrees with Oakley Proposal Payload"); + return BAD_PROPOSAL_SYNTAX; + } - passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); + in_struct(&trans, &isakmp_isakmp_transform_desc, proposal_pbs, &trans_pbs); + attr_start = trans_pbs.cur; + attr_len = pbs_left(&trans_pbs); - 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 BAD_PROPOSAL_SYNTAX; - } + /* process all the attributes that make up the transform */ - seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK); + while (pbs_left(&trans_pbs) != 0) + { + struct isakmp_attribute a; + pb_stream attr_pbs; + u_int32_t val; /* room for larger values */ - val = a.isaat_lv; + if (!in_struct(&a, &isakmp_oakley_attribute_desc, &trans_pbs, &attr_pbs)) + return BAD_PROPOSAL_SYNTAX; - DBG(DBG_PARSING, - { - enum_names *vdesc = oakley_attr_val_descs - [a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK]; + passert((a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK) < 32); - if (vdesc != NULL) - { - const char *nm = enum_name(vdesc, val); + 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 BAD_PROPOSAL_SYNTAX; + } - if (nm != NULL) - DBG_log(" [%u is %s]", (unsigned)val, nm); - } - }); + seen_attrs |= LELEM(a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK); - switch (a.isaat_af_type) - { - case OAKLEY_ENCRYPTION_ALGORITHM | ISAKMP_ATTR_AF_TV: - if (ike_alg_enc_present(val)) - { - ta.encrypt = val; - ta.encrypter = ike_alg_get_encrypter(val); - ta.enckeylen = ta.encrypter->keydeflen; - } - else - { - ugh = builddiag("%s is not supported" - , enum_show(&oakley_enc_names, val)); - } - break; + val = a.isaat_lv; - case OAKLEY_HASH_ALGORITHM | ISAKMP_ATTR_AF_TV: - if (ike_alg_hash_present(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; + DBG(DBG_PARSING, + { + enum_names *vdesc = oakley_attr_val_descs + [a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK]; - case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV: - { - /* check that authentication method is acceptable */ - lset_t iap = st->st_policy & POLICY_ID_AUTH_MASK; + if (vdesc != NULL) + { + const char *nm = enum_name(vdesc, val); - /* 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); + if (nm != NULL) + DBG_log(" [%u is %s]", (unsigned)val, nm); + } + }); - switch (val) - { - case OAKLEY_PRESHARED_KEY: - if ((iap & POLICY_PSK) == LEMPTY) - { - ugh = "policy does not allow OAKLEY_PRESHARED_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: - /* Accept if policy specifies RSASIG or is default */ - if ((iap & POLICY_RSASIG) == LEMPTY) - { - ugh = "policy does not allow OAKLEY_RSA_SIG authentication"; - } - else - { - ta.auth = OAKLEY_RSA_SIG; - } - break; - case XAUTHInitRSA: - if ((iap & POLICY_XAUTH_RSASIG) == LEMPTY || !xauth_init) + switch (a.isaat_af_type) { - 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"; + 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 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; } - else + + if (ugh != NULL) { - ta.auth = XAUTHRespRSA; + loglog(RC_LOG_SERIOUS, "%s. Attribute %s" + , ugh, enum_show(&oakley_attr_names, a.isaat_af_type)); + break; } - 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 = lookup_group(val); - if (ta.group == NULL) + /* + * ML: at last check for allowed transforms in alg_info_ike + * (ALG_INFO_F_STRICT flag) + */ + if (ugh == NULL) { - ugh = "only OAKLEY_GROUP_MODP1024 and OAKLEY_GROUP_MODP1536 supported"; + 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"; + } } - break; - case OAKLEY_LIFE_TYPE | ISAKMP_ATTR_AF_TV: - switch (val) + if (ugh == NULL) { - 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 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; + /* 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 BAD_PROPOSAL_SYNTAX; + } + } + /* We must have liked this transform. + * Lets finish early and leave. + */ - 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)); + DBG(DBG_PARSING | DBG_CRYPT + , DBG_log("Oakley Transform %u accepted", trans.isat_transnum)); - 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; - } - } + 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; - /* - * 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->group : -1, c->alg_info_ike)) - { - ugh = "OAKLEY proposal refused"; - } - } + /* Situation */ + if (!out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL)) + impossible(); - 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 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 */ + /* Proposal */ #ifdef EMIT_ISAKMP_SPI - r_proposal.isap_spisize = COOKIE_SIZE; + r_proposal.isap_spisize = COOKIE_SIZE; #else - r_proposal.isap_spisize = 0; + 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(); + r_proposal.isap_notrans = 1; + if (!out_struct(&r_proposal, &isakmp_proposal_desc, r_sa_pbs, &r_proposal_pbs)) + impossible(); - /* SPI */ + /* SPI */ #ifdef EMIT_ISAKMP_SPI - if (!out_raw(my_cookie, COOKIE_SIZE, &r_proposal_pbs, "SPI")) - impossible(); - r_proposal.isap_spisize = COOKIE_SIZE; + if (!out_raw(my_cookie, COOKIE_SIZE, &r_proposal_pbs, "SPI")) + impossible(); + r_proposal.isap_spisize = COOKIE_SIZE; #else - /* none (0) */ + /* 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 NOTHING_WRONG; - } + /* Transform */ + r_trans.isat_np = ISAKMP_NEXT_NONE; + if (!out_struct(&r_trans, &isakmp_isakmp_transform_desc, &r_proposal_pbs, &r_trans_pbs)) + impossible(); - /* on to next transform */ - no_trans_left--; + 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); + } - 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 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 BAD_PROPOSAL_SYNTAX; + /* copy over the results */ + st->st_oakley = ta; + return 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 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 BAD_PROPOSAL_SYNTAX; + } } - } - loglog(RC_LOG_SERIOUS, "no acceptable Oakley Transform"); - return NO_PROPOSAL_CHOSEN; + loglog(RC_LOG_SERIOUS, "no acceptable Oakley Transform"); + return NO_PROPOSAL_CHOSEN; } /* Parse the body of an IPsec SA Payload (i.e. Phase 2 / Quick Mode). @@ -1315,14 +1316,14 @@ parse_isakmp_sa_body(u_int32_t ipsecdoisit */ 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 */ + 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 @@ -1331,988 +1332,988 @@ parse_ipsec_transform(struct isakmp_transform *trans , pb_stream *prop_pbs , pb_stream *trans_pbs , struct_desc *trans_desc -, int previous_transnum /* or -1 if none */ +, int previous_transnum /* or -1 if none */ , bool selection , bool is_last , bool is_ipcomp -, struct state *st) /* current state object */ +, struct state *st) /* current state object */ { - lset_t seen_attrs = 0; - lset_t seen_durations = 0; - u_int16_t life_type = 0; - const struct oakley_group_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); + lset_t seen_attrs = 0; + lset_t seen_durations = 0; + u_int16_t life_type = 0; + const struct dh_desc *pfs_group = NULL; - val = a.isaat_lv; + if (!in_struct(trans, trans_desc, prop_pbs, trans_pbs)) + return FALSE; - vdesc = ipsec_attr_val_descs[a.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK]; - if (vdesc != NULL) + if (trans->isat_transnum <= previous_transnum) { - 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)); + loglog(RC_LOG_SERIOUS, "Transform Numbers in Proposal are not monotonically increasing"); 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) + switch (trans->isat_np) { - 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; + case ISAKMP_NEXT_T: + if (is_last) + { + loglog(RC_LOG_SERIOUS, "Proposal Payload has more Transforms than specified"); + return FALSE; + } break; - case SA_LIFE_TYPE_KBYTES: - attrs->life_kilobytes = val; + case ISAKMP_NEXT_NONE: + if (!is_last) + { + loglog(RC_LOG_SERIOUS, "Proposal Payload has fewer Transforms than specified"); + return FALSE; + } break; - default: - bad_case(life_type); - } - break; - case GROUP_DESCRIPTION | ISAKMP_ATTR_AF_TV: - if (is_ipcomp) + 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)) { - /* 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."); + 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; } - pfs_group = lookup_group(val); - if (pfs_group == NULL) + + 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) { - loglog(RC_LOG_SERIOUS, "only OAKLEY_GROUP_MODP1024 and OAKLEY_GROUP_MODP1536 supported for PFS"); - return FALSE; + 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))); } - break; - case ENCAPSULATION_MODE | ISAKMP_ATTR_AF_TV: - ipcomp_inappropriate = FALSE; - switch (val) + + switch (a.isaat_af_type) { - 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 - */ + 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; + return FALSE; #endif - } - attrs->encapsulation = val; - break; - case ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS: + } + 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; + 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: + 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; + 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; + 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; + 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; + 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) + + /* 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) { - loglog(RC_LOG_SERIOUS, "GROUP_DESCRIPTION inconsistent with that of %s in IPsec SA" - , selection? "the Proposal" : "a previous Transform"); - return FALSE; - } - } + if (st->st_pfs_group == &unset_group) + st->st_pfs_group = pfs_group; - 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 (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, ENCAPSULATION_MODE)) - { - if (is_ipcomp) + if (LHAS(seen_attrs, SA_LIFE_DURATION)) { - /* 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; + loglog(RC_LOG_SERIOUS, "SA_LIFE_TYPE IPsec attribute not followed by SA_LIFE_DURATION attribute in message"); + return FALSE; } - else + + if (!LHAS(seen_attrs, ENCAPSULATION_MODE)) { - /* ??? 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; + 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 */ + /* ??? should check for key_len and/or key_rounds if required */ - return TRUE; + 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 */ + 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); -} + pb_stream r_proposal_pbs; + pb_stream r_trans_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 struct connection *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 DOI_NOT_SUPPORTED; - } - - /* Situation */ - if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) - return 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 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 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 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 INVALID_SPI; - } + /* 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(); - /* We store CPI in the low order of a network order + /* 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. */ - 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 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 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 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 INVALID_SPI; - } - - if (!in_raw((u_char *)&next_spi, sizeof(next_spi), &next_proposal_pbs, "SPI")) - return INVALID_SPI; + 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"); + } - /* 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 INVALID_SPI; - } - } + /* Transform */ + r_trans.isat_np = ISAKMP_NEXT_NONE; + if (!out_struct(&r_trans, trans_desc, &r_proposal_pbs, &r_trans_pbs)) + impossible(); - if (next_proposal.isap_notrans == 0) - { - loglog(RC_LOG_SERIOUS, "IPsec Proposal contains no Transforms"); - return BAD_PROPOSAL_SYNTAX; - } + /* 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(); - switch (next_proposal.isap_protoid) - { - case PROTO_IPSEC_AH: - if (ah_seen) - { - loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous AH Proposals"); - return BAD_PROPOSAL_SYNTAX; - } - ah_seen = TRUE; - ah_prop_pbs = next_proposal_pbs; - ah_proposal = next_proposal; - ah_spi = next_spi; - break; + close_output_pbs(&r_trans_pbs); + close_output_pbs(&r_proposal_pbs); +} - case PROTO_IPSEC_ESP: - if (esp_seen) - { - loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous ESP Proposals"); - return BAD_PROPOSAL_SYNTAX; - } - esp_seen = TRUE; - esp_prop_pbs = next_proposal_pbs; - esp_proposal = next_proposal; - esp_spi = next_spi; - break; +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 struct connection *c = st->st_connection; + u_int32_t ipsecdoisit; + pb_stream next_proposal_pbs; - case PROTO_IPCOMP: - if (ipcomp_seen) - { - loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous IPCOMP Proposals"); - return 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 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 BAD_PROPOSAL_SYNTAX; - } + struct isakmp_proposal next_proposal; + ipsec_spi_t next_spi; - if (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs)) - return 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. - */ + bool next_full = TRUE; - if (ah_seen) + /* DOI */ + if (sa->isasa_doi != ISAKMP_DOI_IPSEC) { - 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 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 BAD_PROPOSAL_SYNTAX; + loglog(RC_LOG_SERIOUS, "Unknown or unsupported DOI %s", enum_show(&doi_names, sa->isasa_doi)); + /* XXX Could send notification back */ + return DOI_NOT_SUPPORTED; + } - case AUTH_ALGORITHM_HMAC_MD5: - ok_auth = TRUE; - /* fall through */ - case AUTH_ALGORITHM_KPDK: - ok_transid = AH_MD5; - break; + /* Situation */ + if (!in_struct(&ipsecdoisit, &ipsec_sit_desc, sa_pbs, NULL)) + return SITUATION_NOT_SUPPORTED; - 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_transformid_names, ah_attrs.transid)); - return 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_transformid_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 (ipsecdoisit != SIT_IDENTITY_ONLY) + { + loglog(RC_LOG_SERIOUS, "unsupported IPsec DOI situation (%s)" + , bitnamesof(sit_bit_names, ipsecdoisit)); + /* XXX Could send notification back */ + return SITUATION_NOT_SUPPORTED; } - if (esp_seen) + /* 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 BAD_PROPOSAL_SYNTAX; + + /* for each conjunction of proposals... */ + while (next_full) { - 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 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 */ - } + 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 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 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 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 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 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 INVALID_SPI; + } + + if (!in_raw((u_char *)&next_spi, sizeof(next_spi), &next_proposal_pbs, "SPI")) + return 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 INVALID_SPI; + } + } - 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) + if (next_proposal.isap_notrans == 0) { - loglog(RC_LOG_SERIOUS, "ESP_NULL requires auth algorithm"); - return BAD_PROPOSAL_SYNTAX; + loglog(RC_LOG_SERIOUS, "IPsec Proposal contains no Transforms"); + return BAD_PROPOSAL_SYNTAX; } - if (st->st_policy & POLICY_ENCRYPT) + + switch (next_proposal.isap_protoid) { - 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 */ + case PROTO_IPSEC_AH: + if (ah_seen) + { + loglog(RC_LOG_SERIOUS, "IPsec SA contains two simultaneous AH Proposals"); + return 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 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 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 INVALID_PROTOCOL_ID; } - break; -#endif - default: - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("unsupported ESP Transform %s from %s" - , enum_show(&esp_transformid_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) + /* refill next_proposal */ + if (next_proposal.isap_np == ISAKMP_NEXT_NONE) { - 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 */ + 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 BAD_PROPOSAL_SYNTAX; } - 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 (!in_struct(&next_proposal, &isakmp_proposal_desc, sa_pbs, &next_proposal_pbs)) + return 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 (!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) + if (ah_seen) { - /* ??? This should be an error, but is it? */ - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("AH and ESP transforms disagree about encapsulation; TUNNEL presumed")); + 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 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 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_transformid_names, ah_attrs.transid)); + return 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_transformid_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; } - 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 (esp_seen) + { + int previous_transnum = -1; + int tn; - 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 */ - } + 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 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 - if (!can_do_IPcomp) - { - plog("compression proposed by %s, but KLIPS is not configured with 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 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 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 BAD_PROPOSAL_SYNTAX; + default: + DBG(DBG_CONTROL | DBG_CRYPT + , DBG_log("unsupported ESP Transform %s from %s" + , enum_show(&esp_transformid_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; } - - switch (ipcomp_attrs.transid) + else if (st->st_policy & POLICY_ENCRYPT) { - 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 */ + , 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 */ } - - 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) + else if ((st->st_policy & POLICY_AUTHENTICATE) && !ah_seen) { - /* ??? This should be an error, but is it? */ - DBG(DBG_CONTROL | DBG_CRYPT - , DBG_log("ESP and IPCOMP transforms disagree about encapsulation; TUNNEL presumed")); + 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 */ } - 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; - } + 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 KLIPS is not configured with IPCOMP" + , ip_str(&c->spd.that.host_addr)); + continue; + } - /* Eureka: we liked what we saw -- accept it. */ + if (well_known_cpi != 0 && !ah_seen && !esp_seen) + { + plog("illegal proposal: bare IPCOMP used with well-known CPI"); + return BAD_PROPOSAL_SYNTAX; + } - if (r_sa_pbs != NULL) - { - /* emit what we've accepted */ + 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 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 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; + } - /* Situation */ - if (!out_struct(&ipsecdoisit, &ipsec_sit_desc, r_sa_pbs, NULL)) - impossible(); + /* Eureka: we liked what we saw -- accept it. */ - /* 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); - } + 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 */ + /* 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_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_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; + st->st_ipcomp.present = ipcomp_seen; + if (ipcomp_seen) + st->st_ipcomp.attrs = ipcomp_attrs; - return NOTHING_WRONG; - } + return NOTHING_WRONG; + } - loglog(RC_LOG_SERIOUS, "no acceptable Proposal in IPsec SA"); - return NO_PROPOSAL_CHOSEN; + loglog(RC_LOG_SERIOUS, "no acceptable Proposal in IPsec SA"); + return NO_PROPOSAL_CHOSEN; } diff --git a/src/pluto/spdb.h b/src/pluto/spdb.h index b098e247a..221cc00bb 100644 --- a/src/pluto/spdb.h +++ b/src/pluto/spdb.h @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: spdb.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _SPDB_H @@ -25,39 +23,39 @@ * 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; + 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 */ + 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 */ + 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 */ + 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 - */ + 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 */ @@ -72,38 +70,38 @@ extern struct db_sa ipsec_sadb[1 << 3]; struct state; extern bool out_sa( - pb_stream *outs, - struct db_sa *sadb, - struct state *st, - bool oakley_mode, - u_int8_t np); + 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); + 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 */ + 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? */ + 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 tranform can appear */ - struct state *st); /* current state object */ + 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 tranform can appear */ + struct state *st); /* current state object */ extern void backup_pbs(pb_stream *pbs); extern void restore_pbs(pb_stream *pbs); diff --git a/src/pluto/state.c b/src/pluto/state.c index 5372e86f5..6ce0d50e5 100644 --- a/src/pluto/state.c +++ b/src/pluto/state.c @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: state.c 4924 2009-03-10 21:13:18Z andreas $ */ #include <stdio.h> @@ -28,29 +26,28 @@ #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 "rnd.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 "sha1.h" -#include "md5.h" -#include "crypto.h" /* requires sha1.h and md5.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 */ +u_int16_t pluto_port = IKE_UDP_PORT; /* Pluto's port */ /* * This file has the functions that handle the @@ -79,51 +76,53 @@ u_int16_t pluto_port = IKE_UDP_PORT; /* Pluto's port */ struct msgid_list { - msgid_t msgid; /* network order */ - struct msgid_list *next; + msgid_t msgid; /* network order */ + struct msgid_list *next; }; -bool -reserve_msgid(struct state *isakmp_sa, msgid_t msgid) +bool reserve_msgid(struct state *isakmp_sa, msgid_t msgid) { - struct msgid_list *p; + struct msgid_list *p; - passert(msgid != MAINMODE_MSGID); - passert(IS_ISAKMP_ENCRYPTED(isakmp_sa->st_state)); + 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; + for (p = isakmp_sa->st_used_msgids; p != NULL; p = p->next) + if (p->msgid == msgid) + return FALSE; - p = alloc_thing(struct msgid_list, "msgid"); - p->msgid = msgid; - p->next = isakmp_sa->st_used_msgids; - isakmp_sa->st_used_msgids = p; - return TRUE; + 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) +msgid_t generate_msgid(struct state *isakmp_sa) { - int timeout = 100; /* only try so hard for unique msgid */ - msgid_t msgid; + int timeout = 100; /* only try so hard for unique msgid */ + msgid_t msgid; + rng_t *rng; - passert(IS_ISAKMP_ENCRYPTED(isakmp_sa->st_state)); + passert(IS_ISAKMP_ENCRYPTED(isakmp_sa->st_state)); + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - for (;;) - { - get_rnd_bytes((void *) &msgid, sizeof(msgid)); - if (msgid != 0 && reserve_msgid(isakmp_sa, msgid)) - break; - - if (--timeout == 0) + for (;;) { - plog("gave up looking for unique msgid; using 0x%08lx" - , (unsigned long) msgid); - break; + 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; + } } - } - return msgid; + rng->destroy(rng); + return msgid; } @@ -133,63 +132,61 @@ generate_msgid(struct state *isakmp_sa) static struct state *statetable[STATE_TABLE_SIZE]; -static struct state ** -state_hash(const u_char *icookie, const u_char *rcookie, const ip_address *peer) +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); + 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)); + 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 */ + /* 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 < COOKIE_SIZE; j++) + i = i * 407 + icookie[j] + rcookie[j]; - for (j = 0; j < length; j++) - i = i * 613 + byte_ptr[j]; + for (j = 0; j < length; j++) + i = i * 613 + byte_ptr[j]; - i = i % STATE_TABLE_SIZE; + i = i % STATE_TABLE_SIZE; - DBG(DBG_CONTROL, DBG_log("state hash entry %d", i)); + DBG(DBG_CONTROL, DBG_log("state hash entry %d", i)); - return &statetable[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) +struct state *new_state(void) { - static const struct state blank_state; /* initialized all to zero & NULL */ - static so_serial_t next_so = SOS_FIRST; - struct state *st; - - st = clone_thing(blank_state, "struct state in new_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; + static const struct state blank_state; /* initialized all to zero & NULL */ + 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) +void init_states(void) { - int i; + int i; - for (i = 0; i < STATE_TABLE_SIZE; i++) - statetable[i] = (struct state *) NULL; + for (i = 0; i < STATE_TABLE_SIZE; i++) + statetable[i] = (struct state *) NULL; } /* Find the state object with this serial number. @@ -199,627 +196,619 @@ init_states(void) * 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) +struct state *state_with_serialno(so_serial_t sn) { - if (sn >= SOS_FIRST) - { - struct state *st; - int i; + 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; + 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 begining of list. * Needs cookies, connection, and msgid. */ -void -insert_state(struct state *st) +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); + 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) +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; + /* 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) +void release_whack(struct state *st) { - close_any(st->st_whack_sock); + close_any(st->st_whack_sock); } -/* delete a state object */ -void -delete_state(struct state *st) +/** + * Delete a state object + */ +void delete_state(struct state *st) { - struct connection *const c = st->st_connection; - struct state *old_cur_state = cur_state == st? NULL : cur_state; - - set_cur_state(st); + struct connection *const c = st->st_connection; + struct state *old_cur_state = cur_state == st? NULL : cur_state; - /* If DPD is enabled on this state object, clear any pending events */ - if(st->st_dpd_event != NULL) - delete_dpd_event(st); + set_cur_state(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; - } + /* If DPD is enabled on this state object, clear any pending events */ + if(st->st_dpd_event != NULL) + delete_dpd_event(st); - /* 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); + /* 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; + } - delete_event(st); /* delete any pending timer event */ + /* 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); - /* 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); + delete_event(st); /* delete any pending timer event */ - /* effectively, this deletes any ISAKMP SA that this state represents */ - unhash_state(st); + /* 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); - /* 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); + /* effectively, this deletes any ISAKMP SA that this state represents */ + unhash_state(st); - if (c->newest_ipsec_sa == st->st_serialno) - c->newest_ipsec_sa = SOS_NOBODY; + /* 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_isakmp_sa == st->st_serialno) - c->newest_isakmp_sa = SOS_NOBODY; + if (c->newest_ipsec_sa == st->st_serialno) + c->newest_ipsec_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); + if (c->newest_isakmp_sa == st->st_serialno) + c->newest_isakmp_sa = SOS_NOBODY; - release_whack(st); + 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); - /* from here on we are just freeing RAM */ + release_whack(st); - { - struct msgid_list *p = st->st_used_msgids; + /* from here on we are just freeing RAM */ - while (p != NULL) { - struct msgid_list *q = p; - p = p->next; - pfree(q); + 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); - - if (st->st_sec_in_use) - mpz_clear(&(st->st_sec)); - - pfreeany(st->st_tpacket.ptr); - pfreeany(st->st_rpacket.ptr); - pfreeany(st->st_p1isa.ptr); - pfreeany(st->st_gi.ptr); - pfreeany(st->st_gr.ptr); - pfreeany(st->st_shared.ptr); - pfreeany(st->st_ni.ptr); - pfreeany(st->st_nr.ptr); - pfreeany(st->st_skeyid.ptr); - pfreeany(st->st_skeyid_d.ptr); - pfreeany(st->st_skeyid_a.ptr); - pfreeany(st->st_skeyid_e.ptr); - pfreeany(st->st_enc_key.ptr); - pfreeany(st->st_ah.our_keymat); - pfreeany(st->st_ah.peer_keymat); - pfreeany(st->st_esp.our_keymat); - pfreeany(st->st_esp.peer_keymat); - - pfree(st); + + unreference_key(&st->st_peer_pubkey); + + DESTROY_IF(st->st_dh); + + free(st->st_tpacket.ptr); + free(st->st_rpacket.ptr); + free(st->st_p1isa.ptr); + free(st->st_gi.ptr); + free(st->st_gr.ptr); + free(st->st_shared.ptr); + free(st->st_ni.ptr); + free(st->st_nr.ptr); + free(st->st_skeyid.ptr); + free(st->st_skeyid_d.ptr); + free(st->st_skeyid_a.ptr); + free(st->st_skeyid_e.ptr); + free(st->st_enc_key.ptr); + 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(struct connection *c) +bool states_use_connection(struct connection *c) { - /* are there any states still using it? */ - struct state *st = NULL; - int i; + /* 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; + 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; + return FALSE; } -/* - * delete all states that were created for a given connection. +/** + * 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(struct connection *c, bool relations) +void delete_states_by_connection(struct connection *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++) + 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++) { - struct state *st; + int i; - /* For each state in the hash chain... */ - for (st = statetable[i]; st != NULL; ) - { - struct state *this = st; + /* 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 */ + 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; + 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; + 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; + 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; + 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; + + 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) +/** + * 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) +void delete_states_by_peer(ip_address *peer) { - char peerstr[ADDRTOT_BUF]; - int i; - - addrtot(peer, 0, peerstr, sizeof(peerstr)); + char peerstr[ADDRTOT_BUF]; + int i; - /* For each hash chain... */ - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - struct state *st; + addrtot(peer, 0, peerstr, sizeof(peerstr)); - /* For each state in the hash chain... */ - for (st = statetable[i]; st != NULL; ) + /* For each hash chain... */ + for (i = 0; i < STATE_TABLE_SIZE; i++) { - struct state *this = st; - struct spd_route *sr; - struct connection *c = this->st_connection; - - st = st->st_hashchain_next; /* before this is deleted */ + struct state *st; - /* ??? 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)) + /* For each state in the hash chain... */ + for (st = statetable[i]; st != NULL; ) { - 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 */ + struct state *this = st; + struct spd_route *sr; + struct connection *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 *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; - -# define clone_chunk(ch, name) \ - clonetochunk(nst->ch, st->ch.ptr, st->ch.len, name) - - clone_chunk(st_skeyid_d, "st_skeyid_d in duplicate_state"); - clone_chunk(st_skeyid_a, "st_skeyid_a in duplicate_state"); - clone_chunk(st_skeyid_e, "st_skeyid_e in duplicate_state"); - clone_chunk(st_enc_key, "st_enc_key in duplicate_state"); - -# undef clone_chunk - - return nst; + 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); + 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; + 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 /*network order*/ msgid) +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) - && memcmp(icookie, st->st_icookie, COOKIE_SIZE) == 0 - && memcmp(rcookie, st->st_rcookie, COOKIE_SIZE) == 0 - && 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))); + struct state *st = *state_hash(icookie, rcookie, peer); - return st; + 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 +/** + * 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) +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 - && memcmp(st->st_tpacket.ptr, packet, packet_len) == 0) - return st; + int i; + struct state *st; - return NULL; + 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 *find_phase2_state_to_delete(const struct state *p1st, + u_int8_t protoid, ipsec_spi_t spi, + bool *bogus) { - struct state *st; - int i; + 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) + *bogus = FALSE; + for (i = 0; i < STATE_TABLE_SIZE; i++) { - 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) + for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) { - if (pr->attrs.spi == spi) - return st; - if (pr->our_spi == spi) - *bogus = TRUE; + 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; + return NULL; } -/* Find newest Phase 1 negotiation state object for suitable for connection c +/** + * Find newest Phase 1 negotiation state object for suitable for connection c */ -struct state * -find_phase1_state(const struct connection *c, lset_t ok_states) +struct state *find_phase1_state(const struct connection *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; + 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) +void state_eroute_usage(ip_subnet *ours, ip_subnet *his, unsigned long count, + time_t nw) { - struct state *st; - int i; + struct state *st; + int i; - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) + for (i = 0; i < STATE_TABLE_SIZE; i++) { - struct connection *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) + for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) { - st->st_outbound_count = count; - st->st_outbound_time = nw; + struct connection *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; + } } - 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); - }); + 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) +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 struct connection *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); %s in %lds%s%s%s%s" - , st->st_serialno - , c->name, inst - , enum_name(&state_names, st->st_state) - , state_story[st->st_state - STATE_MAIN_R0] - , enum_name(&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; \ - } \ - } + /* what the heck is interesting about a state? */ + const struct connection *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 - STATE_MAIN_R0] + , 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)) + { -# 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, ")"); \ - } \ - } + 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; \ + } \ + } - *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(NULL); +# 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, ")"); \ + } \ + } - 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); - } + *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(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); + } #ifdef KLIPS - 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"); + 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"); #endif - snprintf(state_buf2, state_buf2_len - , "#%lu: \"%s\"%s%s" - , st->st_serialno - , c->name, inst - , buf); + snprintf(state_buf2, state_buf2_len + , "#%lu: \"%s\"%s%s" + , st->st_serialno + , c->name, inst + , buf); -# undef add_said -# undef add_sa_info - } +# undef add_said +# undef add_sa_info + } } /* @@ -831,82 +820,80 @@ void fmt_state(bool all, struct state *st, time_t n * isakmp_sa (XXX probably wrong) * */ -static int -state_compare(const void *a, const void *b) +static int state_compare(const void *a, const void *b) { - const struct state *sap = *(const struct state *const *)a; - struct connection *ca = sap->st_connection; - const struct state *sbp = *(const struct state *const *)b; - struct connection *cb = sbp->st_connection; + const struct state *sap = *(const struct state *const *)a; + struct connection *ca = sap->st_connection; + const struct state *sbp = *(const struct state *const *)b; + struct connection *cb = sbp->st_connection; - /* DBG_log("comparing %s to %s", ca->name, cb->name); */ + /* DBG_log("comparing %s to %s", ca->name, cb->name); */ - return connection_compare(ca, cb); + return connection_compare(ca, cb); } -void -show_states_status(bool all, const char *name) +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; + time_t n = now(); + int i; + char state_buf[LOG_WIDTH]; + char state_buf2[LOG_WIDTH]; + int count; + struct state **array; - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) + /* make count of states */ + count = 0; + for (i = 0; i < STATE_TABLE_SIZE; i++) { - if (name == NULL || streq(name, st->st_connection->name)) - count++; - } - } + struct state *st; - /* build the array */ - array = alloc_bytes(sizeof(struct state *)*count, "state array"); - 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++; + } + } - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) + /* build the array */ + array = malloc(sizeof(struct state *)*count); + count = 0; + for (i = 0; i < STATE_TABLE_SIZE; i++) { - if (name == NULL || streq(name, st->st_connection->name)) - array[count++]=st; + 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); + /* sort it! */ + qsort(array, count, sizeof(struct state *), state_compare); - /* now print sorted results */ - for (i = 0; i < count; i++) - { - struct state *st; + /* now print sorted results */ + for (i = 0; i < count; i++) + { + struct state *st; - st = array[i]; + 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); + 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 */ + /* 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 */ - pfree(array); + /* free the array */ + free(array); } /* Given that we've used up a range of unused CPI's, @@ -915,49 +902,48 @@ show_states_status(bool all, const char *name) * If we can't find one easily, choose 0 (a bad SPI, * no matter what order) indicating failure. */ -void -find_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi) +void find_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi) { - int tries = 0; - cpi_t base = *latest_cpi; - cpi_t closest; - int i; + int tries = 0; + cpi_t base = *latest_cpi; + cpi_t closest; + int i; startover: - closest = ~0; /* not close at all */ - for (i = 0; i < STATE_TABLE_SIZE; i++) - { - struct state *st; - - for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) + closest = ~0; /* not close at all */ + for (i = 0; i < STATE_TABLE_SIZE; i++) { - if (st->st_ipcomp.present) - { - cpi_t c = ntohl(st->st_ipcomp.our_spi) - base; + struct state *st; - if (c < closest) + for (st = statetable[i]; st != NULL; st = st->st_hashchain_next) { - if (c == 0) - { - /* oops: next spot is occupied; start over */ - if (++tries == 20) + if (st->st_ipcomp.present) { - /* FAILURE */ - *latest_cpi = *first_busy_cpi = 0; - return; + cpi_t c = ntohl(st->st_ipcomp.our_spi) - base; + + if (c < closest) + { + if (c == 0) + { + /* oops: next spot is occupied; start over */ + if (++tries == 20) + { + /* FAILURE */ + *latest_cpi = *first_busy_cpi = 0; + return; + } + base++; + if (base > IPCOMP_LAST_NEGOTIATED) + base = IPCOMP_FIRST_NEGOTIATED; + goto startover; /* really a tail call */ + } + closest = c; + } } - base++; - if (base > IPCOMP_LAST_NEGOTIATED) - base = IPCOMP_FIRST_NEGOTIATED; - goto startover; /* really a tail call */ - } - closest = c; } - } } - } - *latest_cpi = base; /* base is first in next free range */ - *first_busy_cpi = closest + base; /* and this is the roof */ + *latest_cpi = base; /* base is first in next free range */ + *first_busy_cpi = closest + base; /* and this is the roof */ } /* Muck with high-order 16 bits of this SPI in order to make @@ -968,38 +954,42 @@ startover: * 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) +ipsec_spi_t uniquify_his_cpi(ipsec_spi_t cpi, struct state *st) { - int tries = 0; - int i; + 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 */ - get_rnd_bytes((u_char *)&cpi, 2); - - /* 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; + /* network order makes first two bytes our target */ + rng->get_bytes(rng, 2, (u_char *)&cpi); - for (s = statetable[i]; s != NULL; s = s->st_hashchain_next) + /* 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++) { - 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) - return 0; /* FAILURE */ - goto startover; - } + 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; + } + } } - } - return cpi; + rng->destroy(rng); + return cpi; } /* diff --git a/src/pluto/state.h b/src/pluto/state.h index 220dce341..a059c52b4 100644 --- a/src/pluto/state.h +++ b/src/pluto/state.h @@ -1,6 +1,7 @@ /* 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 @@ -11,15 +12,14 @@ * 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. - * - * RCSID $Id: state.h 3252 2007-10-06 21:24:50Z andreas $ */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <time.h> -#include <gmp.h> /* GNU MP library */ + +#include <crypto/diffie_hellman.h> #include "connections.h" @@ -40,10 +40,10 @@ * than specified by draft-jenkins-ipsec-rekeying-06.txt. */ -typedef u_int32_t msgid_t; /* Network order! */ +typedef u_int32_t msgid_t; /* Network order! */ #define MAINMODE_MSGID ((msgid_t) 0) -struct state; /* forward declaration of tag */ +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); @@ -54,17 +54,17 @@ extern msgid_t generate_msgid(struct state *isakmp_sa); * 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 oakley_group_desc *group; /* Oakley group */ - time_t life_seconds; /* When this SA expires (seconds) */ - u_int32_t life_kilobytes; /* When this SA is exhausted (kilobytes) */ + 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 */ + u_int16_t prf; /* Pseudo Random Function */ #endif }; @@ -74,28 +74,28 @@ struct oakley_trans_attrs { * 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; + 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; + 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; + 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 @@ -107,135 +107,133 @@ struct ipsec_proto_info { */ struct state { - so_serial_t st_serialno; /* serial number (for seniority) */ - so_serial_t st_clonedfrom; /* serial number of parent */ + 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 */ + struct connection *st_connection; /* connection for this SA */ - int st_whack_sock; /* fd for our Whack TCP socket. - * Single copy: close when freeing struct. - */ + 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 msg_digest *st_suspended_md; /* suspended state-transition */ - struct oakley_trans_attrs st_oakley; + struct oakley_trans_attrs st_oakley; - struct ipsec_proto_info st_ah; - struct ipsec_proto_info st_esp; - struct ipsec_proto_info st_ipcomp; + struct ipsec_proto_info st_ah; + struct ipsec_proto_info st_esp; + struct ipsec_proto_info st_ipcomp; #ifdef KLIPS - ipsec_spi_t st_tunnel_in_spi; /* KLUDGE */ - ipsec_spi_t st_tunnel_out_spi; /* KLUDGE */ + ipsec_spi_t st_tunnel_in_spi; /* KLUDGE */ + ipsec_spi_t st_tunnel_out_spi; /* KLUDGE */ #endif - const struct oakley_group_desc *st_pfs_group; /* group for Phase 2 PFS */ + 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; + u_int32_t st_doi; /* Domain of Interpretation */ + u_int32_t st_situation; - lset_t st_policy; /* policy for IPsec SA */ + lset_t st_policy; /* policy for IPsec SA */ - msgid_t st_msgid; /* MSG-ID from header. Network Order! */ + 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 */ + /* 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 */ + 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 */ + 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 */ + 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; + /* 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 */ + 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; + /* 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 */ - u_int8_t st_sec_in_use; /* bool: does st_sec hold a value */ - MP_INT st_sec; /* Our local 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 */ + 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 u_int16_t pluto_port; /* Pluto's port */ extern bool states_use_connection(struct connection *c); @@ -247,27 +245,27 @@ 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); + , 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); + *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 void find_my_cpi_gap(cpi_t *latest_cpi, cpi_t *first_busy_cpi); 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); + , 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); diff --git a/src/pluto/timer.c b/src/pluto/timer.c index aea293098..ecbee740f 100644 --- a/src/pluto/timer.c +++ b/src/pluto/timer.c @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: timer.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdio.h> @@ -26,36 +24,39 @@ #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 "ipsec_doi.h" /* needs demux.h and state.h */ #include "kernel.h" #include "server.h" #include "log.h" -#include "rnd.h" #include "timer.h" #include "whack.h" #include "nat_traversal.h" -/* monotonic version of time(3) */ -time_t -now(void) +/** + * monotonic version of time(3) + */ +time_t now(void) { - static time_t delta = 0 - , last_time = 0; - time_t n = time((time_t)NULL); - - passert(n != (time_t)-1); - if (last_time > n) - { - plog("time moved backwards %ld seconds", (long)(last_time - n)); - delta += last_time - n; - } - last_time = n; - return n + delta; + static time_t delta = 0 + , last_time = 0; + time_t n = time((time_t)NULL); + + passert(n != (time_t)-1); + if (last_time > n) + { + plog("time moved backwards %ld seconds", (long)(last_time - n)); + delta += last_time - n; + } + last_time = n; + return n + delta; } /* This file has the event handling routines. Events are @@ -66,467 +67,495 @@ now(void) 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) +void event_schedule(enum event_type type, time_t tm, struct state *st) { - struct event *ev = alloc_thing(struct event, "struct event in event_schedule()"); - - 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) + 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) { - passert(st->st_dpd_event == NULL); - st->st_dpd_event = ev; + ev->ev_next = evlist; + evlist = ev; } else { - passert(st->st_event == NULL); - st->st_event = ev; - } - } + struct event *evt; - DBG(DBG_CONTROL, - if (st == NULL) - DBG_log("inserting event %s, timeout in %lu seconds" - , enum_show(&timer_event_names, type), (unsigned long)tm); - else - DBG_log("inserting event %s, timeout in %lu seconds for #%lu" - , enum_show(&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 %s" - , enum_show(&timer_event_names, evt->ev_type)); - else - DBG_log("event added after event %s for #%lu" - , enum_show(&timer_event_names, evt->ev_type) - , evt->ev_state->st_serialno)); + 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; - } + ev->ev_next = evt->ev_next; + evt->ev_next = ev; + } +} + +/** + * Generate the secret value for responder cookies, and + * schedule an event for refresh. + */ +void init_secret(void) +{ + rng_t *rng; + + rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); + 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); } -/* +/** * Handle the first event on the list. */ -void -handle_timer_event(void) +void handle_timer_event(void) { - time_t tm; - struct event *ev = evlist; - int type; - struct state *st; - struct connection *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, %s)" - , (unsigned long)tm, (unsigned long)ev->ev_time - , enum_show(&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 %s in %ld seconds" - , enum_show(&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) + time_t tm; + struct event *ev = evlist; + int type; + struct state *st; + struct connection *c = NULL; + ip_address peer; + + if (ev == (struct event *) NULL) /* Just paranoid */ { - passert(st->st_dpd_event == ev); - st->st_dpd_event = NULL; + DBG(DBG_CONTROL, DBG_log("empty event list, yet we're called")); + return; } - else + + type = ev->ev_type; + st = ev->ev_state; + + tm = now(); + + if (tm < ev->ev_time) { - passert(st->st_event == ev); - st->st_event = NULL; + 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; } - 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; -#ifdef KLIPS - case EVENT_SHUNT_SCAN: - passert(st == NULL); - scan_proc_shunts(); - break; -#endif + evlist = evlist->ev_next; /* Ok, we'll handle this event */ - 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) + 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) { - 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); + passert(st->st_dpd_event == ev); + st->st_dpd_event = NULL; } - else + 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"; + 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; - default: + +#ifdef KLIPS + case EVENT_SHUNT_SCAN: + passert(st == NULL); + scan_proc_shunts(); 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 */ +#endif - 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); + case EVENT_LOG_DAILY: + daily_log_event(); + break; - if (st->st_whack_sock != NULL_FD) + 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. + */ { - /* Release whack because the observer will get bored. */ - loglog(RC_COMMENT, "%s, but releasing whack" - , story); - release_pending_whacks(st, story); + 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); + } } - else + break; + + case EVENT_SA_REPLACE: + case EVENT_SA_REPLACE_IF_USED: { - /* no whack: just log to syslog */ - plog("%s", story); + 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); } - 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; + break; - case EVENT_SA_EXPIRE: - { - const char *satype; - so_serial_t latest; + 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; - if (IS_PHASE1(st->st_state)) - { - satype = "ISAKMP"; - latest = c->newest_isakmp_sa; - } - else - { - satype = "IPsec"; - latest = c->newest_ipsec_sa; - } + 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); + } - 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 %s" - , enum_show(&timer_event_names, type)); - } - - pfree(ev); - reset_cur_state(); + 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) +long next_event(void) { - time_t tm; + time_t tm; + + if (evlist == (struct event *) NULL) + return -1; - if (evlist == (struct event *) NULL) - return -1; + tm = now(); - 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)); - DBG(DBG_CONTROL, - if (evlist->ev_state == NULL) - DBG_log("next event %s in %ld seconds" - , enum_show(&timer_event_names, evlist->ev_type) - , (long)evlist->ev_time - (long)tm); + if (evlist->ev_time - tm <= 0) + return 0; else - DBG_log("next event %s in %ld seconds for #%lu" - , enum_show(&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; + return evlist->ev_time - tm; } -/* +/** * Delete an event. */ -void -delete_event(struct state *st) +void delete_event(struct state *st) { - if (st->st_event != (struct event *) NULL) - { - struct event **ev; - - for (ev = &evlist; ; ev = &(*ev)->ev_next) + if (st->st_event != (struct event *) NULL) { - if (*ev == NULL) - { - DBG(DBG_CONTROL, DBG_log("event %s to be deleted not found", - enum_show(&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; - pfree(st->st_event); - st->st_event = (struct event *) NULL; - - break; - } + 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) +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 %s to be deleted not found", - enum_show(&timer_event_names, st->st_dpd_event->ev_type))); - break; - } - if ((*ev) == st->st_dpd_event) - { - *ev = (*ev)->ev_next; - pfree(st->st_dpd_event); - st->st_dpd_event = (struct event *) NULL; - break; - } - } - } + 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 index c772d37f9..322aeba6a 100644 --- a/src/pluto/timer.h +++ b/src/pluto/timer.h @@ -10,20 +10,18 @@ * 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. - * - * RCSID $Id: timer.h 3252 2007-10-06 21:24:50Z andreas $ */ -extern time_t now(void); /* careful version of time(2) */ +extern time_t now(void); /* careful version of time(2) */ -struct state; /* forward declaration */ +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 */ + 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); @@ -32,3 +30,5 @@ 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 void init_secret(void); diff --git a/src/pluto/vendor.c b/src/pluto/vendor.c index f957bf39b..ff145eb38 100644 --- a/src/pluto/vendor.c +++ b/src/pluto/vendor.c @@ -1,5 +1,6 @@ /* 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 @@ -10,8 +11,6 @@ * 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. - * - * RCSID $Id: vendor.c 5052 2009-03-30 03:47:14Z andreas $ */ #include <stdlib.h> @@ -20,10 +19,12 @@ #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 "md5.h" #include "connections.h" #include "packet.h" #include "demux.h" @@ -88,232 +89,226 @@ #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; - const char *vid; - u_int vid_len; + 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 }, + { VID_##id, VID_MD5HASH, str, descr, { NULL, 0 } }, #define DEC_MD5_VID(id,str) \ - { VID_##id, VID_MD5HASH, str, NULL, NULL, 0 }, -#define DEC_FSWAN_VID(id,str,descr) \ - { VID_##id, VID_FSWAN_HASH, str, descr, NULL, 0 }, + { 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}, - - /* - * Openswan - */ - DEC_FSWAN_VID(OPENSWAN2, "Openswan 2.2.0", "Openswan 2.2.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 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_4_0_7, "strongSwan 4.0.7") - DEC_MD5_VID(STRONGSWAN_4_0_6, "strongSwan 4.0.6") - DEC_MD5_VID(STRONGSWAN_4_0_5, "strongSwan 4.0.5") - DEC_MD5_VID(STRONGSWAN_4_0_4, "strongSwan 4.0.4") - DEC_MD5_VID(STRONGSWAN_4_0_3, "strongSwan 4.0.3") - DEC_MD5_VID(STRONGSWAN_4_0_2, "strongSwan 4.0.2") - DEC_MD5_VID(STRONGSWAN_4_0_1, "strongSwan 4.0.1") - DEC_MD5_VID(STRONGSWAN_4_0_0, "strongSwan 4.0.0") - - DEC_MD5_VID(STRONGSWAN_2_8_8, "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") - DEC_MD5_VID(STRONGSWAN_2_7_3, "strongSwan 2.7.3") - DEC_MD5_VID(STRONGSWAN_2_7_2, "strongSwan 2.7.2") - DEC_MD5_VID(STRONGSWAN_2_7_1, "strongSwan 2.7.1") - DEC_MD5_VID(STRONGSWAN_2_7_0, "strongSwan 2.7.0") - DEC_MD5_VID(STRONGSWAN_2_6_4, "strongSwan 2.6.4") - DEC_MD5_VID(STRONGSWAN_2_6_3, "strongSwan 2.6.3") - DEC_MD5_VID(STRONGSWAN_2_6_2, "strongSwan 2.6.2") - DEC_MD5_VID(STRONGSWAN_2_6_1, "strongSwan 2.6.1") - DEC_MD5_VID(STRONGSWAN_2_6_0, "strongSwan 2.6.0") - DEC_MD5_VID(STRONGSWAN_2_5_7, "strongSwan 2.5.7") - DEC_MD5_VID(STRONGSWAN_2_5_6, "strongSwan 2.5.6") - DEC_MD5_VID(STRONGSWAN_2_5_5, "strongSwan 2.5.5") - DEC_MD5_VID(STRONGSWAN_2_5_4, "strongSwan 2.5.4") - DEC_MD5_VID(STRONGSWAN_2_5_3, "strongSwan 2.5.3") - DEC_MD5_VID(STRONGSWAN_2_5_2, "strongSwan 2.5.2") - DEC_MD5_VID(STRONGSWAN_2_5_1, "strongSwan 2.5.1") - DEC_MD5_VID(STRONGSWAN_2_5_0, "strongSwan 2.5.0") - DEC_MD5_VID(STRONGSWAN_2_4_4, "strongSwan 2.4.4") - DEC_MD5_VID(STRONGSWAN_2_4_3, "strongSwan 2.4.3") - DEC_MD5_VID(STRONGSWAN_2_4_2, "strongSwan 2.4.2") - DEC_MD5_VID(STRONGSWAN_2_4_1, "strongSwan 2.4.1") - DEC_MD5_VID(STRONGSWAN_2_4_0, "strongSwan 2.4.0") - DEC_MD5_VID(STRONGSWAN_2_3_2, "strongSwan 2.3.2") - DEC_MD5_VID(STRONGSWAN_2_3_1, "strongSwan 2.3.1") - DEC_MD5_VID(STRONGSWAN_2_3_0, "strongSwan 2.3.0") - DEC_MD5_VID(STRONGSWAN_2_2_2, "strongSwan 2.2.2") - DEC_MD5_VID(STRONGSWAN_2_2_1, "strongSwan 2.2.1") - DEC_MD5_VID(STRONGSWAN_2_2_0, "strongSwan 2.2.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 } + /* 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 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_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_4_0_7, "strongSwan 4.0.7") + DEC_MD5_VID(STRONGSWAN_4_0_6, "strongSwan 4.0.6") + DEC_MD5_VID(STRONGSWAN_4_0_5, "strongSwan 4.0.5") + DEC_MD5_VID(STRONGSWAN_4_0_4, "strongSwan 4.0.4") + DEC_MD5_VID(STRONGSWAN_4_0_3, "strongSwan 4.0.3") + DEC_MD5_VID(STRONGSWAN_4_0_2, "strongSwan 4.0.2") + DEC_MD5_VID(STRONGSWAN_4_0_1, "strongSwan 4.0.1") + DEC_MD5_VID(STRONGSWAN_4_0_0, "strongSwan 4.0.0") + + 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") + DEC_MD5_VID(STRONGSWAN_2_7_3, "strongSwan 2.7.3") + DEC_MD5_VID(STRONGSWAN_2_7_2, "strongSwan 2.7.2") + DEC_MD5_VID(STRONGSWAN_2_7_1, "strongSwan 2.7.1") + DEC_MD5_VID(STRONGSWAN_2_7_0, "strongSwan 2.7.0") + DEC_MD5_VID(STRONGSWAN_2_6_4, "strongSwan 2.6.4") + DEC_MD5_VID(STRONGSWAN_2_6_3, "strongSwan 2.6.3") + DEC_MD5_VID(STRONGSWAN_2_6_2, "strongSwan 2.6.2") + DEC_MD5_VID(STRONGSWAN_2_6_1, "strongSwan 2.6.1") + DEC_MD5_VID(STRONGSWAN_2_6_0, "strongSwan 2.6.0") + DEC_MD5_VID(STRONGSWAN_2_5_7, "strongSwan 2.5.7") + DEC_MD5_VID(STRONGSWAN_2_5_6, "strongSwan 2.5.6") + DEC_MD5_VID(STRONGSWAN_2_5_5, "strongSwan 2.5.5") + DEC_MD5_VID(STRONGSWAN_2_5_4, "strongSwan 2.5.4") + DEC_MD5_VID(STRONGSWAN_2_5_3, "strongSwan 2.5.3") + DEC_MD5_VID(STRONGSWAN_2_5_2, "strongSwan 2.5.2") + DEC_MD5_VID(STRONGSWAN_2_5_1, "strongSwan 2.5.1") + DEC_MD5_VID(STRONGSWAN_2_5_0, "strongSwan 2.5.0") + DEC_MD5_VID(STRONGSWAN_2_4_4, "strongSwan 2.4.4") + DEC_MD5_VID(STRONGSWAN_2_4_3, "strongSwan 2.4.3") + DEC_MD5_VID(STRONGSWAN_2_4_2, "strongSwan 2.4.2") + DEC_MD5_VID(STRONGSWAN_2_4_1, "strongSwan 2.4.1") + DEC_MD5_VID(STRONGSWAN_2_4_0, "strongSwan 2.4.0") + DEC_MD5_VID(STRONGSWAN_2_3_2, "strongSwan 2.3.2") + DEC_MD5_VID(STRONGSWAN_2_3_1, "strongSwan 2.3.1") + DEC_MD5_VID(STRONGSWAN_2_3_0, "strongSwan 2.3.0") + DEC_MD5_VID(STRONGSWAN_2_2_2, "strongSwan 2.2.2") + DEC_MD5_VID(STRONGSWAN_2_2_1, "strongSwan 2.2.1") + DEC_MD5_VID(STRONGSWAN_2_2_0, "strongSwan 2.2.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 } } }; @@ -321,239 +316,211 @@ static const char _hexdig[] = "0123456789abcdef"; static int _vid_struct_init = 0; -void -init_vendorid(void) +void init_vendorid(void) { - struct vid_struct *vid; - MD5_CTX ctx; - int i; + 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 = strdup(vid->data); - vid->vid_len = strlen(vid->data); - } - else if (vid->flags & VID_MD5HASH) + for (vid = _vid_tab; vid->id; vid++) { - /** VendorID is a string to hash with MD5 **/ - char *vidm = malloc(MD5_DIGEST_SIZE); - - vid->vid = vidm; - if (vidm) - { - MD5Init(&ctx); - MD5Update(&ctx, (const u_char *)vid->data, strlen(vid->data)); - MD5Final(vidm, &ctx); - vid->vid_len = MD5_DIGEST_SIZE; - } - } - else if (vid->flags & VID_FSWAN_HASH) - { - /** FreeS/WAN 2.00+ specific hash **/ -#define FSWAN_VID_SIZE 12 - unsigned char hash[MD5_DIGEST_SIZE]; - char *vidm = malloc(FSWAN_VID_SIZE); - - vid->vid = vidm; - if (vidm) - { - MD5Init(&ctx); - MD5Update(&ctx, (const u_char *)vid->data, strlen(vid->data)); - MD5Final(hash, &ctx); - vidm[0] = 'O'; - vidm[1] = 'E'; -#if FSWAN_VID_SIZE - 2 <= MD5_DIGEST_SIZE - memcpy(vidm + 2, hash, FSWAN_VID_SIZE - 2); -#else - memcpy(vidm + 2, hash, MD5_DIGEST_SIZE); - memset(vidm + 2 + MD5_DIGEST_SIZE, '\0', - FSWAN_VID_SIZE - 2 - MD5_DIGEST_SIZE); -#endif - for (i = 2; i < FSWAN_VID_SIZE; i++) + 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) { - vidm[i] &= 0x7f; - vidm[i] |= 0x40; + /** Find something to display **/ + vid->descr = vid->data; } - vid->vid_len = FSWAN_VID_SIZE; - } } + hasher->destroy(hasher); + _vid_struct_init = 1; +} + +void free_vendorid(void) +{ + struct vid_struct *vid; - if (vid->descr == NULL) + for (vid = _vid_tab; vid->id; vid++) { - /** Find something to display **/ - vid->descr = vid->data; + if (vid->flags & (VID_STRING | VID_MD5HASH | VID_FSWAN_HASH)) + { + free(vid->vid.ptr); + } } - } - _vid_struct_init = 1; } -static void -handle_known_vendorid (struct msg_digest *md -, const char *vidstr, size_t len, struct vid_struct *vid) +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 supports OpenPGP certificates */ - case VID_OPENPGP: - md->openpgp = 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; + char vid_dump[128]; + bool vid_useful = FALSE; + size_t i, j; + + switch (vid->id) { + /* Remote side supports OpenPGP certificates */ + case VID_OPENPGP: + md->openpgp = 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; } - 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) + + if (vid->flags & VID_SUBSTRING_DUMPHEXA) { - md->nat_traversal_vid = vid->id; - vid_useful = TRUE; + /* 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]; + } } - 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++) + else if (vid->flags & VID_SUBSTRING_DUMPASCII) { - vid_dump[i] = _hexdig[(vidstr[j] >> 4) & 0xF]; - vid_dump[i+1] = _hexdig[vidstr[j] & 0xF]; + /* 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 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++) + else { - vid_dump[i] = (isprint(vidstr[i])) ? vidstr[i] : '.'; + /* Dump description (descr) */ + snprintf(vid_dump, sizeof(vid_dump), "%s", + vid->descr ? vid->descr : ""); } - } - 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); + + 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) +void handle_vendorid (struct msg_digest *md, const char *vid, size_t len) { - struct vid_struct *pvid; + struct vid_struct *pvid; - if (!_vid_struct_init) - init_vendorid(); + if (!_vid_struct_init) + init_vendorid(); - /* - * Find known VendorID in _vid_tab - */ - for (pvid = _vid_tab; pvid->id; pvid++) - { - if (pvid->vid && vid && pvid->vid_len && len) + /* + * Find known VendorID in _vid_tab + */ + for (pvid = _vid_tab; pvid->id; pvid++) { - if (pvid->vid_len == len) - { - if (memcmp(pvid->vid, vid, len) == 0) + if (pvid->vid.ptr && vid && pvid->vid.len && len) { - handle_known_vendorid(md, vid, len, pvid); - return; + 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; + } + } } - } - else if ((pvid->vid_len < len) && (pvid->flags & VID_SUBSTRING)) - { - if (memcmp(pvid->vid, vid, pvid->vid_len) == 0) - { - 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; + /* + * Unknown VendorID. Log the beginning. + */ + { + char log_vid[2*MAX_LOG_VID_LEN+1]; + size_t i; - memset(log_vid, 0, sizeof(log_vid)); + 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]; + 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) ? "..." : ""); } - 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) +bool out_vendorid (u_int8_t np, pb_stream *outs, enum known_vendorid vid) { - struct vid_struct *pvid; + struct vid_struct *pvid; - if (!_vid_struct_init) - init_vendorid(); + if (!_vid_struct_init) + init_vendorid(); - for (pvid = _vid_tab; pvid->id && pvid->id != vid; pvid++); + for (pvid = _vid_tab; pvid->id && pvid->id != vid; pvid++); - if (pvid->id != vid) - return STF_INTERNAL_ERROR; /* not found */ - if (!pvid->vid) - return STF_INTERNAL_ERROR; /* not initialized */ + 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, pvid->vid_len, "V_ID"); + 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 index 2c8c24b34..164c1aa6d 100644 --- a/src/pluto/vendor.h +++ b/src/pluto/vendor.h @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: vendor.h 5052 2009-03-30 03:47:14Z andreas $ */ #ifndef _VENDOR_H_ @@ -19,140 +17,144 @@ 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_OPENSWAN2 = 31, - VID_NCP_SERVER = 32, - VID_NCP_CLIENT = 33, - VID_VISTA_AUTHIP = 34, - VID_VISTA_AUTHIP2 = 35, - VID_VISTA_AUTHIP3 = 36, + 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 = 37, - VID_STRONGSWAN_2_2_0 = 38, - VID_STRONGSWAN_2_2_1 = 39, - VID_STRONGSWAN_2_2_2 = 40, - VID_STRONGSWAN_2_3_0 = 41, - VID_STRONGSWAN_2_3_1 = 42, - VID_STRONGSWAN_2_3_2 = 43, - VID_STRONGSWAN_2_4_0 = 44, - VID_STRONGSWAN_2_4_1 = 45, - VID_STRONGSWAN_2_4_2 = 46, - VID_STRONGSWAN_2_4_3 = 47, - VID_STRONGSWAN_2_4_4 = 48, - VID_STRONGSWAN_2_5_0 = 49, - VID_STRONGSWAN_2_5_1 = 50, - VID_STRONGSWAN_2_5_2 = 51, - VID_STRONGSWAN_2_5_3 = 52, - VID_STRONGSWAN_2_5_4 = 53, - VID_STRONGSWAN_2_5_5 = 54, - VID_STRONGSWAN_2_5_6 = 55, - VID_STRONGSWAN_2_5_7 = 56, - VID_STRONGSWAN_2_6_0 = 57, - VID_STRONGSWAN_2_6_1 = 58, - VID_STRONGSWAN_2_6_2 = 59, - VID_STRONGSWAN_2_6_3 = 60, - VID_STRONGSWAN_2_6_4 = 61, - VID_STRONGSWAN_2_7_0 = 62, - VID_STRONGSWAN_2_7_1 = 63, - VID_STRONGSWAN_2_7_2 = 64, - VID_STRONGSWAN_2_7_3 = 65, - VID_STRONGSWAN_2_8_0 = 66, - VID_STRONGSWAN_2_8_1 = 67, - VID_STRONGSWAN_2_8_2 = 68, - VID_STRONGSWAN_2_8_3 = 69, - VID_STRONGSWAN_2_8_4 = 70, - VID_STRONGSWAN_2_8_5 = 71, - VID_STRONGSWAN_2_8_6 = 72, - VID_STRONGSWAN_2_8_7 = 73, - VID_STRONGSWAN_2_8_8 = 74, - VID_STRONGSWAN_2_8_9 = 75, + VID_STRONGSWAN = 37, + VID_STRONGSWAN_2_2_0 = 38, + VID_STRONGSWAN_2_2_1 = 39, + VID_STRONGSWAN_2_2_2 = 40, + VID_STRONGSWAN_2_3_0 = 41, + VID_STRONGSWAN_2_3_1 = 42, + VID_STRONGSWAN_2_3_2 = 43, + VID_STRONGSWAN_2_4_0 = 44, + VID_STRONGSWAN_2_4_1 = 45, + VID_STRONGSWAN_2_4_2 = 46, + VID_STRONGSWAN_2_4_3 = 47, + VID_STRONGSWAN_2_4_4 = 48, + VID_STRONGSWAN_2_5_0 = 49, + VID_STRONGSWAN_2_5_1 = 50, + VID_STRONGSWAN_2_5_2 = 51, + VID_STRONGSWAN_2_5_3 = 52, + VID_STRONGSWAN_2_5_4 = 53, + VID_STRONGSWAN_2_5_5 = 54, + VID_STRONGSWAN_2_5_6 = 55, + VID_STRONGSWAN_2_5_7 = 56, + VID_STRONGSWAN_2_6_0 = 57, + VID_STRONGSWAN_2_6_1 = 58, + VID_STRONGSWAN_2_6_2 = 59, + VID_STRONGSWAN_2_6_3 = 60, + VID_STRONGSWAN_2_6_4 = 61, + VID_STRONGSWAN_2_7_0 = 62, + VID_STRONGSWAN_2_7_1 = 63, + VID_STRONGSWAN_2_7_2 = 64, + VID_STRONGSWAN_2_7_3 = 65, + VID_STRONGSWAN_2_8_0 = 66, + VID_STRONGSWAN_2_8_1 = 67, + VID_STRONGSWAN_2_8_2 = 68, + VID_STRONGSWAN_2_8_3 = 69, + VID_STRONGSWAN_2_8_4 = 70, + VID_STRONGSWAN_2_8_5 = 71, + VID_STRONGSWAN_2_8_6 = 72, + VID_STRONGSWAN_2_8_7 = 73, + VID_STRONGSWAN_2_8_8 = 74, + VID_STRONGSWAN_2_8_9 = 75, - VID_STRONGSWAN_4_0_0 = 80, - VID_STRONGSWAN_4_0_1 = 81, - VID_STRONGSWAN_4_0_2 = 82, - VID_STRONGSWAN_4_0_3 = 83, - VID_STRONGSWAN_4_0_4 = 84, - VID_STRONGSWAN_4_0_5 = 85, - VID_STRONGSWAN_4_0_6 = 86, - VID_STRONGSWAN_4_0_7 = 87, - 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_0_0 = 80, + VID_STRONGSWAN_4_0_1 = 81, + VID_STRONGSWAN_4_0_2 = 82, + VID_STRONGSWAN_4_0_3 = 83, + VID_STRONGSWAN_4_0_4 = 84, + VID_STRONGSWAN_4_0_5 = 85, + VID_STRONGSWAN_4_0_6 = 86, + VID_STRONGSWAN_4_0_7 = 87, + 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_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_3_0 =116, + VID_STRONGSWAN_4_3_1 =117, /* 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, + 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 + 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); diff --git a/src/pluto/virtual.c b/src/pluto/virtual.c index 4a81ee283..2067bde01 100644 --- a/src/pluto/virtual.c +++ b/src/pluto/virtual.c @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: virtual.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <freeswan.h> @@ -35,9 +33,9 @@ #define F_VIRTUAL_HOST 32 struct virtual_t { - unsigned short flags; - unsigned short n_net; - ip_subnet net[0]; + unsigned short flags; + unsigned short n_net; + ip_subnet net[0]; }; static ip_subnet *private_net_ok=NULL, *private_net_ko=NULL; @@ -49,123 +47,119 @@ static unsigned short private_net_ok_len=0, private_net_ko_len=0; */ static bool _read_subnet(const char *src, size_t len, ip_subnet *dst, ip_subnet *dstko, - bool *isok) + bool *isok) { - bool ok; - int af; - - if ((len > 4) && (strncmp(src, "%v4:", 4)==0)) - { - af = AF_INET; - } - else if ((len > 4) && (strncmp(src, "%v6:", 4)==0)) - { - af = AF_INET6; - } - else - { - return FALSE; - } + 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; + ok = (src[4] != '!'); + src += ok ? 4 : 5; + len -= ok ? 4 : 5; - if (!len) - return FALSE; - if (!ok && !dstko) - return FALSE; + if (!len) + return FALSE; + if (!ok && !dstko) + return FALSE; - passert ( ((ok)?(dst):(dstko))!=NULL ); + passert ( ((ok)?(dst):(dstko))!=NULL ); - if (ttosubnet(src, len, af, ((ok)?(dst):(dstko)))) - { - return FALSE; - } - if (isok) - *isok = ok; - return TRUE; + 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 *)alloc_bytes( - (private_net_ok_len*sizeof(ip_subnet)), - "private_net_ok subnets"); - } - if (private_net_ko_len) - { - private_net_ko = (ip_subnet *)alloc_bytes( - (private_net_ko_len*sizeof(ip_subnet)), - "private_net_ko subnets"); - } - 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"); - pfreeany(private_net_ok); - private_net_ok = NULL; - pfreeany(private_net_ko); - private_net_ko = NULL; - } - else - { - /** Fill **/ - str = private_list; - i_ok = 0; - i_ko = 0; + const char *next, *str=private_list; + unsigned short ign = 0, i_ok, i_ko; + ip_subnet sub; + bool ok; - while (str) - { + /** 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, - &(private_net_ok[i_ok]), &(private_net_ko[i_ko]), &ok)) + 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) { - if (ok) - i_ok++; - else - i_ko++; + 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; + } } - str = *next ? next+1 : NULL; - } } - } - else - loglog(RC_LOG_SERIOUS, - "%d bad entries in virtual_private - none loaded", ign); + else + loglog(RC_LOG_SERIOUS, + "%d bad entries in virtual_private - none loaded", ign); } /** @@ -188,147 +182,146 @@ init_virtual_ip(const char *private_list) struct virtual_t *create_virtual(const struct connection *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; + 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 (!string || string[0] == '\0') + return NULL; - if (strlen(string) >= 6 && strncmp(string,"vhost:",6) == 0) - { - flags |= F_VIRTUAL_HOST; - str += 6; - } - else if (strlen(string) >= 5 && strncmp(string,"vnet:",5) == 0) - 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 && strncmp(str, "%no", 3) == 0) - flags |= F_VIRTUAL_NO; -#if 0 - else if (next-str == 4 && strncmp(str, "%ike", 4) == 0) - flags |= F_VIRTUAL_IKE_CONFIG; - else if (next-str == 5 && strncmp(str, "%dhcp", 5) == 0) - flags |= F_VIRTUAL_DHCP; -#endif - else if (next-str == 5 && strncmp(str, "%priv", 5) == 0) - flags |= F_VIRTUAL_PRIVATE; - else if (next-str == 4 && strncmp(str, "%all", 4) == 0) - flags |= F_VIRTUAL_ALL; - else if (_read_subnet(str, next-str, &sub, NULL, NULL)) + if (strlen(string) >= 6 && strneq(string,"vhost:",6)) { - n_net++; - if (!first_net) - first_net = str; + flags |= F_VIRTUAL_HOST; + str += 6; } + else if (strlen(string) >= 5 && strneq(string,"vnet:",5)) + str += 5; else - goto fail; - - str = *next ? next+1 : NULL; - } - - v = (struct virtual_t *)alloc_bytes( - sizeof(struct virtual_t) + (n_net*sizeof(ip_subnet)), - "virtual description"); - if (!v) goto fail; - - v->flags = flags; - v->n_net = n_net; - if (n_net && first_net) - { + goto fail; + /** - * Save subnets in newly allocated struct + * Parse string : fill flags & count subnets */ - for (str = first_net, i = 0; str && *str; ) + while ((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; + 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; } - } - return v; + 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; + 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); + return ((that->virt)?TRUE:FALSE); } bool is_virtual_connection(const struct connection *c) { - return ((c->spd.that.virt)?TRUE:FALSE); + 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 len) { - unsigned short i; + unsigned short i; - if (!list || !len) - return FALSE; + if (!list || !len) + return FALSE; - for (i = 0; i < len; i++) - { - if (subnetinsubnet(peer_net, &(list[i]))) - return TRUE; - } - return FALSE; + for (i = 0; i < len; i++) + { + if (subnetinsubnet(peer_net, &(list[i]))) + return TRUE; + } + return FALSE; } bool is_virtual_net_allowed(const struct connection *c, const ip_subnet *peer_net, - const ip_address *his_addr) + const ip_address *his_addr) { - if (c->spd.that.virt == NULL) - return FALSE; + 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_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_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->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; - } + 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; + return FALSE; } diff --git a/src/pluto/virtual.h b/src/pluto/virtual.h index 9fe9bdd8d..e64407c81 100644 --- a/src/pluto/virtual.h +++ b/src/pluto/virtual.h @@ -10,8 +10,6 @@ * 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. - * - * RCSID $Id: virtual.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _VIRTUAL_IP_H @@ -20,12 +18,12 @@ extern void init_virtual_ip(const char *private_list); extern struct virtual_t *create_virtual(const struct connection *c, - const char *string); + 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); + const ip_subnet *peer_net, const ip_address *his_addr); #endif /* _VIRTUAL_IP_H */ diff --git a/src/pluto/x509.c b/src/pluto/x509.c index c61de6edc..0953f18f5 100644 --- a/src/pluto/x509.c +++ b/src/pluto/x509.c @@ -2,7 +2,7 @@ * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss * Copyright (C) 2002 Mario Strasser - * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * 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 @@ -13,8 +13,6 @@ * 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. - * - * RCSID $Id: x509.c 3252 2007-10-06 21:24:50Z andreas $ */ #include <stdlib.h> @@ -26,16 +24,16 @@ #include <sys/types.h> #include <freeswan.h> -#include <ipsec_policy.h> + +#include <asn1/asn1.h> +#include <asn1/asn1_parser.h> +#include <asn1/oid.h> +#include <crypto/hashers/hasher.h> #include "constants.h" #include "defs.h" -#include "mp_defs.h" #include "log.h" #include "id.h" -#include "asn1.h" -#include <asn1/oid.h> -#include "pkcs1.h" #include "x509.h" #include "crl.h" #include "ca.h" @@ -44,298 +42,243 @@ #include "whack.h" #include "fetch.h" #include "ocsp.h" -#include "sha1.h" - -/* chained lists of X.509 end certificates */ +/** + * Chained lists of X.509 end certificates + */ static x509cert_t *x509certs = NULL; -/* ASN.1 definition of a basicConstraints extension */ - +/** + * ASN.1 definition of a basicConstraints extension + */ static const asn1Object_t basicConstraintsObjects[] = { - { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "CA", ASN1_BOOLEAN, ASN1_DEF | - ASN1_BODY }, /* 1 */ - { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT | - ASN1_BODY }, /* 2 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */ + { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "CA", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 1 */ + { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; - #define BASIC_CONSTRAINTS_CA 1 -#define BASIC_CONSTRAINTS_ROOF 4 - -/* ASN.1 definition of time */ -static const asn1Object_t timeObjects[] = { - { 0, "utcTime", ASN1_UTCTIME, ASN1_OPT | - ASN1_BODY }, /* 0 */ - { 0, "end opt", ASN1_EOC, ASN1_END }, /* 1 */ - { 0, "generalizeTime", ASN1_GENERALIZEDTIME, ASN1_OPT | - ASN1_BODY }, /* 2 */ - { 0, "end opt", ASN1_EOC, ASN1_END } /* 3 */ -}; - -#define TIME_UTC 0 -#define TIME_GENERALIZED 2 -#define TIME_ROOF 4 - -/* ASN.1 definition of a keyIdentifier */ - -static const asn1Object_t keyIdentifierObjects[] = { - { 0, "keyIdentifier", ASN1_OCTET_STRING, ASN1_BODY } /* 0 */ -}; - -/* ASN.1 definition of a authorityKeyIdentifier extension */ - -static const asn1Object_t authorityKeyIdentifierObjects[] = { - { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT | - ASN1_OBJ }, /* 1 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ - { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT | - ASN1_OBJ }, /* 3 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ - { 1, "authorityCertSerialNumber", ASN1_CONTEXT_S_2, ASN1_OPT | - ASN1_BODY }, /* 5 */ - { 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */ +/** + * ASN.1 definition of a authorityKeyIdentifier extension + */ +static const asn1Object_t authKeyIdentifierObjects[] = { + { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT|ASN1_BODY }, /* 1 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ + { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_OBJ }, /* 3 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ + { 1, "authorityCertSerialNumber", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 5 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; - -#define AUTH_KEY_ID_KEY_ID 1 +#define AUTH_KEY_ID_KEY_ID 1 #define AUTH_KEY_ID_CERT_ISSUER 3 #define AUTH_KEY_ID_CERT_SERIAL 5 -#define AUTH_KEY_ID_ROOF 7 - -/* ASN.1 definition of a authorityInfoAccess extension */ -static const asn1Object_t authorityInfoAccessObjects[] = { - { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */ - { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */ - { 0, "end loop", ASN1_EOC, ASN1_END } /* 4 */ +/** + * ASN.1 definition of a authorityInfoAccess extension + */ +static const asn1Object_t authInfoAccessObjects[] = { + { 0, "authorityInfoAccess", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "accessDescription", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "accessMethod", ASN1_OID, ASN1_BODY }, /* 2 */ + { 2, "accessLocation", ASN1_EOC, ASN1_RAW }, /* 3 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 4 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; - #define AUTH_INFO_ACCESS_METHOD 2 #define AUTH_INFO_ACCESS_LOCATION 3 -#define AUTH_INFO_ACCESS_ROOF 5 - -/* ASN.1 definition of a extendedKeyUsage extension */ +/** + * ASN.1 definition of a extendedKeyUsage extension + */ static const asn1Object_t extendedKeyUsageObjects[] = { - { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ + { 0, "extendedKeyUsage", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "keyPurposeID", ASN1_OID, ASN1_BODY }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; - #define EXT_KEY_USAGE_PURPOSE_ID 1 -#define EXT_KEY_USAGE_ROOF 3 - -/* ASN.1 definition of generalNames */ +/** + * ASN.1 definition of generalNames + */ static const asn1Object_t generalNamesObjects[] = { - { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "generalName", ASN1_EOC, ASN1_RAW }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */ + { 0, "generalNames", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "generalName", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; - #define GENERAL_NAMES_GN 1 -#define GENERAL_NAMES_ROOF 3 - -/* ASN.1 definition of generalName */ +/** + * ASN.1 definition of generalName + */ static const asn1Object_t generalNameObjects[] = { - { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT | - ASN1_BODY }, /* 0 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */ - { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT | - ASN1_BODY }, /* 2 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */ - { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT | - ASN1_BODY }, /* 4 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ - { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT | - ASN1_BODY }, /* 6 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ - { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT | - ASN1_BODY }, /* 8 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT | - ASN1_BODY }, /* 10 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ - { 0, "uniformResourceIdentifier", ASN1_CONTEXT_S_6, ASN1_OPT | - ASN1_BODY }, /* 12 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */ - { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT | - ASN1_BODY }, /* 14 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */ - { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT | - ASN1_BODY }, /* 16 */ - { 0, "end choice", ASN1_EOC, ASN1_END } /* 17 */ + { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */ + { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */ + { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ + { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ + { 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT|ASN1_BODY }, /* 8 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ + { 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT|ASN1_BODY }, /* 10 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ + { 0, "URI", ASN1_CONTEXT_S_6, ASN1_OPT|ASN1_BODY }, /* 12 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */ + { 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT|ASN1_BODY }, /* 14 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */ + { 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT|ASN1_BODY }, /* 16 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 17 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; - -#define GN_OBJ_OTHER_NAME 0 -#define GN_OBJ_RFC822_NAME 2 -#define GN_OBJ_DNS_NAME 4 -#define GN_OBJ_X400_ADDRESS 6 +#define GN_OBJ_OTHER_NAME 0 +#define GN_OBJ_RFC822_NAME 2 +#define GN_OBJ_DNS_NAME 4 +#define GN_OBJ_X400_ADDRESS 6 #define GN_OBJ_DIRECTORY_NAME 8 #define GN_OBJ_EDI_PARTY_NAME 10 -#define GN_OBJ_URI 12 -#define GN_OBJ_IP_ADDRESS 14 +#define GN_OBJ_URI 12 +#define GN_OBJ_IP_ADDRESS 14 #define GN_OBJ_REGISTERED_ID 16 -#define GN_OBJ_ROOF 18 - -/* ASN.1 definition of otherName */ +/** + * ASN.1 definition of otherName + */ static const asn1Object_t otherNameObjects[] = { - {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */ - {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY } /* 1 */ + {0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */ + {0, "value", ASN1_CONTEXT_C_0, ASN1_BODY }, /* 1 */ + {0, "exit", ASN1_EOC, ASN1_EXIT } }; - #define ON_OBJ_ID_TYPE 0 #define ON_OBJ_VALUE 1 -#define ON_OBJ_ROOF 2 - -/* ASN.1 definition of crlDistributionPoints */ +/** + * ASN.1 definition of crlDistributionPoints + */ static const asn1Object_t crlDistributionPointsObjects[] = { - { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT | - ASN1_LOOP }, /* 2 */ - { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT | - ASN1_OBJ }, /* 3 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ - { 3, "nameRelativeToCRLIssuer", ASN1_CONTEXT_C_1, ASN1_OPT | - ASN1_BODY }, /* 5 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ - { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT | - ASN1_BODY }, /* 8 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ - { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT | - ASN1_BODY }, /* 10 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */ + { 0, "crlDistributionPoints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "DistributionPoint", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "distributionPoint", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 2 */ + { 3, "fullName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 3 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ + { 3, "nameRelToCRLIssuer",ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 5 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ + { 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */ + { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_BODY }, /* 10 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */ + { 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; - #define CRL_DIST_POINTS_FULLNAME 3 -#define CRL_DIST_POINTS_ROOF 13 - -/* ASN.1 definition of an X.509v3 certificate */ +/** + * ASN.1 definition of an X.509v3 x509_cert + */ static const asn1Object_t certObjects[] = { - { 0, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ - { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */ - { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */ - { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ - { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */ - { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */ - { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */ - { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ - { 2, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */ - { 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */ - { 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 13 */ - { 4, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 14 */ - { 5, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 15 */ - { 5, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 16 */ - { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 17 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 18 */ - { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 19 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ - { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 21 */ - { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 22 */ - { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 23 */ - { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 24 */ - { 5, "critical", ASN1_BOOLEAN, ASN1_DEF | - ASN1_BODY }, /* 25 */ - { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 26 */ - { 3, "end loop", ASN1_EOC, ASN1_END }, /* 27 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 28 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 29 */ - { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 30 */ + { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */ + { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ + { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */ + { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */ + { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ + { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */ + { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */ + { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */ + { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ + { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_RAW }, /* 11 */ + { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ + { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 14 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ + { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 16 */ + { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 17 */ + { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 18 */ + { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 19 */ + { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 20 */ + { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 21 */ + { 3, "end loop", ASN1_EOC, ASN1_END }, /* 22 */ + { 2, "end opt", ASN1_EOC, ASN1_END }, /* 23 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 24 */ + { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 25 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; - -#define X509_OBJ_CERTIFICATE 0 -#define X509_OBJ_TBS_CERTIFICATE 1 -#define X509_OBJ_VERSION 3 -#define X509_OBJ_SERIAL_NUMBER 4 -#define X509_OBJ_SIG_ALG 5 -#define X509_OBJ_ISSUER 6 -#define X509_OBJ_NOT_BEFORE 8 -#define X509_OBJ_NOT_AFTER 9 -#define X509_OBJ_SUBJECT 10 -#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12 -#define X509_OBJ_SUBJECT_PUBLIC_KEY 13 -#define X509_OBJ_RSA_PUBLIC_KEY 14 -#define X509_OBJ_MODULUS 15 -#define X509_OBJ_PUBLIC_EXPONENT 16 -#define X509_OBJ_EXTN_ID 24 -#define X509_OBJ_CRITICAL 25 -#define X509_OBJ_EXTN_VALUE 26 -#define X509_OBJ_ALGORITHM 29 -#define X509_OBJ_SIGNATURE 30 -#define X509_OBJ_ROOF 31 - +#define X509_OBJ_CERTIFICATE 0 +#define X509_OBJ_TBS_CERTIFICATE 1 +#define X509_OBJ_VERSION 3 +#define X509_OBJ_SERIAL_NUMBER 4 +#define X509_OBJ_SIG_ALG 5 +#define X509_OBJ_ISSUER 6 +#define X509_OBJ_NOT_BEFORE 8 +#define X509_OBJ_NOT_AFTER 9 +#define X509_OBJ_SUBJECT 10 +#define X509_OBJ_SUBJECT_PUBLIC_KEY_INFO 11 +#define X509_OBJ_EXTN_ID 19 +#define X509_OBJ_CRITICAL 20 +#define X509_OBJ_EXTN_VALUE 21 +#define X509_OBJ_ALGORITHM 24 +#define X509_OBJ_SIGNATURE 25 const x509cert_t empty_x509cert = { - NULL , /* *next */ - UNDEFINED_TIME, /* installed */ - 0 , /* count */ - FALSE , /* smartcard */ - AUTH_NONE , /* authority_flags */ - { NULL, 0 } , /* certificate */ - { NULL, 0 } , /* tbsCertificate */ - 1 , /* version */ - { NULL, 0 } , /* serialNumber */ - OID_UNKNOWN , /* sigAlg */ - { NULL, 0 } , /* issuer */ - /* validity */ - 0 , /* notBefore */ - 0 , /* notAfter */ - { NULL, 0 } , /* subject */ - /* subjectPublicKeyInfo */ - OID_UNKNOWN , /* subjectPublicKeyAlgorithm */ - { NULL, 0 } , /* subjectPublicKey */ - { NULL, 0 } , /* modulus */ - { NULL, 0 } , /* publicExponent */ - /* issuerUniqueID */ - /* subjectUniqueID */ - /* extensions */ - /* extension */ - /* extnID */ - /* critical */ - /* extnValue */ - FALSE , /* isCA */ - FALSE , /* isOcspSigner */ - { NULL, 0 } , /* subjectKeyID */ - { NULL, 0 } , /* authKeyID */ - { NULL, 0 } , /* authKeySerialNumber */ - { NULL, 0 } , /* accessLocation */ - NULL , /* subjectAltName */ - NULL , /* crlDistributionPoints */ - OID_UNKNOWN , /* algorithm */ - { NULL, 0 } /* signature */ + NULL , /* *next */ + UNDEFINED_TIME, /* installed */ + 0 , /* count */ + FALSE , /* smartcard */ + AUTH_NONE , /* authority_flags */ + { NULL, 0 } , /* certificate */ + { NULL, 0 } , /* tbsCertificate */ + 1 , /* version */ + { NULL, 0 } , /* serialNumber */ + OID_UNKNOWN , /* sigAlg */ + { NULL, 0 } , /* issuer */ + /* validity */ + 0 , /* notBefore */ + 0 , /* notAfter */ + { NULL, 0 } , /* subject */ + NULL , /* public_key */ + /* issuerUniqueID */ + /* subjectUniqueID */ + /* extensions */ + /* extension */ + /* extnID */ + /* critical */ + /* extnValue */ + FALSE , /* isCA */ + FALSE , /* isOcspSigner */ + { NULL, 0 } , /* subjectKeyID */ + { NULL, 0 } , /* authKeyID */ + { NULL, 0 } , /* authKeySerialNumber */ + { NULL, 0 } , /* accessLocation */ + NULL , /* subjectAltName */ + NULL , /* crlDistributionPoints */ + OID_UNKNOWN , /* algorithm */ + { NULL, 0 } /* signature */ }; /* coding of X.501 distinguished name */ typedef struct { - const u_char *name; - chunk_t oid; - u_char type; + const u_char *name; + chunk_t oid; + u_char type; } x501rdn_t; /* X.501 acronyms for well known object identifiers (OIDs) */ static u_char oid_ND[] = {0x02, 0x82, 0x06, 0x01, - 0x0A, 0x07, 0x14}; + 0x0A, 0x07, 0x14}; static u_char oid_UID[] = {0x09, 0x92, 0x26, 0x89, 0x93, - 0xF2, 0x2C, 0x64, 0x01, 0x01}; + 0xF2, 0x2C, 0x64, 0x01, 0x01}; static u_char oid_DC[] = {0x09, 0x92, 0x26, 0x89, 0x93, - 0xF2, 0x2C, 0x64, 0x01, 0x19}; + 0xF2, 0x2C, 0x64, 0x01, 0x19}; static u_char oid_CN[] = {0x55, 0x04, 0x03}; static u_char oid_S[] = {0x55, 0x04, 0x04}; static u_char oid_SN[] = {0x55, 0x04, 0x05}; @@ -351,13 +294,13 @@ static u_char oid_G[] = {0x55, 0x04, 0x2A}; static u_char oid_I[] = {0x55, 0x04, 0x2B}; static u_char oid_ID[] = {0x55, 0x04, 0x2D}; static u_char oid_EN[] = {0x60, 0x86, 0x48, 0x01, 0x86, - 0xF8, 0x42, 0x03, 0x01, 0x03}; + 0xF8, 0x42, 0x03, 0x01, 0x03}; static u_char oid_E[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x09, 0x01}; + 0x0D, 0x01, 0x09, 0x01}; static u_char oid_UN[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x09, 0x02}; + 0x0D, 0x01, 0x09, 0x02}; static u_char oid_TCGID[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x89, - 0x31, 0x01, 0x01, 0x02, 0x02, 0x4B}; + 0x31, 0x01, 0x01, 0x02, 0x02, 0x4B}; static const x501rdn_t x501rdns[] = { {"ND" , {oid_ND, 7}, ASN1_PRINTABLESTRING}, @@ -391,1850 +334,1804 @@ static const x501rdn_t x501rdns[] = { #define X501_RDN_ROOF 26 static u_char ASN1_subjectAltName_oid_str[] = { - 0x06, 0x03, 0x55, 0x1D, 0x11 + 0x06, 0x03, 0x55, 0x1D, 0x11 }; -static const chunk_t ASN1_subjectAltName_oid = strchunk(ASN1_subjectAltName_oid_str); +static const chunk_t ASN1_subjectAltName_oid = chunk_from_buf(ASN1_subjectAltName_oid_str); -static void -update_chunk(chunk_t *ch, int n) +static void update_chunk(chunk_t *ch, int n) { - n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1; - ch->ptr += n; ch->len -= n; + n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1; + ch->ptr += n; ch->len -= n; } -/* +/** * Pointer is set to the first RDN in a DN */ -static err_t -init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next) +static err_t init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next) { - *rdn = empty_chunk; - *attribute = empty_chunk; - - /* a DN is a SEQUENCE OF RDNs */ + *rdn = chunk_empty; + *attribute = chunk_empty; - if (*dn.ptr != ASN1_SEQUENCE) - { - return "DN is not a SEQUENCE"; - } + /* a DN is a SEQUENCE OF RDNs */ - rdn->len = asn1_length(&dn); + if (*dn.ptr != ASN1_SEQUENCE) + { + return "DN is not a SEQUENCE"; + } - if (rdn->len == ASN1_INVALID_LENGTH) - return "Invalid RDN length"; + rdn->len = asn1_length(&dn); - rdn->ptr = dn.ptr; + if (rdn->len == ASN1_INVALID_LENGTH) + { + return "Invalid RDN length"; + } + rdn->ptr = dn.ptr; - /* are there any RDNs ? */ - *next = rdn->len > 0; + /* are there any RDNs ? */ + *next = rdn->len > 0; - return NULL; + return NULL; } -/* +/** * Fetches the next RDN in a DN */ -static err_t -get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, chunk_t *value -, asn1_t *type, bool *next) +static err_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid, + chunk_t *value, asn1_t *type, bool *next) { - chunk_t body; + chunk_t body; - /* initialize return values */ - *oid = empty_chunk; - *value = empty_chunk; + /* initialize return values */ + *oid = chunk_empty; + *value = chunk_empty; - /* if all attributes have been parsed, get next rdn */ - if (attribute->len <= 0) - { - /* an RDN is a SET OF attributeTypeAndValue */ - if (*rdn->ptr != ASN1_SET) - return "RDN is not a SET"; - - attribute->len = asn1_length(rdn); - - if (attribute->len == ASN1_INVALID_LENGTH) - return "Invalid attribute length"; - - attribute->ptr = rdn->ptr; - - /* advance to start of next RDN */ - rdn->ptr += attribute->len; - rdn->len -= attribute->len; - } - - /* an attributeTypeAndValue is a SEQUENCE */ - if (*attribute->ptr != ASN1_SEQUENCE) - return "attributeTypeAndValue is not a SEQUENCE"; - - /* extract the attribute body */ - body.len = asn1_length(attribute); - - if (body.len == ASN1_INVALID_LENGTH) - return "Invalid attribute body length"; + /* if all attributes have been parsed, get next rdn */ + if (attribute->len <= 0) + { + /* an RDN is a SET OF attributeTypeAndValue */ + if (*rdn->ptr != ASN1_SET) + { + return "RDN is not a SET"; + } + attribute->len = asn1_length(rdn); + + if (attribute->len == ASN1_INVALID_LENGTH) + { + return "Invalid attribute length"; + } + attribute->ptr = rdn->ptr; - body.ptr = attribute->ptr; - - /* advance to start of next attribute */ - attribute->ptr += body.len; - attribute->len -= body.len; + /* advance to start of next RDN */ + rdn->ptr += attribute->len; + rdn->len -= attribute->len; + } - /* attribute type is an OID */ - if (*body.ptr != ASN1_OID) - return "attributeType is not an OID"; + /* an attributeTypeAndValue is a SEQUENCE */ + if (*attribute->ptr != ASN1_SEQUENCE) + { + return "attributeTypeAndValue is not a SEQUENCE"; + } - /* extract OID */ - oid->len = asn1_length(&body); - - if (oid->len == ASN1_INVALID_LENGTH) - return "Invalid attribute OID length"; + /* extract the attribute body */ + body.len = asn1_length(attribute); + + if (body.len == ASN1_INVALID_LENGTH) + { + return "Invalid attribute body length"; + } + body.ptr = attribute->ptr; + + /* advance to start of next attribute */ + attribute->ptr += body.len; + attribute->len -= body.len; - oid->ptr = body.ptr; + /* attribute type is an OID */ + if (*body.ptr != ASN1_OID) + { + return "attributeType is not an OID"; + } - /* advance to the attribute value */ - body.ptr += oid->len; - body.len -= oid->len; + /* extract OID */ + oid->len = asn1_length(&body); + + if (oid->len == ASN1_INVALID_LENGTH) + { + return "Invalid attribute OID length"; + } + oid->ptr = body.ptr; - /* extract string type */ - *type = *body.ptr; + /* advance to the attribute value */ + body.ptr += oid->len; + body.len -= oid->len; - /* extract string value */ - value->len = asn1_length(&body); - - if (value->len == ASN1_INVALID_LENGTH) - return "Invalid attribute string length"; + /* extract string type */ + *type = *body.ptr; - value->ptr = body.ptr; + /* extract string value */ + value->len = asn1_length(&body); + + if (value->len == ASN1_INVALID_LENGTH) + { + return "Invalid attribute string length"; + } + value->ptr = body.ptr; - /* are there any RDNs left? */ - *next = rdn->len > 0 || attribute->len > 0; + /* are there any RDNs left? */ + *next = rdn->len > 0 || attribute->len > 0; - return NULL; + return NULL; } -/* +/** * Parses an ASN.1 distinguished name int its OID/value pairs */ -static err_t -dn_parse(chunk_t dn, chunk_t *str) +static err_t dn_parse(chunk_t dn, chunk_t *str) { - chunk_t rdn, oid, attribute, value; - asn1_t type; - int oid_code; - bool next; - bool first = TRUE; + chunk_t rdn, oid, attribute, value; + asn1_t type; + int oid_code; + bool next; + bool first = TRUE; - err_t ugh = init_rdn(dn, &rdn, &attribute, &next); + err_t ugh = init_rdn(dn, &rdn, &attribute, &next); - if (ugh != NULL) /* a parsing error has occured */ - return ugh; + if (ugh != NULL) /* a parsing error has occured */ + { + return ugh; + } - while (next) - { - ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next); + while (next) + { + ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next); - if (ugh != NULL) /* a parsing error has occured */ - return ugh; + if (ugh != NULL) /* a parsing error has occured */ + { + return ugh; + } - if (first) /* first OID/value pair */ - first = FALSE; - else /* separate OID/value pair by a comma */ - update_chunk(str, snprintf(str->ptr,str->len,", ")); + if (first) /* first OID/value pair */ + { + first = FALSE; + } + else /* separate OID/value pair by a comma */ + { + update_chunk(str, snprintf(str->ptr,str->len,", ")); + } - /* print OID */ - oid_code = known_oid(oid); - if (oid_code == OID_UNKNOWN) /* OID not found in list */ - hex_str(oid, str); - else - update_chunk(str, snprintf(str->ptr,str->len,"%s", - oid_names[oid_code].name)); + /* print OID */ + oid_code = asn1_known_oid(oid); + if (oid_code == OID_UNKNOWN) /* OID not found in list */ + { + hex_str(oid, str); + } + else + { + update_chunk(str, snprintf(str->ptr,str->len,"%s", + oid_names[oid_code].name)); + } - /* print value */ - update_chunk(str, snprintf(str->ptr,str->len,"=%.*s", - (int)value.len,value.ptr)); - } - return NULL; + /* print value */ + update_chunk(str, snprintf(str->ptr,str->len,"=%.*s", + (int)value.len,value.ptr)); + } + return NULL; } -/* +/** * Count the number of wildcard RDNs in a distinguished name */ -int -dn_count_wildcards(chunk_t dn) +int dn_count_wildcards(chunk_t dn) { - chunk_t rdn, attribute, oid, value; - asn1_t type; - bool next; - int wildcards = 0; + chunk_t rdn, attribute, oid, value; + asn1_t type; + bool next; + int wildcards = 0; - err_t ugh = init_rdn(dn, &rdn, &attribute, &next); + err_t ugh = init_rdn(dn, &rdn, &attribute, &next); - if (ugh != NULL) /* a parsing error has occured */ - return -1; + if (ugh != NULL) /* a parsing error has occured */ + { + return -1; + } - while (next) - { - ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next); + while (next) + { + ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next); - if (ugh != NULL) /* a parsing error has occured */ - return -1; - if (value.len == 1 && *value.ptr == '*') - wildcards++; /* we have found a wildcard RDN */ - } - return wildcards; + if (ugh != NULL) /* a parsing error has occured */ + { + return -1; + } + if (value.len == 1 && *value.ptr == '*') + { + wildcards++; /* we have found a wildcard RDN */ + } + } + return wildcards; } -/* +/** * Prints a binary string in hexadecimal form */ -void -hex_str(chunk_t bin, chunk_t *str) +void hex_str(chunk_t bin, chunk_t *str) { - u_int i; - update_chunk(str, snprintf(str->ptr,str->len,"0x")); - for (i=0; i < bin.len; i++) - update_chunk(str, snprintf(str->ptr,str->len,"%02X",*bin.ptr++)); + u_int i; + update_chunk(str, snprintf(str->ptr,str->len,"0x")); + for (i=0; i < bin.len; i++) + update_chunk(str, snprintf(str->ptr,str->len,"%02X",*bin.ptr++)); } -/* Converts a binary DER-encoded ASN.1 distinguished name +/** Converts a binary DER-encoded ASN.1 distinguished name * into LDAP-style human-readable ASCII format */ -int -dntoa(char *dst, size_t dstlen, chunk_t dn) +int dntoa(char *dst, size_t dstlen, chunk_t dn) { - err_t ugh = NULL; - chunk_t str; - - str.ptr = dst; - str.len = dstlen; - ugh = dn_parse(dn, &str); + err_t ugh = NULL; + chunk_t str; - if (ugh != NULL) /* error, print DN as hex string */ - { - DBG(DBG_PARSING, - DBG_log("error in DN parsing: %s", ugh) - ) str.ptr = dst; str.len = dstlen; - hex_str(dn, &str); - } - return (int)(dstlen - str.len); + ugh = dn_parse(dn, &str); + + if (ugh != NULL) /* error, print DN as hex string */ + { + DBG(DBG_PARSING, + DBG_log("error in DN parsing: %s", ugh) + ) + str.ptr = dst; + str.len = dstlen; + hex_str(dn, &str); + } + return (int)(dstlen - str.len); } -/* +/** * Same as dntoa but prints a special string for a null dn */ -int -dntoa_or_null(char *dst, size_t dstlen, chunk_t dn, const char* null_dn) +int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn, const char* null_dn) { - if (dn.ptr == NULL) - return snprintf(dst, dstlen, "%s", null_dn); + if (dn.ptr == NULL) + { + return snprintf(dst, dstlen, "%s", null_dn); + } + else + { + return dntoa(dst, dstlen, dn); + } +} + + +/** + * Codes ASN.1 lengths up to a size of 16'777'215 bytes + */ +static void code_asn1_length(size_t length, chunk_t *code) +{ + if (length < 128) + { + code->ptr[0] = length; + code->len = 1; + } + else if (length < 256) + { + code->ptr[0] = 0x81; + code->ptr[1] = (u_char) length; + code->len = 2; + } + else if (length < 65536) + { + code->ptr[0] = 0x82; + code->ptr[1] = length >> 8; + code->ptr[2] = length & 0x00ff; + code->len = 3; + } else - return dntoa(dst, dstlen, dn); + { + code->ptr[0] = 0x83; + code->ptr[1] = length >> 16; + code->ptr[2] = (length >> 8) & 0x00ff; + code->ptr[3] = length & 0x0000ff; + code->len = 4; + } } -/* Converts an LDAP-style human-readable ASCII-encoded +/** + * Converts an LDAP-style human-readable ASCII-encoded * ASN.1 distinguished name into binary DER-encoded format */ -err_t -atodn(char *src, chunk_t *dn) +err_t atodn(char *src, chunk_t *dn) { /* finite state machine for atodn */ - typedef enum { - SEARCH_OID = 0, - READ_OID = 1, - SEARCH_NAME = 2, - READ_NAME = 3, - UNKNOWN_OID = 4 - } state_t; - - u_char oid_len_buf[3]; - u_char name_len_buf[3]; - u_char rdn_seq_len_buf[3]; - u_char rdn_set_len_buf[3]; - u_char dn_seq_len_buf[3]; - - chunk_t asn1_oid_len = { oid_len_buf, 0 }; - chunk_t asn1_name_len = { name_len_buf, 0 }; - chunk_t asn1_rdn_seq_len = { rdn_seq_len_buf, 0 }; - chunk_t asn1_rdn_set_len = { rdn_set_len_buf, 0 }; - chunk_t asn1_dn_seq_len = { dn_seq_len_buf, 0 }; - chunk_t oid = empty_chunk; - chunk_t name = empty_chunk; - - int whitespace = 0; - int rdn_seq_len = 0; - int rdn_set_len = 0; - int dn_seq_len = 0; - int pos = 0; - - err_t ugh = NULL; - - u_char *dn_ptr = dn->ptr + 4; - - state_t state = SEARCH_OID; - - do - { - switch (state) + typedef enum { + SEARCH_OID = 0, + READ_OID = 1, + SEARCH_NAME = 2, + READ_NAME = 3, + UNKNOWN_OID = 4 + } state_t; + + u_char oid_len_buf[3]; + u_char name_len_buf[3]; + u_char rdn_seq_len_buf[3]; + u_char rdn_set_len_buf[3]; + u_char dn_seq_len_buf[3]; + + chunk_t asn1_oid_len = { oid_len_buf, 0 }; + chunk_t asn1_name_len = { name_len_buf, 0 }; + chunk_t asn1_rdn_seq_len = { rdn_seq_len_buf, 0 }; + chunk_t asn1_rdn_set_len = { rdn_set_len_buf, 0 }; + chunk_t asn1_dn_seq_len = { dn_seq_len_buf, 0 }; + chunk_t oid = chunk_empty; + chunk_t name = chunk_empty; + + int whitespace = 0; + int rdn_seq_len = 0; + int rdn_set_len = 0; + int dn_seq_len = 0; + int pos = 0; + + err_t ugh = NULL; + + u_char *dn_ptr = dn->ptr + 4; + + state_t state = SEARCH_OID; + + do { - case SEARCH_OID: - if (*src != ' ' && *src != '/' && *src != ',') - { - oid.ptr = src; - oid.len = 1; - state = READ_OID; - } - break; - case READ_OID: - if (*src != ' ' && *src != '=') - oid.len++; - else - { - for (pos = 0; pos < X501_RDN_ROOF; pos++) + switch (state) { - if (strlen(x501rdns[pos].name) == oid.len && - strncasecmp(x501rdns[pos].name, oid.ptr, oid.len) == 0) - break; /* found a valid OID */ - } - if (pos == X501_RDN_ROOF) - { - ugh = "unknown OID in distinguished name"; - state = UNKNOWN_OID; - break; + case SEARCH_OID: + if (*src != ' ' && *src != '/' && *src != ',') + { + oid.ptr = src; + oid.len = 1; + state = READ_OID; + } + break; + case READ_OID: + if (*src != ' ' && *src != '=') + { + oid.len++; + } + else + { + for (pos = 0; pos < X501_RDN_ROOF; pos++) + { + if (strlen(x501rdns[pos].name) == oid.len && + strncasecmp(x501rdns[pos].name, oid.ptr, oid.len) == 0) + { + break; /* found a valid OID */ + } + } + if (pos == X501_RDN_ROOF) + { + ugh = "unknown OID in distinguished name"; + state = UNKNOWN_OID; + break; + } + code_asn1_length(x501rdns[pos].oid.len, &asn1_oid_len); + + /* reset oid and change state */ + oid = chunk_empty; + state = SEARCH_NAME; + } + break; + case SEARCH_NAME: + if (*src != ' ' && *src != '=') + { + name.ptr = src; + name.len = 1; + whitespace = 0; + state = READ_NAME; + } + break; + case READ_NAME: + if (*src != ',' && *src != '/' && *src != '\0') + { + name.len++; + if (*src == ' ') + { + whitespace++; + } + else + { + whitespace = 0; + } + } + else + { + name.len -= whitespace; + code_asn1_length(name.len, &asn1_name_len); + + /* compute the length of the relative distinguished name sequence */ + rdn_seq_len = 1 + asn1_oid_len.len + x501rdns[pos].oid.len + + 1 + asn1_name_len.len + name.len; + code_asn1_length(rdn_seq_len, &asn1_rdn_seq_len); + + /* compute the length of the relative distinguished name set */ + rdn_set_len = 1 + asn1_rdn_seq_len.len + rdn_seq_len; + code_asn1_length(rdn_set_len, &asn1_rdn_set_len); + + /* encode the relative distinguished name */ + *dn_ptr++ = ASN1_SET; + chunkcpy(dn_ptr, asn1_rdn_set_len); + *dn_ptr++ = ASN1_SEQUENCE; + chunkcpy(dn_ptr, asn1_rdn_seq_len); + *dn_ptr++ = ASN1_OID; + chunkcpy(dn_ptr, asn1_oid_len); + chunkcpy(dn_ptr, x501rdns[pos].oid); + /* encode the ASN.1 character string type of the name */ + *dn_ptr++ = (x501rdns[pos].type == ASN1_PRINTABLESTRING + && !asn1_is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type; + chunkcpy(dn_ptr, asn1_name_len); + chunkcpy(dn_ptr, name); + + /* accumulate the length of the distinguished name sequence */ + dn_seq_len += 1 + asn1_rdn_set_len.len + rdn_set_len; + + /* reset name and change state */ + name = chunk_empty; + state = SEARCH_OID; + } + break; + case UNKNOWN_OID: + break; } - code_asn1_length(x501rdns[pos].oid.len, &asn1_oid_len); - - /* reset oid and change state */ - oid = empty_chunk; - state = SEARCH_NAME; - } - break; - case SEARCH_NAME: - if (*src != ' ' && *src != '=') - { - name.ptr = src; - name.len = 1; - whitespace = 0; - state = READ_NAME; - } - break; - case READ_NAME: - if (*src != ',' && *src != '/' && *src != '\0') - { - name.len++; - if (*src == ' ') - whitespace++; - else - whitespace = 0; - } - else - { - name.len -= whitespace; - code_asn1_length(name.len, &asn1_name_len); - - /* compute the length of the relative distinguished name sequence */ - rdn_seq_len = 1 + asn1_oid_len.len + x501rdns[pos].oid.len + - 1 + asn1_name_len.len + name.len; - code_asn1_length(rdn_seq_len, &asn1_rdn_seq_len); - - /* compute the length of the relative distinguished name set */ - rdn_set_len = 1 + asn1_rdn_seq_len.len + rdn_seq_len; - code_asn1_length(rdn_set_len, &asn1_rdn_set_len); - - /* encode the relative distinguished name */ - *dn_ptr++ = ASN1_SET; - chunkcpy(dn_ptr, asn1_rdn_set_len); - *dn_ptr++ = ASN1_SEQUENCE; - chunkcpy(dn_ptr, asn1_rdn_seq_len); - *dn_ptr++ = ASN1_OID; - chunkcpy(dn_ptr, asn1_oid_len); - chunkcpy(dn_ptr, x501rdns[pos].oid); - /* encode the ASN.1 character string type of the name */ - *dn_ptr++ = (x501rdns[pos].type == ASN1_PRINTABLESTRING - && !is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type; - chunkcpy(dn_ptr, asn1_name_len); - chunkcpy(dn_ptr, name); - - /* accumulate the length of the distinguished name sequence */ - dn_seq_len += 1 + asn1_rdn_set_len.len + rdn_set_len; - - /* reset name and change state */ - name = empty_chunk; - state = SEARCH_OID; - } - break; - case UNKNOWN_OID: - break; - } - } while (*src++ != '\0'); - - /* complete the distinguished name sequence*/ - code_asn1_length(dn_seq_len, &asn1_dn_seq_len); - dn->ptr += 3 - asn1_dn_seq_len.len; - dn->len = 1 + asn1_dn_seq_len.len + dn_seq_len; - dn_ptr = dn->ptr; - *dn_ptr++ = ASN1_SEQUENCE; - chunkcpy(dn_ptr, asn1_dn_seq_len); - return ugh; + } while (*src++ != '\0'); + + /* complete the distinguished name sequence*/ + code_asn1_length(dn_seq_len, &asn1_dn_seq_len); + dn->ptr += 3 - asn1_dn_seq_len.len; + dn->len = 1 + asn1_dn_seq_len.len + dn_seq_len; + dn_ptr = dn->ptr; + *dn_ptr++ = ASN1_SEQUENCE; + chunkcpy(dn_ptr, asn1_dn_seq_len); + return ugh; } -/* compare two distinguished names by - * comparing the individual RDNs +/** + * compare two distinguished names by comparing the individual RDNs */ -bool -same_dn(chunk_t a, chunk_t b) +bool same_dn(chunk_t a, chunk_t b) { - chunk_t rdn_a, rdn_b, attribute_a, attribute_b; - chunk_t oid_a, oid_b, value_a, value_b; - asn1_t type_a, type_b; - bool next_a, next_b; + chunk_t rdn_a, rdn_b, attribute_a, attribute_b; + chunk_t oid_a, oid_b, value_a, value_b; + asn1_t type_a, type_b; + bool next_a, next_b; - /* same lengths for the DNs */ - if (a.len != b.len) - return FALSE; + /* same lengths for the DNs */ + if (a.len != b.len) + { + return FALSE; + } - /* try a binary comparison first */ - if (memcmp(a.ptr, b.ptr, b.len) == 0) - return TRUE; - - /* initialize DN parsing */ - if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL - || init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL) - return FALSE; + /* try a binary comparison first */ + if (memeq(a.ptr, b.ptr, b.len)) + { + return TRUE; + } - /* fetch next RDN pair */ - while (next_a && next_b) - { - /* parse next RDNs and check for errors */ - if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL - || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL) + /* initialize DN parsing */ + if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL + || init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL) { - return FALSE; + return FALSE; } - /* OIDs must agree */ - if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0) - return FALSE; + /* fetch next RDN pair */ + while (next_a && next_b) + { + /* parse next RDNs and check for errors */ + if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL + || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL) + { + return FALSE; + } + + /* OIDs must agree */ + if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0) + { + return FALSE; + } - /* same lengths for values */ - if (value_a.len != value_b.len) - return FALSE; + /* same lengths for values */ + if (value_a.len != value_b.len) + { + return FALSE; + } - /* printableStrings and email RDNs require uppercase comparison */ - if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING || - (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL))) - { - if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) - return FALSE; + /* printableStrings and email RDNs require uppercase comparison */ + if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING || + (type_a == ASN1_IA5STRING && asn1_known_oid(oid_a) == OID_PKCS9_EMAIL))) + { + if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) + { + return FALSE; + } + } + else + { + if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0) + { + return FALSE; + } + } } - else + /* both DNs must have same number of RDNs */ + if (next_a || next_b) { - if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0) return FALSE; } - } - /* both DNs must have same number of RDNs */ - if (next_a || next_b) - return FALSE; - /* the two DNs are equal! */ - return TRUE; + /* the two DNs are equal! */ + return TRUE; } -/* compare two distinguished names by comparing the individual RDNs. +/** + * Compare two distinguished names by comparing the individual RDNs. * A single'*' character designates a wildcard RDN in DN b. */ -bool -match_dn(chunk_t a, chunk_t b, int *wildcards) +bool match_dn(chunk_t a, chunk_t b, int *wildcards) { - chunk_t rdn_a, rdn_b, attribute_a, attribute_b; - chunk_t oid_a, oid_b, value_a, value_b; - asn1_t type_a, type_b; - bool next_a, next_b; + chunk_t rdn_a, rdn_b, attribute_a, attribute_b; + chunk_t oid_a, oid_b, value_a, value_b; + asn1_t type_a, type_b; + bool next_a, next_b; - /* initialize wildcard counter */ - *wildcards = 0; + /* initialize wildcard counter */ + *wildcards = 0; - /* initialize DN parsing */ - if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL - || init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL) - return FALSE; - - /* fetch next RDN pair */ - while (next_a && next_b) - { - /* parse next RDNs and check for errors */ - if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL - || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL) + /* initialize DN parsing */ + if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL + || init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL) { - return FALSE; + return FALSE; } - /* OIDs must agree */ - if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0) - return FALSE; - - /* does rdn_b contain a wildcard? */ - if (value_b.len == 1 && *value_b.ptr == '*') + /* fetch next RDN pair */ + while (next_a && next_b) { - (*wildcards)++; - continue; - } + /* parse next RDNs and check for errors */ + if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL + || get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL) + { + return FALSE; + } - /* same lengths for values */ - if (value_a.len != value_b.len) - return FALSE; + /* OIDs must agree */ + if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0) + { + return FALSE; + } - /* printableStrings and email RDNs require uppercase comparison */ - if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING || - (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL))) - { - if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) - return FALSE; + /* does rdn_b contain a wildcard? */ + if (value_b.len == 1 && *value_b.ptr == '*') + { + (*wildcards)++; + continue; + } + + /* same lengths for values */ + if (value_a.len != value_b.len) + { + return FALSE; + } + + /* printableStrings and email RDNs require uppercase comparison */ + if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING || + (type_a == ASN1_IA5STRING && asn1_known_oid(oid_a) == OID_PKCS9_EMAIL))) + { + if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0) + { + return FALSE; + } + } + else + { + if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0) + { + return FALSE; + } + } } - else + + /* both DNs must have same number of RDNs */ + if (next_a || next_b) { - if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0) return FALSE; } - } - /* both DNs must have same number of RDNs */ - if (next_a || next_b) - return FALSE; - /* the two DNs match! */ - return TRUE; + /* the two DNs match! */ + return TRUE; } -/* - * compare two X.509 certificates by comparing their signatures +/** + * Compare two X.509 certificates by comparing their signatures */ -bool -same_x509cert(const x509cert_t *a, const x509cert_t *b) +bool same_x509cert(const x509cert_t *a, const x509cert_t *b) { - return same_chunk(a->signature, b->signature); + return chunk_equals(a->signature, b->signature); } -/* for each link pointing to the certificate - " increase the count by one +/** + * For each link pointing to the certificate increase the count by one */ -void -share_x509cert(x509cert_t *cert) +void share_x509cert(x509cert_t *cert) { - if (cert != NULL) - cert->count++; + if (cert != NULL) + { + cert->count++; + } } -/* - * add a X.509 user/host certificate to the chained list +/** + * Add a X.509 user/host certificate to the chained list */ -x509cert_t* -add_x509cert(x509cert_t *cert) +x509cert_t* add_x509cert(x509cert_t *cert) { - x509cert_t *c = x509certs; + x509cert_t *c = x509certs; - while (c != NULL) - { - if (same_x509cert(c, cert)) /* already in chain, free cert */ + while (c != NULL) { - free_x509cert(cert); - return c; + if (same_x509cert(c, cert)) /* already in chain, free cert */ + { + free_x509cert(cert); + return c; + } + c = c->next; } - c = c->next; - } - /* insert new cert at the root of the chain */ - lock_certs_and_keys("add_x509cert"); - cert->next = x509certs; - x509certs = cert; - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" x509 cert inserted") - ) - unlock_certs_and_keys("add_x509cert"); - return cert; + /* insert new cert at the root of the chain */ + lock_certs_and_keys("add_x509cert"); + cert->next = x509certs; + x509certs = cert; + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log(" x509 cert inserted") + ) + unlock_certs_and_keys("add_x509cert"); + return cert; } -/* - * choose either subject DN or a subjectAltName as connection end ID +/** + * Choose either subject DN or a subjectAltName as connection end ID */ -void -select_x509cert_id(x509cert_t *cert, struct id *end_id) +void select_x509cert_id(x509cert_t *cert, struct id *end_id) { - bool copy_subject_dn = TRUE; /* ID is subject DN */ + bool copy_subject_dn = TRUE; /* ID is subject DN */ - if (end_id->kind != ID_NONE) /* check for matching subjectAltName */ - { - generalName_t *gn = cert->subjectAltName; - - while (gn != NULL) + if (end_id->kind != ID_ANY) /* check for matching subjectAltName */ { - struct id id = empty_id; + generalName_t *gn = cert->subjectAltName; - gntoid(&id, gn); - if (same_id(&id, end_id)) - { - copy_subject_dn = FALSE; /* take subjectAltName instead */ - break; - } - gn = gn->next; + while (gn != NULL) + { + struct id id = empty_id; + + gntoid(&id, gn); + if (same_id(&id, end_id)) + { + copy_subject_dn = FALSE; /* take subjectAltName instead */ + break; + } + gn = gn->next; + } } - } - if (copy_subject_dn) - { - if (end_id->kind != ID_NONE && end_id->kind != ID_DER_ASN1_DN) + if (copy_subject_dn) { - char buf[BUF_LEN]; + if (end_id->kind != ID_ANY && end_id->kind != ID_DER_ASN1_DN) + { + char buf[BUF_LEN]; - idtoa(end_id, buf, BUF_LEN); - plog(" no subjectAltName matches ID '%s', replaced by subject DN", buf); + idtoa(end_id, buf, BUF_LEN); + plog(" no subjectAltName matches ID '%s', replaced by subject DN", buf); + } + end_id->kind = ID_DER_ASN1_DN; + end_id->name.len = cert->subject.len; + end_id->name.ptr = temporary_cyclic_buffer(); + memcpy(end_id->name.ptr, cert->subject.ptr, cert->subject.len); } - end_id->kind = ID_DER_ASN1_DN; - end_id->name.len = cert->subject.len; - end_id->name.ptr = temporary_cyclic_buffer(); - memcpy(end_id->name.ptr, cert->subject.ptr, cert->subject.len); - } } -/* - * check for equality between two key identifiers +/** + * Check for equality between two key identifiers */ -bool -same_keyid(chunk_t a, chunk_t b) +bool same_keyid(chunk_t a, chunk_t b) { - if (a.ptr == NULL || b.ptr == NULL) - return FALSE; - - return same_chunk(a, b); + if (a.ptr == NULL || b.ptr == NULL) + { + return FALSE; + } + return chunk_equals(a, b); } -/* - * check for equality between two serial numbers +/** + * Check for equality between two serial numbers */ -bool -same_serial(chunk_t a, chunk_t b) +bool same_serial(chunk_t a, chunk_t b) { - /* do not compare serial numbers if one of them is not defined */ - if (a.ptr == NULL || b.ptr == NULL) - return TRUE; - - return same_chunk(a, b); + /* do not compare serial numbers if one of them is not defined */ + if (a.ptr == NULL || b.ptr == NULL) + { + return TRUE; + } + return chunk_equals(a, b); } -/* - * get a X.509 certificate with a given issuer found at a certain position +/** + * Get a X.509 certificate with a given issuer found at a certain position */ -x509cert_t* -get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, x509cert_t *chain) +x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, + x509cert_t *chain) { - x509cert_t *cert = (chain != NULL)? chain->next : x509certs; + x509cert_t *cert = (chain != NULL)? chain->next : x509certs; - while (cert != NULL) - { - if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->authKeyID) - : (same_dn(issuer, cert->issuer) - && same_serial(serial, cert->authKeySerialNumber))) + while (cert != NULL) { - return cert; + if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->authKeyID) + : (same_dn(issuer, cert->issuer) + && same_serial(serial, cert->authKeySerialNumber))) + { + return cert; + } + cert = cert->next; } - cert = cert->next; - } - return NULL; + return NULL; } -/* - * encode a linked list of subjectAltNames +/** + * Encode a linked list of subjectAltNames */ -chunk_t -build_subjectAltNames(generalName_t *subjectAltNames) +chunk_t build_subjectAltNames(generalName_t *subjectAltNames) { - u_char *pos; - chunk_t names; - size_t len = 0; - generalName_t *gn = subjectAltNames; - + u_char *pos; + chunk_t names; + size_t len = 0; + generalName_t *gn = subjectAltNames; + /* compute the total size of the ASN.1 attributes object */ - while (gn != NULL) - { - len += gn->name.len; - gn = gn->next; - } + while (gn != NULL) + { + len += gn->name.len; + gn = gn->next; + } - pos = build_asn1_object(&names, ASN1_SEQUENCE, len); + pos = asn1_build_object(&names, ASN1_SEQUENCE, len); - gn = subjectAltNames; - while (gn != NULL) - { - chunkcpy(pos, gn->name); - gn = gn->next; - } + gn = subjectAltNames; + while (gn != NULL) + { + chunkcpy(pos, gn->name); + gn = gn->next; + } - return asn1_wrap(ASN1_SEQUENCE, "cm" - , ASN1_subjectAltName_oid - , asn1_wrap(ASN1_OCTET_STRING, "m", names)); + return asn1_wrap(ASN1_SEQUENCE, "cm" + , ASN1_subjectAltName_oid + , asn1_wrap(ASN1_OCTET_STRING, "m", names)); } -/* - * build a to-be-signed X.509 certificate body +/** + * Build a to-be-signed X.509 certificate body */ -static chunk_t -build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa) +static chunk_t build_tbs_x509cert(x509cert_t *cert, public_key_t *rsa) { - /* version is always X.509v3 */ - chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2); + /* version is always X.509v3 */ + chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2); - chunk_t extensions = empty_chunk; + chunk_t extensions = chunk_empty; - if (cert->subjectAltName != NULL) - { - extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m" - , asn1_wrap(ASN1_SEQUENCE, "m" - , build_subjectAltNames(cert->subjectAltName))); - } + chunk_t key = rsa->get_encoding(rsa); - return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm" - , version - , asn1_simple_object(ASN1_INTEGER, cert->serialNumber) - , asn1_algorithmIdentifier(cert->sigAlg) - , cert->issuer - , asn1_wrap(ASN1_SEQUENCE, "mm" - , timetoasn1(&cert->notBefore, ASN1_UTCTIME) - , timetoasn1(&cert->notAfter, ASN1_UTCTIME) - ) - , cert->subject - , pkcs1_build_publicKeyInfo(rsa) - , extensions - ); + chunk_t keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm", + asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), + asn1_bitstring("m", key)); + + if (cert->subjectAltName != NULL) + { + extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m" + , asn1_wrap(ASN1_SEQUENCE, "m" + , build_subjectAltNames(cert->subjectAltName))); + } + + return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm" + , version + , asn1_integer("c", cert->serialNumber) + , asn1_algorithmIdentifier(cert->sigAlg) + , cert->issuer + , asn1_wrap(ASN1_SEQUENCE, "mm" + , asn1_from_time(&cert->notBefore, ASN1_UTCTIME) + , asn1_from_time(&cert->notAfter, ASN1_UTCTIME) + ) + , cert->subject + , keyInfo + , extensions + ); } -/* - * build a DER-encoded X.509 certificate +/** + * Build a DER-encoded X.509 certificate */ -void -build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key -, const RSA_private_key_t *signer_key) +void build_x509cert(x509cert_t *cert, public_key_t *cert_key, + private_key_t *signer_key) { - chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key); + chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key); - chunk_t signature = pkcs1_build_signature(tbs_cert, cert->sigAlg - , signer_key, TRUE); + chunk_t signature = x509_build_signature(tbs_cert, cert->sigAlg + , signer_key, TRUE); - cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm" - , tbs_cert - , asn1_algorithmIdentifier(cert->sigAlg) - , signature); + cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm" + , tbs_cert + , asn1_algorithmIdentifier(cert->sigAlg) + , signature); } -/* - * free the dynamic memory used to store generalNames +/** + * Free the dynamic memory used to store generalNames */ -void -free_generalNames(generalName_t* gn, bool free_name) +void free_generalNames(generalName_t* gn, bool free_name) { - while (gn != NULL) - { - generalName_t *gn_top = gn; - if (free_name) + while (gn != NULL) { - pfree(gn->name.ptr); + generalName_t *gn_top = gn; + if (free_name) + { + free(gn->name.ptr); + } + gn = gn->next; + free(gn_top); } - gn = gn->next; - pfree(gn_top); - } } -/* - * free a X.509 certificate +/** + * Free a X.509 certificate */ -void -free_x509cert(x509cert_t *cert) +void free_x509cert(x509cert_t *cert) { - if (cert != NULL) - { - free_generalNames(cert->subjectAltName, FALSE); - free_generalNames(cert->crlDistributionPoints, FALSE); - pfreeany(cert->certificate.ptr); - pfree(cert); - cert = NULL; - } + if (cert != NULL) + { + DESTROY_IF(cert->public_key); + free_generalNames(cert->subjectAltName, FALSE); + free_generalNames(cert->crlDistributionPoints, FALSE); + free(cert->certificate.ptr); + free(cert); + cert = NULL; + } } -/* release of a certificate decreases the count by one - " the certificate is freed when the counter reaches zero +/** + * Release of a certificate decreases the count by one + * the certificate is freed when the counter reaches zero */ -void -release_x509cert(x509cert_t *cert) +void release_x509cert(x509cert_t *cert) { - if (cert != NULL && --cert->count == 0) - { - x509cert_t **pp = &x509certs; - while (*pp != cert) - pp = &(*pp)->next; - *pp = cert->next; - free_x509cert(cert); - } + if (cert != NULL && --cert->count == 0) + { + x509cert_t **pp = &x509certs; + while (*pp != cert) + { + pp = &(*pp)->next; + } + *pp = cert->next; + free_x509cert(cert); + } } - -/* - * stores a chained list of end certs and CA certs +/** + * Stores a chained list of end certs and CA certs */ -void -store_x509certs(x509cert_t **firstcert, bool strict) +void store_x509certs(x509cert_t **firstcert, bool strict) { - x509cert_t *cacerts = NULL; - x509cert_t **pp = firstcert; + x509cert_t *cacerts = NULL; + x509cert_t **pp = firstcert; - /* first extract CA certs, discarding root CA certs */ + /* first extract CA certs, discarding root CA certs */ - while (*pp != NULL) - { - x509cert_t *cert = *pp; - - if (cert->isCA) + while (*pp != NULL) { - *pp = cert->next; - - /* we don't accept self-signed CA certs */ - if (same_dn(cert->issuer, cert->subject)) - { - plog("self-signed cacert rejected"); - free_x509cert(cert); - } - else - { - /* insertion into temporary chain of candidate CA certs */ - cert->next = cacerts; - cacerts = cert; - } + x509cert_t *cert = *pp; + + if (cert->isCA) + { + *pp = cert->next; + + /* we don't accept self-signed CA certs */ + if (same_dn(cert->issuer, cert->subject)) + { + plog("self-signed cacert rejected"); + free_x509cert(cert); + } + else + { + /* insertion into temporary chain of candidate CA certs */ + cert->next = cacerts; + cacerts = cert; + } + } + else + { + pp = &cert->next; + } } - else - pp = &cert->next; - } - /* now verify the candidate CA certs */ - - while (cacerts != NULL) - { - x509cert_t *cert = cacerts; + /* now verify the candidate CA certs */ - cacerts = cacerts->next; - - if (trust_authcert_candidate(cert, cacerts)) - { - add_authcert(cert, AUTH_CA); - } - else + while (cacerts != NULL) { - plog("intermediate cacert rejected"); - free_x509cert(cert); - } - } - - /* now verify the end certificates */ + x509cert_t *cert = cacerts; + + cacerts = cacerts->next; - pp = firstcert; + if (trust_authcert_candidate(cert, cacerts)) + { + add_authcert(cert, AUTH_CA); + } + else + { + plog("intermediate cacert rejected"); + free_x509cert(cert); + } + } + + /* now verify the end certificates */ - while (*pp != NULL) - { - time_t valid_until; - x509cert_t *cert = *pp; + pp = firstcert; - if (verify_x509cert(cert, strict, &valid_until)) + while (*pp != NULL) { - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log("public key validated") - ) - add_x509_public_key(cert, valid_until, DAL_SIGNED); - } - else - { - plog("X.509 certificate rejected"); + time_t valid_until; + x509cert_t *cert = *pp; + + if (verify_x509cert(cert, strict, &valid_until)) + { + DBG(DBG_CONTROL | DBG_PARSING, + DBG_log("public key validated") + ) + add_x509_public_key(cert, valid_until, DAL_SIGNED); + } + else + { + plog("X.509 certificate rejected"); + } + *pp = cert->next; + free_x509cert(cert); } - *pp = cert->next; - free_x509cert(cert); - } } -/* - * decrypts an RSA signature using the issuer's certificate +/** + * Check if a signature over binary blob is genuine */ -static bool -decrypt_sig(chunk_t sig, int alg, const x509cert_t *issuer_cert, - chunk_t *digest) +bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, + const x509cert_t *issuer_cert) { - switch (alg) - { - chunk_t decrypted; - - case OID_RSA_ENCRYPTION: - case OID_MD2_WITH_RSA: - case OID_MD5_WITH_RSA: - case OID_SHA1_WITH_RSA: - case OID_SHA1_WITH_RSA_OIW: - case OID_SHA256_WITH_RSA: - case OID_SHA384_WITH_RSA: - case OID_SHA512_WITH_RSA: + public_key_t *key = issuer_cert->public_key; + signature_scheme_t scheme = signature_scheme_from_oid(algorithm); + + if (scheme == SIGN_UNKNOWN) { - mpz_t s; - RSA_public_key_t rsa; - - init_RSA_public_key(&rsa, issuer_cert->publicExponent - , issuer_cert->modulus); - - /* decrypt the signature s = s^e mod n */ - n_to_mpz(s, sig.ptr, sig.len); - mpz_powm(s, s, &rsa.e, &rsa.n); - - /* convert back to bytes */ - decrypted = mpz_to_n(s, rsa.k); - DBG(DBG_PARSING, - DBG_dump_chunk(" decrypted signature: ", decrypted) - ) - - /* copy the least significant bits of decrypted signature - * into the digest string - */ - memcpy(digest->ptr, decrypted.ptr + decrypted.len - digest->len, - digest->len); - - /* free memory */ - free_RSA_public_content(&rsa); - pfree(decrypted.ptr); - mpz_clear(s); - return TRUE; + return FALSE; } - default: - digest->len = 0; - return FALSE; - } + return key->verify(key, scheme, tbs, sig); } -/* - * Check if a signature over binary blob is genuine +/** + * Build an ASN.1 encoded PKCS#1 signature over a binary blob */ -bool -check_signature(chunk_t tbs, chunk_t sig, int digest_alg, int enc_alg -, const x509cert_t *issuer_cert) +chunk_t x509_build_signature(chunk_t tbs, int algorithm, private_key_t *key, + bool bit_string) { - u_char digest_buf[MAX_DIGEST_LEN]; - u_char decrypted_buf[MAX_DIGEST_LEN]; - chunk_t digest = {digest_buf, MAX_DIGEST_LEN}; - chunk_t decrypted = {decrypted_buf, MAX_DIGEST_LEN}; - - DBG(DBG_PARSING, - if (digest_alg != OID_UNKNOWN) - DBG_log("signature digest algorithm: '%s'",oid_names[digest_alg].name); - else - DBG_log("unknown signature digest algorithm"); - ) + chunk_t signature; + signature_scheme_t scheme = signature_scheme_from_oid(algorithm); - if (!compute_digest(tbs, digest_alg, &digest)) - { - plog(" digest algorithm not supported"); - return FALSE; - } - - DBG(DBG_PARSING, - DBG_dump_chunk(" digest:", digest) - ) - - decrypted.len = digest.len; /* we want the same digest length */ - - DBG(DBG_PARSING, - if (enc_alg != OID_UNKNOWN) - DBG_log("signature encryption algorithm: '%s'",oid_names[enc_alg].name); - else - DBG_log("unknown signature encryption algorithm"); - ) - - if (!decrypt_sig(sig, enc_alg, issuer_cert, &decrypted)) - { - plog(" decryption algorithm not supported"); - return FALSE; - } - - /* check if digests are equal */ - return !memcmp(decrypted.ptr, digest.ptr, digest.len); + 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); } -/* - * extracts the basicConstraints extension +/** + * Extracts the basicConstraints extension */ -static bool -parse_basicConstraints(chunk_t blob, int level0) +static bool parse_basicConstraints(chunk_t blob, int level0) { - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - bool isCA = FALSE; - - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); - - while (objectID < BASIC_CONSTRAINTS_ROOF) { + asn1_parser_t *parser; + chunk_t object; + int objectID; + bool isCA = FALSE; - if (!extract_object(basicConstraintsObjects, &objectID, - &object,&level, &ctx)) - break; + parser = asn1_parser_create(basicConstraintsObjects, blob); + parser->set_top_level(parser, level0); - if (objectID == BASIC_CONSTRAINTS_CA) + while (parser->iterate(parser, &objectID, &object)) { - isCA = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(isCA)?"TRUE":"FALSE"); - ) + if (objectID == BASIC_CONSTRAINTS_CA) + { + isCA = object.len && *object.ptr; + DBG(DBG_PARSING, + DBG_log(" %s",(isCA)?"TRUE":"FALSE"); + ) + } } - objectID++; - } - return isCA; + parser->destroy(parser); + + return isCA; } -/* +/** * Converts a X.500 generalName into an ID */ -void -gntoid(struct id *id, const generalName_t *gn) +void gntoid(struct id *id, const generalName_t *gn) { - switch(gn->kind) - { - case GN_DNS_NAME: /* ID type: ID_FQDN */ - id->kind = ID_FQDN; - id->name = gn->name; - break; - case GN_IP_ADDRESS: /* ID type: ID_IPV4_ADDR */ + switch(gn->kind) { - const struct af_info *afi = &af_inet4_info; - err_t ugh = NULL; + case GN_DNS_NAME: /* ID type: ID_FQDN */ + id->kind = ID_FQDN; + id->name = gn->name; + break; + case GN_IP_ADDRESS: /* ID type: ID_IPV4_ADDR */ + { + const struct af_info *afi = &af_inet4_info; + err_t ugh = NULL; - id->kind = afi->id_addr; - ugh = initaddr(gn->name.ptr, gn->name.len, afi->af, &id->ip_addr); + id->kind = afi->id_addr; + ugh = initaddr(gn->name.ptr, gn->name.len, afi->af, &id->ip_addr); + } + break; + case GN_RFC822_NAME: /* ID type: ID_USER_FQDN */ + id->kind = ID_USER_FQDN; + id->name = gn->name; + break; + default: + id->kind = ID_ANY; + id->name = chunk_empty; } - break; - case GN_RFC822_NAME: /* ID type: ID_USER_FQDN */ - id->kind = ID_USER_FQDN; - id->name = gn->name; - break; - default: - id->kind = ID_NONE; - id->name = empty_chunk; - } } -/* compute the subjectKeyIdentifier according to section 4.2.1.2 of RFC 3280 +/** + * Compute the subjectKeyIdentifier according to section 4.2.1.2 of RFC 3280 * as the 160 bit SHA-1 hash of the public key */ -void -compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID) +bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID) { - SHA1_CTX context; - - SHA1Init(&context); - SHA1Update(&context - , cert->subjectPublicKey.ptr - , cert->subjectPublicKey.len); - SHA1Final(subjectKeyID.ptr, &context); - subjectKeyID.len = SHA1_DIGEST_SIZE; + identification_t *keyid; + chunk_t encoding; + + keyid = cert->public_key->get_id(cert->public_key, ID_PUBKEY_SHA1); + if (keyid == NULL) + { + plog(" unable to compute subjectKeyID"); + return FALSE; + } + encoding = keyid->get_encoding(keyid); + memcpy(subjectKeyID.ptr, encoding.ptr, subjectKeyID.len); + return TRUE; } -/* - * extracts an otherName +/** + * Extracts an otherName */ -static bool -parse_otherName(chunk_t blob, int level0) +static bool parse_otherName(chunk_t blob, int level0) { - asn1_ctx_t ctx; - chunk_t object; - int objectID = 0; - u_int level; - int oid = OID_UNKNOWN; + asn1_parser_t *parser; + chunk_t object; + int objectID; + int oid = OID_UNKNOWN; + bool success = FALSE; - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); - - while (objectID < ON_OBJ_ROOF) - { - if (!extract_object(otherNameObjects, &objectID, &object, &level, &ctx)) - return FALSE; + parser = asn1_parser_create(otherNameObjects, blob); + parser->set_top_level(parser, level0); - switch (objectID) + while (parser->iterate(parser, &objectID, &object)) { - case ON_OBJ_ID_TYPE: - oid = known_oid(object); - break; - case ON_OBJ_VALUE: - if (oid == OID_XMPP_ADDR) - { - if (!parse_asn1_simple_object(&object, ASN1_UTF8STRING - , level + 1, "xmppAddr")) + switch (objectID) { - return FALSE; + case ON_OBJ_ID_TYPE: + oid = asn1_known_oid(object); + break; + case ON_OBJ_VALUE: + if (oid == OID_XMPP_ADDR) + { + if (!asn1_parse_simple_object(&object, ASN1_UTF8STRING, + parser->get_level(parser) + 1, "xmppAddr")) + { + goto end; + } + } + break; + default: + break; } - } - break; - default: - break; } - objectID++; - } - return TRUE; + success = parser->success(parser); + +end: + parser->destroy(parser); + return success; } -/* - * extracts a generalName +/** + * Extracts a generalName */ -static generalName_t* -parse_generalName(chunk_t blob, int level0) +static generalName_t* parse_generalName(chunk_t blob, int level0) { - u_char buf[BUF_LEN]; - asn1_ctx_t ctx; - chunk_t object; - int objectID = 0; - u_int level; - - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); + u_char buf[BUF_LEN]; + asn1_parser_t *parser; + chunk_t object; + generalName_t *gn = NULL; + int objectID; - while (objectID < GN_OBJ_ROOF) - { - bool valid_gn = FALSE; + parser = asn1_parser_create(generalNameObjects, blob); + parser->set_top_level(parser, level0); - if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx)) - return NULL; - - switch (objectID) { - case GN_OBJ_RFC822_NAME: - case GN_OBJ_DNS_NAME: - case GN_OBJ_URI: - DBG(DBG_PARSING, - DBG_log(" '%.*s'", (int)object.len, object.ptr); - ) - valid_gn = TRUE; - break; - case GN_OBJ_DIRECTORY_NAME: - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'", buf) - ) - valid_gn = TRUE; - break; - case GN_OBJ_IP_ADDRESS: - DBG(DBG_PARSING, - DBG_log(" '%d.%d.%d.%d'", *object.ptr, *(object.ptr+1), - *(object.ptr+2), *(object.ptr+3)); - ) - valid_gn = TRUE; - break; - case GN_OBJ_OTHER_NAME: - if (!parse_otherName(object, level + 1)) - return NULL; - break; - case GN_OBJ_X400_ADDRESS: - case GN_OBJ_EDI_PARTY_NAME: - case GN_OBJ_REGISTERED_ID: - break; - default: - break; - } - - if (valid_gn) + while (parser->iterate(parser, &objectID, &object)) { - generalName_t *gn = alloc_thing(generalName_t, "generalName"); - gn->kind = (objectID - GN_OBJ_OTHER_NAME) / 2; - gn->name = object; - gn->next = NULL; - return gn; - } - objectID++; - } - return NULL; -} - - -/* - * extracts one or several GNs and puts them into a chained list - */ -static generalName_t* -parse_generalNames(chunk_t blob, int level0, bool implicit) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - generalName_t *top_gn = NULL; - - asn1_init(&ctx, blob, level0, implicit, DBG_RAW); + bool valid_gn = FALSE; + + switch (objectID) { + case GN_OBJ_RFC822_NAME: + case GN_OBJ_DNS_NAME: + case GN_OBJ_URI: + DBG(DBG_PARSING, + DBG_log(" '%.*s'", (int)object.len, object.ptr); + ) + valid_gn = TRUE; + break; + case GN_OBJ_DIRECTORY_NAME: + DBG(DBG_PARSING, + dntoa(buf, BUF_LEN, object); + DBG_log(" '%s'", buf) + ) + valid_gn = TRUE; + break; + case GN_OBJ_IP_ADDRESS: + DBG(DBG_PARSING, + DBG_log(" '%d.%d.%d.%d'", *object.ptr, *(object.ptr+1), + *(object.ptr+2), *(object.ptr+3)); + ) + valid_gn = TRUE; + break; + case GN_OBJ_OTHER_NAME: + if (!parse_otherName(object, parser->get_level(parser)+1)) + { + goto end; + } + break; + case GN_OBJ_X400_ADDRESS: + case GN_OBJ_EDI_PARTY_NAME: + case GN_OBJ_REGISTERED_ID: + break; + default: + break; + } - while (objectID < GENERAL_NAMES_ROOF) - { - if (!extract_object(generalNamesObjects, &objectID, &object, &level, &ctx)) - return NULL; - - if (objectID == GENERAL_NAMES_GN) - { - generalName_t *gn = parse_generalName(object, level+1); - if (gn != NULL) - { - gn->next = top_gn; - top_gn = gn; - } + if (valid_gn) + { + gn = malloc_thing(generalName_t); + gn->kind = (objectID - GN_OBJ_OTHER_NAME) / 2; + gn->name = object; + gn->next = NULL; + goto end; + } } - objectID++; - } - return top_gn; + +end: + parser->destroy(parser); + return gn; } -/* - * returns a directoryName +/** + * Extracts one or several GNs and puts them into a chained list */ -chunk_t get_directoryName(chunk_t blob, int level, bool implicit) +static generalName_t* parse_generalNames(chunk_t blob, int level0, bool implicit) { - chunk_t name = empty_chunk; - generalName_t * gn = parse_generalNames(blob, level, implicit); - - if (gn != NULL && gn->kind == GN_DIRECTORY_NAME) - name= gn->name; - - free_generalNames(gn, FALSE); + asn1_parser_t *parser; + chunk_t object; + int objectID; + generalName_t *top_gn = NULL; + + parser = asn1_parser_create(generalNamesObjects, blob); + parser->set_top_level(parser, level0); + parser->set_flags(parser, implicit, FALSE); + + while (parser->iterate(parser, &objectID, &object)) + { + if (objectID == GENERAL_NAMES_GN) + { + generalName_t *gn = parse_generalName(object, + parser->get_level(parser)+1); + if (gn) + { + gn->next = top_gn; + top_gn = gn; + } + } + } + parser->destroy(parser); - return name; + return top_gn; } -/* - * extracts and converts a UTCTIME or GENERALIZEDTIME object +/** + * Returns a directoryName */ -time_t -parse_time(chunk_t blob, int level0) +chunk_t get_directoryName(chunk_t blob, int level, bool implicit) { - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); + chunk_t name = chunk_empty; + generalName_t * gn = parse_generalNames(blob, level, implicit); - while (objectID < TIME_ROOF) - { - if (!extract_object(timeObjects, &objectID, &object, &level, &ctx)) - return UNDEFINED_TIME; - - if (objectID == TIME_UTC || objectID == TIME_GENERALIZED) + if (gn != NULL && gn->kind == GN_DIRECTORY_NAME) { - return asn1totime(&object, (objectID == TIME_UTC) - ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME); + name= gn->name; } - objectID++; - } - return UNDEFINED_TIME; - } - -/* - * extracts a keyIdentifier - */ -static chunk_t -parse_keyIdentifier(chunk_t blob, int level0, bool implicit) -{ - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - - asn1_init(&ctx, blob, level0, implicit, DBG_RAW); - - extract_object(keyIdentifierObjects, &objectID, &object, &level, &ctx); - return object; + free_generalNames(gn, FALSE); + return name; } -/* - * extracts an authoritykeyIdentifier +/** + * Extracts an authoritykeyIdentifier */ -void -parse_authorityKeyIdentifier(chunk_t blob, int level0 - , chunk_t *authKeyID, chunk_t *authKeySerialNumber) +void parse_authorityKeyIdentifier(chunk_t blob, int level0, + chunk_t *authKeyID, + chunk_t *authKeySerialNumber) { - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; + asn1_parser_t *parser; + chunk_t object; + int objectID; - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); + parser = asn1_parser_create(authKeyIdentifierObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case AUTH_KEY_ID_KEY_ID: + *authKeyID = object; + break; + case AUTH_KEY_ID_CERT_ISSUER: + { + generalName_t * gn = parse_generalNames(object, + parser->get_level(parser) + 1, TRUE); - while (objectID < AUTH_KEY_ID_ROOF) - { - if (!extract_object(authorityKeyIdentifierObjects, &objectID, &object, &level, &ctx)) - return; - - switch (objectID) { - case AUTH_KEY_ID_KEY_ID: - *authKeyID = parse_keyIdentifier(object, level+1, TRUE); - break; - case AUTH_KEY_ID_CERT_ISSUER: - { - generalName_t * gn = parse_generalNames(object, level+1, TRUE); - - free_generalNames(gn, FALSE); - } - break; - case AUTH_KEY_ID_CERT_SERIAL: - *authKeySerialNumber = object; - break; - default: - break; + free_generalNames(gn, FALSE); + } + break; + case AUTH_KEY_ID_CERT_SERIAL: + *authKeySerialNumber = object; + break; + default: + break; + } } - objectID++; - } + parser->destroy(parser); } -/* - * extracts an authorityInfoAcess location +/** + * Extracts an authorityInfoAcess location */ -static void -parse_authorityInfoAccess(chunk_t blob, int level0, chunk_t *accessLocation) +static void parse_authorityInfoAccess(chunk_t blob, int level0, + chunk_t *accessLocation) { - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; - int accessMethod = OID_UNKNOWN; - - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); + asn1_parser_t *parser; + chunk_t object; + int objectID; + int accessMethod = OID_UNKNOWN; - while (objectID < AUTH_INFO_ACCESS_ROOF) - { - if (!extract_object(authorityInfoAccessObjects, &objectID, &object, &level, &ctx)) - return; - - switch (objectID) { - case AUTH_INFO_ACCESS_METHOD: - accessMethod = known_oid(object); - break; - case AUTH_INFO_ACCESS_LOCATION: - { - switch (accessMethod) + parser = asn1_parser_create(authInfoAccessObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) { - case OID_OCSP: - if (*object.ptr == ASN1_CONTEXT_S_6) - { - if (asn1_length(&object) == ASN1_INVALID_LENGTH) - return; - - DBG(DBG_PARSING, - DBG_log(" '%.*s'",(int)object.len, object.ptr) - ) - - /* only HTTP(S) URIs accepted */ - if (strncasecmp(object.ptr, "http", 4) == 0) + case AUTH_INFO_ACCESS_METHOD: + accessMethod = asn1_known_oid(object); + break; + case AUTH_INFO_ACCESS_LOCATION: { - *accessLocation = object; - return; + switch (accessMethod) + { + case OID_OCSP: + if (*object.ptr == ASN1_CONTEXT_S_6) + { + if (asn1_length(&object) == ASN1_INVALID_LENGTH) + { + goto end; + } + DBG(DBG_PARSING, + DBG_log(" '%.*s'",(int)object.len, object.ptr) + ) + + /* only HTTP(S) URIs accepted */ + if (strncasecmp(object.ptr, "http", 4) == 0) + { + *accessLocation = object; + goto end; + } + } + plog("warning: ignoring OCSP InfoAccessLocation with unkown protocol"); + break; + default: + /* unkown accessMethod, ignoring */ + break; + } } - } - plog("warning: ignoring OCSP InfoAccessLocation with unkown protocol"); - break; + break; default: - /* unkown accessMethod, ignoring */ - break; + break; } - } - break; - default: - break; } - objectID++; - } - + +end: + parser->destroy(parser); } -/* - * extracts extendedKeyUsage OIDs +/** + * Extracts extendedKeyUsage OIDs */ -static bool -parse_extendedKeyUsage(chunk_t blob, int level0) +static bool parse_extendedKeyUsage(chunk_t blob, int level0) { - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; + asn1_parser_t *parser; + chunk_t object; + int objectID; + bool ocsp_signing = FALSE; - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); + parser = asn1_parser_create(extendedKeyUsageObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + if (objectID == EXT_KEY_USAGE_PURPOSE_ID + && asn1_known_oid(object) == OID_OCSP_SIGNING) + { + ocsp_signing = TRUE; + } + } + parser->destroy(parser); - while (objectID < EXT_KEY_USAGE_ROOF) - { - if (!extract_object(extendedKeyUsageObjects, &objectID - , &object, &level, &ctx)) - return FALSE; - - if (objectID == EXT_KEY_USAGE_PURPOSE_ID - && known_oid(object) == OID_OCSP_SIGNING) - return TRUE; - objectID++; - } - return FALSE; + return ocsp_signing; } -/* extracts one or several crlDistributionPoints and puts them into - * a chained list +/** + * Extracts one or several crlDistributionPoints + * and puts them into a chained list */ -static generalName_t* -parse_crlDistributionPoints(chunk_t blob, int level0) +static generalName_t* parse_crlDistributionPoints(chunk_t blob, int level0) { - asn1_ctx_t ctx; - chunk_t object; - u_int level; - int objectID = 0; + asn1_parser_t *parser; + chunk_t object; + int objectID; - generalName_t *top_gn = NULL; /* top of the chained list */ - generalName_t **tail_gn = &top_gn; /* tail of the chained list */ + generalName_t *top_gn = NULL; /* top of the chained list */ + generalName_t **tail_gn = &top_gn; /* tail of the chained list */ - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); - - while (objectID < CRL_DIST_POINTS_ROOF) - { - if (!extract_object(crlDistributionPointsObjects, &objectID, - &object, &level, &ctx)) - return NULL; - - if (objectID == CRL_DIST_POINTS_FULLNAME) + parser = asn1_parser_create(crlDistributionPointsObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) { - generalName_t *gn = parse_generalNames(object, level+1, TRUE); - /* append extracted generalNames to existing chained list */ - *tail_gn = gn; - /* find new tail of the chained list */ - while (gn != NULL) - { - tail_gn = &gn->next; gn = gn->next; - } + if (objectID == CRL_DIST_POINTS_FULLNAME) + { + generalName_t *gn; + + gn = parse_generalNames(object, parser->get_level(parser)+1, TRUE); + /* append extracted generalNames to existing chained list */ + *tail_gn = gn; + /* find new tail of the chained list */ + while (gn != NULL) + { + tail_gn = &gn->next; gn = gn->next; + } + } } - objectID++; - } - return top_gn; -} + parser->destroy(parser); + return top_gn; +} -/* +/** * Parses an X.509v3 certificate */ -bool -parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert) +bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert) { - u_char buf[BUF_LEN]; - asn1_ctx_t ctx; - bool critical; - chunk_t object; - u_int level; - int objectID = 0; - int extn_oid = OID_UNKNOWN; - - asn1_init(&ctx, blob, level0, FALSE, DBG_RAW); - - while (objectID < X509_OBJ_ROOF) - { - if (!extract_object(certObjects, &objectID, &object, &level, &ctx)) - return FALSE; - - /* those objects which will parsed further need the next higher level */ - level++; - - switch (objectID) { - case X509_OBJ_CERTIFICATE: - cert->certificate = object; - break; - case X509_OBJ_TBS_CERTIFICATE: - cert->tbsCertificate = object; - break; - case X509_OBJ_VERSION: - cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1; - DBG(DBG_PARSING, - DBG_log(" v%d", cert->version); - ) - break; - case X509_OBJ_SERIAL_NUMBER: - cert->serialNumber = object; - break; - case X509_OBJ_SIG_ALG: - cert->sigAlg = parse_algorithmIdentifier(object, level, NULL); - break; - case X509_OBJ_ISSUER: - cert->issuer = object; - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'",buf) - ) - break; - case X509_OBJ_NOT_BEFORE: - cert->notBefore = parse_time(object, level); - break; - case X509_OBJ_NOT_AFTER: - cert->notAfter = parse_time(object, level); - break; - case X509_OBJ_SUBJECT: - cert->subject = object; - DBG(DBG_PARSING, - dntoa(buf, BUF_LEN, object); - DBG_log(" '%s'",buf) - ) - break; - case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM: - if (parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION) - cert->subjectPublicKeyAlgorithm = PUBKEY_ALG_RSA; - else - { - plog(" unsupported public key algorithm"); - return FALSE; - } - break; - case X509_OBJ_SUBJECT_PUBLIC_KEY: - if (ctx.blobs[4].len > 0 && *ctx.blobs[4].ptr == 0x00) - { - /* skip initial bit string octet defining 0 unused bits */ - ctx.blobs[4].ptr++; ctx.blobs[4].len--; - } - else - { - plog(" invalid RSA public key format"); - return FALSE; - } - break; - case X509_OBJ_RSA_PUBLIC_KEY: - cert->subjectPublicKey = object; - break; - case X509_OBJ_MODULUS: - if (object.len < RSA_MIN_OCTETS + 1) - { - plog(" " RSA_MIN_OCTETS_UGH); - return FALSE; - } - if (object.len > RSA_MAX_OCTETS + (size_t)(*object.ptr == 0x00)) - { - plog(" " RSA_MAX_OCTETS_UGH); - return FALSE; - } - cert->modulus = object; - break; - case X509_OBJ_PUBLIC_EXPONENT: - cert->publicExponent = object; - break; - case X509_OBJ_EXTN_ID: - extn_oid = known_oid(object); - break; - case X509_OBJ_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - break; - case X509_OBJ_EXTN_VALUE: - { - switch (extn_oid) { - case OID_SUBJECT_KEY_ID: - cert->subjectKeyID = - parse_keyIdentifier(object, level, FALSE); - break; - case OID_SUBJECT_ALT_NAME: - cert->subjectAltName = - parse_generalNames(object, level, FALSE); - break; - case OID_BASIC_CONSTRAINTS: - cert->isCA = - parse_basicConstraints(object, level); - break; - case OID_CRL_DISTRIBUTION_POINTS: - cert->crlDistributionPoints = - parse_crlDistributionPoints(object, level); - break; - case OID_AUTHORITY_KEY_ID: - parse_authorityKeyIdentifier(object, level - , &cert->authKeyID, &cert->authKeySerialNumber); - break; - case OID_AUTHORITY_INFO_ACCESS: - parse_authorityInfoAccess(object, level, &cert->accessLocation); - break; - case OID_EXTENDED_KEY_USAGE: - cert->isOcspSigner = parse_extendedKeyUsage(object, level); - break; - case OID_NS_REVOCATION_URL: - case OID_NS_CA_REVOCATION_URL: - case OID_NS_CA_POLICY_URL: - case OID_NS_COMMENT: - if (!parse_asn1_simple_object(&object, ASN1_IA5STRING - , level, oid_names[extn_oid].name)) - { - return FALSE; - } - break; + u_char buf[BUF_LEN]; + asn1_parser_t *parser; + chunk_t object; + int objectID; + int extn_oid = OID_UNKNOWN; + bool critical; + bool success = FALSE; + + parser = asn1_parser_create(certObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser) + 1; + + switch (objectID) { + case X509_OBJ_CERTIFICATE: + cert->certificate = object; + break; + case X509_OBJ_TBS_CERTIFICATE: + cert->tbsCertificate = object; + break; + case X509_OBJ_VERSION: + cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1; + DBG(DBG_PARSING, + DBG_log(" v%d", cert->version); + ) + break; + case X509_OBJ_SERIAL_NUMBER: + cert->serialNumber = object; + break; + case X509_OBJ_SIG_ALG: + cert->sigAlg = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case X509_OBJ_ISSUER: + cert->issuer = object; + DBG(DBG_PARSING, + dntoa(buf, BUF_LEN, object); + DBG_log(" '%s'",buf) + ) + break; + case X509_OBJ_NOT_BEFORE: + cert->notBefore = asn1_parse_time(object, level); + break; + case X509_OBJ_NOT_AFTER: + cert->notAfter = asn1_parse_time(object, level); + break; + case X509_OBJ_SUBJECT: + cert->subject = object; + DBG(DBG_PARSING, + dntoa(buf, BUF_LEN, object); + DBG_log(" '%s'",buf) + ) + break; + case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO: + cert->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, + KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END); + if (cert->public_key == NULL) + { + goto end; + } + break; + case X509_OBJ_EXTN_ID: + extn_oid = asn1_known_oid(object); + break; + case X509_OBJ_CRITICAL: + critical = object.len && *object.ptr; + DBG(DBG_PARSING, + DBG_log(" %s",(critical)?"TRUE":"FALSE"); + ) + break; + case X509_OBJ_EXTN_VALUE: + { + switch (extn_oid) { + case OID_SUBJECT_KEY_ID: + if (!asn1_parse_simple_object(&object, ASN1_OCTET_STRING, + level, "keyIdentifier")) + { + goto end; + } + cert->subjectKeyID = object; + break; + case OID_SUBJECT_ALT_NAME: + cert->subjectAltName = + parse_generalNames(object, level, FALSE); + break; + case OID_BASIC_CONSTRAINTS: + cert->isCA = + parse_basicConstraints(object, level); + break; + case OID_CRL_DISTRIBUTION_POINTS: + cert->crlDistributionPoints = + parse_crlDistributionPoints(object, level); + break; + case OID_AUTHORITY_KEY_ID: + parse_authorityKeyIdentifier(object, level + , &cert->authKeyID, &cert->authKeySerialNumber); + break; + case OID_AUTHORITY_INFO_ACCESS: + parse_authorityInfoAccess(object, level, &cert->accessLocation); + break; + case OID_EXTENDED_KEY_USAGE: + cert->isOcspSigner = parse_extendedKeyUsage(object, level); + break; + case OID_NS_REVOCATION_URL: + case OID_NS_CA_REVOCATION_URL: + case OID_NS_CA_POLICY_URL: + case OID_NS_COMMENT: + if (!asn1_parse_simple_object(&object, ASN1_IA5STRING + , level, oid_names[extn_oid].name)) + { + goto end; + } + break; + default: + break; + } + } + break; + case X509_OBJ_ALGORITHM: + cert->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case X509_OBJ_SIGNATURE: + cert->signature = object; + break; default: - break; + break; } - } - break; - case X509_OBJ_ALGORITHM: - cert->algorithm = parse_algorithmIdentifier(object, level, NULL); - break; - case X509_OBJ_SIGNATURE: - cert->signature = object; - break; - default: - break; } - objectID++; - } - time(&cert->installed); - return TRUE; + success = parser->success(parser); + time(&cert->installed); + +end: + parser->destroy(parser); + return success; } -/* verify the validity of a certificate by +/** + * Verify the validity of a certificate by * checking the notBefore and notAfter dates */ -err_t -check_validity(const x509cert_t *cert, time_t *until) +err_t check_validity(const x509cert_t *cert, time_t *until) { - time_t current_time; + time_t current_time; - time(¤t_time); - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log(" not before : %s", timetoa(&cert->notBefore, TRUE)); - DBG_log(" current time: %s", timetoa(¤t_time, TRUE)); - DBG_log(" not after : %s", timetoa(&cert->notAfter, TRUE)); - ) - - if (cert->notAfter < *until) *until = cert->notAfter; + time(¤t_time); + DBG(DBG_CONTROL | DBG_PARSING , + DBG_log(" not before : %T", &cert->notBefore, TRUE); + DBG_log(" current time: %T", ¤t_time, TRUE); + DBG_log(" not after : %T", &cert->notAfter, TRUE); + ) - if (current_time < cert->notBefore) - return "certificate is not valid yet"; - if (current_time > cert->notAfter) - return "certificate has expired"; - else - return NULL; + if (cert->notAfter < *until) + { + *until = cert->notAfter; + } + if (current_time < cert->notBefore) + { + return "certificate is not valid yet"; + } + if (current_time > cert->notAfter) + { + return "certificate has expired"; + } + else + { + return NULL; + } } -/* - * verifies a X.509 certificate +/** + * Verifies a X.509 certificate */ -bool -verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) +bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until) { - int pathlen; + int pathlen; - *until = cert->notAfter; + *until = cert->notAfter; - for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) - { - x509cert_t *issuer_cert; - u_char buf[BUF_LEN]; - err_t ugh = NULL; - - DBG(DBG_CONTROL, - dntoa(buf, BUF_LEN, cert->subject); - DBG_log("subject: '%s'",buf); - dntoa(buf, BUF_LEN, cert->issuer); - DBG_log("issuer: '%s'",buf); - if (cert->authKeyID.ptr != NULL) - { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); - DBG_log("authkey: %s", buf); - } - ) + for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++) + { + x509cert_t *issuer_cert; + u_char buf[BUF_LEN]; + err_t ugh = NULL; - ugh = check_validity(cert, until); + DBG(DBG_CONTROL, + dntoa(buf, BUF_LEN, cert->subject); + DBG_log("subject: '%s'",buf); + dntoa(buf, BUF_LEN, cert->issuer); + DBG_log("issuer: '%s'",buf); + if (cert->authKeyID.ptr != NULL) + { + datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' + , buf, BUF_LEN); + DBG_log("authkey: %s", buf); + } + ) - if (ugh != NULL) - { - plog("%s", ugh); - return FALSE; - } + ugh = check_validity(cert, until); - DBG(DBG_CONTROL, - DBG_log("certificate is valid") - ) + if (ugh != NULL) + { + plog("%s", ugh); + return FALSE; + } - lock_authcert_list("verify_x509cert"); - issuer_cert = get_authcert(cert->issuer, cert->authKeySerialNumber - , cert->authKeyID, AUTH_CA); + DBG(DBG_CONTROL, + DBG_log("certificate is valid") + ) - if (issuer_cert == NULL) - { - plog("issuer cacert not found"); - unlock_authcert_list("verify_x509cert"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("issuer cacert found") - ) + lock_authcert_list("verify_x509cert"); + issuer_cert = get_authcert(cert->issuer, cert->authKeySerialNumber + , cert->authKeyID, AUTH_CA); - if (!check_signature(cert->tbsCertificate, cert->signature - , cert->algorithm, cert->algorithm, issuer_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"); + if (issuer_cert == NULL) + { + plog("issuer cacert not found"); + unlock_authcert_list("verify_x509cert"); + return FALSE; + } + DBG(DBG_CONTROL, + DBG_log("issuer cacert found") + ) - /* check if cert is a self-signed root ca */ - if (pathlen > 0 && same_dn(cert->issuer, cert->subject)) - { - DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca") - ) - return TRUE; - } - else - { - time_t nextUpdate = *until; - time_t revocationDate = UNDEFINED_TIME; - crl_reason_t revocationReason = 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)) + if (!x509_check_signature(cert->tbsCertificate, cert->signature, + cert->algorithm, issuer_cert)) { - DBG(DBG_CONTROL, - DBG_log("certificate is good but status is stale") - ) - remove_x509_public_key(cert); - return FALSE; + plog("certificate signature is invalid"); + unlock_authcert_list("verify_x509cert"); + return FALSE; } DBG(DBG_CONTROL, - DBG_log("certificate is good") + DBG_log("certificate signature is valid") ) - - /* 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 %s, reason: %s" - , timetoa(&revocationDate, TRUE) - , enum_name(&crl_reason_names, revocationReason)); - remove_x509_public_key(cert); - return FALSE; - case CERT_UNKNOWN: - case CERT_UNDEFINED: - default: - plog("certificate status unknown"); - if (strict) + unlock_authcert_list("verify_x509cert"); + + /* check if cert is a self-signed root ca */ + if (pathlen > 0 && same_dn(cert->issuer, cert->subject)) { - remove_x509_public_key(cert); - return FALSE; + DBG(DBG_CONTROL, + DBG_log("reached self-signed root ca") + ) + return TRUE; } - break; - } - } + else + { + time_t nextUpdate = *until; + time_t revocationDate = UNDEFINED_TIME; + crl_reason_t revocationReason = REASON_UNSPECIFIED; - /* go up one step in the trust chain */ - cert = issuer_cert; - } - plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN); - return FALSE; + /* 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 ca path length of %d levels exceeded", MAX_CA_PATH_LEN); + return FALSE; } -/* - * list all X.509 certs in a chained list +/** + * List all X.509 certs in a chained list */ -void -list_x509cert_chain(const char *caption, x509cert_t* cert, u_char auth_flags - , bool utc) +void list_x509cert_chain(const char *caption, x509cert_t* cert, + u_char auth_flags, bool utc) { - bool first = TRUE; - time_t now; + bool first = TRUE; + time_t now; - /* determine the current time */ - time(&now); + /* determine the current time */ + time(&now); - while (cert != NULL) - { - if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags)) + while (cert != NULL) { - unsigned keysize; - char keyid[KEYID_BUF]; - u_char buf[BUF_LEN]; - cert_t c; - - c.type = CERT_X509_SIGNATURE; - c.u.x509 = cert; - - if (first) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 %s Certificates:", caption); - whack_log(RC_COMMENT, " "); - first = FALSE; - } - - whack_log(RC_COMMENT, "%s, count: %d", timetoa(&cert->installed, utc), - cert->count); - dntoa(buf, BUF_LEN, cert->subject); - whack_log(RC_COMMENT, " subject: '%s'", buf); - dntoa(buf, BUF_LEN, cert->issuer); - whack_log(RC_COMMENT, " issuer: '%s'", buf); - datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " serial: %s", buf); - form_keyid(cert->publicExponent, cert->modulus, keyid, &keysize); - whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s" - , 8*keysize, keyid - , cert->smartcard ? ", on smartcard" : - (has_private_key(c)? ", has private key" : "")); - whack_log(RC_COMMENT, " validity: not before %s %s", - timetoa(&cert->notBefore, utc), - (cert->notBefore < now)?"ok":"fatal (not valid yet)"); - whack_log(RC_COMMENT, " not after %s %s", - timetoa(&cert->notAfter, utc), - check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE)); - if (cert->subjectKeyID.ptr != NULL) - { - datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " subjkey: %s", buf); - } - if (cert->authKeyID.ptr != NULL) - { - datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':' - , buf, BUF_LEN); - whack_log(RC_COMMENT, " authkey: %s", buf); - } - if (cert->authKeySerialNumber.ptr != NULL) - { - datatot(cert->authKeySerialNumber.ptr, cert->authKeySerialNumber.len - , ':', buf, BUF_LEN); - whack_log(RC_COMMENT, " aserial: %s", buf); - } + if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags)) + { + u_char buf[BUF_LEN]; + public_key_t *key = cert->public_key; + cert_t c; + + c.type = CERT_X509_SIGNATURE; + c.u.x509 = cert; + + if (first) + { + whack_log(RC_COMMENT, " "); + whack_log(RC_COMMENT, "List of X.509 %s Certificates:", caption); + whack_log(RC_COMMENT, " "); + first = FALSE; + } + + whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, + cert->count); + dntoa(buf, BUF_LEN, cert->subject); + whack_log(RC_COMMENT, " subject: '%s'", buf); + dntoa(buf, BUF_LEN, cert->issuer); + whack_log(RC_COMMENT, " issuer: '%s'", buf); + datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':', + buf, BUF_LEN); + whack_log(RC_COMMENT, " serial: %s", buf); + whack_log(RC_COMMENT, " validity: not before %T %s", + &cert->notBefore, utc, + (cert->notBefore < now)?"ok":"fatal (not valid yet)"); + whack_log(RC_COMMENT, " not after %T %s", + &cert->notAfter, utc, + check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE)); + whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", + key_type_names, key->get_type(key), + key->get_keysize(key) * BITS_PER_BYTE, + cert->smartcard ? ", on smartcard" : + (has_private_key(c)? ", has private key" : "")); + whack_log(RC_COMMENT, " keyid: %Y", + key->get_id(key, ID_PUBKEY_INFO_SHA1)); + if (cert->subjectKeyID.ptr != NULL) + { + datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':', + buf, BUF_LEN); + whack_log(RC_COMMENT, " subjkey: %s", buf); + } + if (cert->authKeyID.ptr != NULL) + { + datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':', + buf, BUF_LEN); + whack_log(RC_COMMENT, " authkey: %s", buf); + } + if (cert->authKeySerialNumber.ptr != NULL) + { + datatot(cert->authKeySerialNumber.ptr, + cert->authKeySerialNumber.len, ':', buf, BUF_LEN); + whack_log(RC_COMMENT, " aserial: %s", buf); + } + } + cert = cert->next; } - cert = cert->next; - } } -/* - * list all X.509 end certificates in a chained list +/** + * List all X.509 end certificates in a chained list */ -void -list_x509_end_certs(bool utc) +void list_x509_end_certs(bool utc) { - list_x509cert_chain("End", x509certs, AUTH_NONE, utc); + list_x509cert_chain("End", x509certs, AUTH_NONE, utc); } diff --git a/src/pluto/x509.h b/src/pluto/x509.h index 67730bbd0..ab0fbac9e 100644 --- a/src/pluto/x509.h +++ b/src/pluto/x509.h @@ -2,7 +2,7 @@ * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss * Copyright (C) 2002 Mario Strasser - * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur + * 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 @@ -13,28 +13,29 @@ * 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. - * - * RCSID $Id: x509.h 3252 2007-10-06 21:24:50Z andreas $ */ #ifndef _X509_H #define _X509_H -#include "pkcs1.h" +#include <credentials/keys/public_key.h> +#include <credentials/keys/private_key.h> + +#include "constants.h" #include "id.h" /* Definition of generalNames kinds */ typedef enum { - GN_OTHER_NAME = 0, - GN_RFC822_NAME = 1, - GN_DNS_NAME = 2, - GN_X400_ADDRESS = 3, - GN_DIRECTORY_NAME = 4, - GN_EDI_PARTY_NAME = 5, - GN_URI = 6, - GN_IP_ADDRESS = 7, - GN_REGISTERED_ID = 8 + GN_OTHER_NAME = 0, + GN_RFC822_NAME = 1, + GN_DNS_NAME = 2, + GN_X400_ADDRESS = 3, + GN_DIRECTORY_NAME = 4, + GN_EDI_PARTY_NAME = 5, + GN_URI = 6, + GN_IP_ADDRESS = 7, + GN_REGISTERED_ID = 8 } generalNames_t; /* access structure for a GeneralName */ @@ -42,9 +43,9 @@ typedef enum { typedef struct generalName generalName_t; struct generalName { - generalName_t *next; - generalNames_t kind; - chunk_t name; + generalName_t *next; + generalNames_t kind; + chunk_t name; }; /* access structure for an X.509v3 certificate */ @@ -52,46 +53,42 @@ struct generalName { typedef struct x509cert x509cert_t; struct x509cert { - x509cert_t *next; - time_t installed; - int count; - bool smartcard; - u_char authority_flags; - chunk_t certificate; - chunk_t tbsCertificate; - u_int version; - chunk_t serialNumber; - /* signature */ - int sigAlg; - chunk_t issuer; - /* validity */ - time_t notBefore; - time_t notAfter; - chunk_t subject; - /* subjectPublicKeyInfo */ - enum pubkey_alg subjectPublicKeyAlgorithm; - chunk_t subjectPublicKey; - chunk_t modulus; - chunk_t publicExponent; - /* issuerUniqueID */ - /* subjectUniqueID */ - /* v3 extensions */ - /* extension */ - /* extension */ - /* extnID */ - /* critical */ - /* extnValue */ - bool isCA; - bool isOcspSigner; /* ocsp */ - chunk_t subjectKeyID; - chunk_t authKeyID; - chunk_t authKeySerialNumber; - chunk_t accessLocation; /* ocsp */ - generalName_t *subjectAltName; - generalName_t *crlDistributionPoints; - /* signatureAlgorithm */ - int algorithm; - chunk_t signature; + x509cert_t *next; + time_t installed; + int count; + bool smartcard; + u_char authority_flags; + chunk_t certificate; + chunk_t tbsCertificate; + u_int version; + chunk_t serialNumber; + /* signature */ + int sigAlg; + chunk_t issuer; + /* validity */ + time_t notBefore; + time_t notAfter; + chunk_t subject; + public_key_t *public_key; + /* issuerUniqueID */ + /* subjectUniqueID */ + /* v3 extensions */ + /* extension */ + /* extension */ + /* extnID */ + /* critical */ + /* extnValue */ + bool isCA; + bool isOcspSigner; /* ocsp */ + chunk_t subjectKeyID; + chunk_t authKeyID; + chunk_t authKeySerialNumber; + chunk_t accessLocation; /* ocsp */ + generalName_t *subjectAltName; + generalName_t *crlDistributionPoints; + /* signatureAlgorithm */ + int algorithm; + chunk_t signature; }; /* used for initialization */ @@ -105,33 +102,37 @@ extern bool same_x509cert(const x509cert_t *a, const x509cert_t *b); extern void hex_str(chunk_t bin, chunk_t *str); extern int dn_count_wildcards(chunk_t dn); extern int dntoa(char *dst, size_t dstlen, chunk_t dn); -extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn - , const char* null_dn); +extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn, + const char* null_dn); extern err_t atodn(char *src, chunk_t *dn); extern void gntoid(struct id *id, const generalName_t *gn); -extern void compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID); +extern bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID); extern void select_x509cert_id(x509cert_t *cert, struct id *end_id); extern bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert); extern time_t parse_time(chunk_t blob, int level0); extern void parse_authorityKeyIdentifier(chunk_t blob, int level0 - , chunk_t *authKeyID, chunk_t *authKeySerialNumber); + , chunk_t *authKeyID, chunk_t *authKeySerialNumber); extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit); extern err_t check_validity(const x509cert_t *cert, time_t *until); -extern bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg - , int enc_alg, const x509cert_t *issuer_cert); + +extern bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm, + const x509cert_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(const x509cert_t *cert, bool strict, time_t *until); extern x509cert_t* add_x509cert(x509cert_t *cert); -extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid - , x509cert_t* chain); -extern void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key - , const RSA_private_key_t *signer_key); +extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid, + x509cert_t* chain); +extern void build_x509cert(x509cert_t *cert, public_key_t *cert_key, + private_key_t *signer_key); extern chunk_t build_subjectAltNames(generalName_t *subjectAltNames); extern void share_x509cert(x509cert_t *cert); extern void release_x509cert(x509cert_t *cert); extern void free_x509cert(x509cert_t *cert); extern void store_x509certs(x509cert_t **firstcert, bool strict); -extern void list_x509cert_chain(const char *caption, x509cert_t* cert - , u_char auth_flags, bool utc); +extern void list_x509cert_chain(const char *caption, x509cert_t* cert, + u_char auth_flags, bool utc); extern void list_x509_end_certs(bool utc); extern void free_generalNames(generalName_t* gn, bool free_name); diff --git a/src/pluto/xauth.c b/src/pluto/xauth.c index 8f4dc2460..af2d72d71 100644 --- a/src/pluto/xauth.c +++ b/src/pluto/xauth.c @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: xauth.c 3738 2008-04-02 19:04:45Z andreas $ */ #include <dlfcn.h> @@ -29,51 +27,51 @@ void xauth_init(void) { #ifdef XAUTH_DEFAULT_LIB - xauth_module.handle = dlopen(XAUTH_DEFAULT_LIB, RTLD_NOW); + xauth_module.handle = dlopen(XAUTH_DEFAULT_LIB, RTLD_NOW); - if (xauth_module.handle != NULL) - { - DBG(DBG_CONTROL, - DBG_log("xauth module '%s' loading'", XAUTH_DEFAULT_LIB) - ) - xauth_module.get_secret = (bool (*) (const xauth_t*)) - dlsym(xauth_module.handle, "get_secret"); - DBG(DBG_CONTROL, - if (xauth_module.get_secret != NULL) - { - DBG_log("xauth module: found get_secret() function"); - } - ) - xauth_module.verify_secret = (bool (*) (const xauth_peer_t*, const xauth_t*)) - dlsym(xauth_module.handle, "verify_secret"); - DBG(DBG_CONTROL, - if (xauth_module.verify_secret != NULL) - { - DBG_log("xauth module: found verify_secret() function"); - } - ) - } + if (xauth_module.handle != NULL) + { + DBG(DBG_CONTROL, + DBG_log("xauth module '%s' loading'", XAUTH_DEFAULT_LIB) + ) + xauth_module.get_secret = (bool (*) (const xauth_t*)) + dlsym(xauth_module.handle, "get_secret"); + DBG(DBG_CONTROL, + if (xauth_module.get_secret != NULL) + { + DBG_log("xauth module: found get_secret() function"); + } + ) + xauth_module.verify_secret = (bool (*) (const xauth_peer_t*, const xauth_t*)) + dlsym(xauth_module.handle, "verify_secret"); + DBG(DBG_CONTROL, + if (xauth_module.verify_secret != NULL) + { + DBG_log("xauth module: found verify_secret() function"); + } + ) + } #endif - /* any null function pointers will be filled in by default functions */ - xauth_defaults(); + /* any null function pointers will be filled in by default functions */ + xauth_defaults(); } void xauth_finalize(void) { #ifdef XAUTH_DEFAULT_LIB - if (xauth_module.handle != NULL) - { - if (dlclose(xauth_module.handle)) - { - plog("failed to unload xauth module"); - } - else + if (xauth_module.handle != NULL) { - DBG(DBG_CONTROL, - DBG_log("xauth module unloaded") - ) + if (dlclose(xauth_module.handle)) + { + plog("failed to unload xauth module"); + } + else + { + DBG(DBG_CONTROL, + DBG_log("xauth module unloaded") + ) + } } - } #endif } diff --git a/src/pluto/xauth.h b/src/pluto/xauth.h index fd7e5399f..8ab125ac4 100644 --- a/src/pluto/xauth.h +++ b/src/pluto/xauth.h @@ -11,8 +11,6 @@ * 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. - * - * RCSID $Id: xauth.h 3738 2008-04-02 19:04:45Z andreas $ */ #ifndef _XAUTH_H @@ -26,20 +24,20 @@ struct chunk_t; typedef struct { - char *conn_name; - char id[BUF_LEN]; - char ip_address[ADDRTOT_BUF]; + char *conn_name; + char id[BUF_LEN]; + char ip_address[ADDRTOT_BUF]; } xauth_peer_t; typedef struct { - chunk_t user_name; - chunk_t user_password; + chunk_t user_name; + chunk_t user_password; } xauth_t; typedef struct { - void *handle; - bool (*get_secret) (xauth_t *xauth_secret); - bool (*verify_secret) (const xauth_peer_t *peer, const xauth_t *xauth_secret); + void *handle; + bool (*get_secret) (xauth_t *xauth_secret); + bool (*verify_secret) (const xauth_peer_t *peer, const xauth_t *xauth_secret); } xauth_module_t; extern xauth_module_t xauth_module; |