From 7c52c3f35cdbdff58443b994f2f33d13b4d81f57 Mon Sep 17 00:00:00 2001 From: Rene Mayrhofer Date: Tue, 23 Jun 2009 11:35:38 +0000 Subject: Updated to new upstream version. --- src/pluto/Makefile.am | 52 +- src/pluto/Makefile.in | 239 +- src/pluto/TODO | 129 - src/pluto/ac.c | 1575 ++++--- src/pluto/ac.h | 56 +- src/pluto/adns.c | 726 ++-- src/pluto/adns.h | 56 +- src/pluto/alg/ike_alg_aes.c | 68 - src/pluto/alg/ike_alg_blowfish.c | 52 - src/pluto/alg/ike_alg_serpent.c | 70 - src/pluto/alg/ike_alg_sha2.c | 634 --- src/pluto/alg/ike_alg_twofish.c | 85 - src/pluto/alg/ike_alginit.c | 7 - src/pluto/alg_info.c | 1539 +++---- src/pluto/alg_info.h | 69 +- src/pluto/asn1.c | 806 ---- src/pluto/asn1.h | 141 - src/pluto/ca.c | 923 ++-- src/pluto/ca.h | 42 +- src/pluto/certs.c | 374 +- src/pluto/certs.h | 63 +- src/pluto/connections.c | 6580 ++++++++++++++-------------- src/pluto/connections.h | 270 +- src/pluto/constants.c | 1071 ++--- src/pluto/constants.h | 1013 ++--- src/pluto/cookie.c | 68 +- src/pluto/cookie.h | 8 +- src/pluto/crl.c | 1197 +++--- src/pluto/crl.h | 34 +- src/pluto/crypto.c | 997 +++-- src/pluto/crypto.h | 91 +- src/pluto/db_ops.c | 541 ++- src/pluto/db_ops.h | 36 +- src/pluto/defs.c | 346 +- src/pluto/defs.h | 97 +- src/pluto/demux.c | 3950 ++++++++--------- src/pluto/demux.h | 64 +- src/pluto/dnskey.c | 2609 +++++------ src/pluto/dnskey.h | 70 +- src/pluto/dsa.c | 476 -- src/pluto/dsa.h | 32 - src/pluto/elgamal.c | 613 --- src/pluto/elgamal.h | 35 - src/pluto/fetch.c | 1293 +++--- src/pluto/fetch.h | 28 +- src/pluto/foodgroups.c | 606 ++- src/pluto/foodgroups.h | 4 +- src/pluto/gcryptfix.c | 283 -- src/pluto/gcryptfix.h | 111 - src/pluto/id.c | 672 +-- src/pluto/id.h | 34 +- src/pluto/ike_alg.c | 775 ++-- src/pluto/ike_alg.h | 86 +- src/pluto/ipsec_doi.c | 8830 +++++++++++++++++++------------------- src/pluto/ipsec_doi.h | 80 +- src/pluto/kameipsec.h | 46 +- src/pluto/kernel.c | 4681 ++++++++++---------- src/pluto/kernel.h | 204 +- src/pluto/kernel_alg.c | 1163 +++-- src/pluto/kernel_alg.h | 2 - src/pluto/kernel_netlink.c | 1748 ++++---- src/pluto/kernel_netlink.h | 2 - src/pluto/kernel_noklips.c | 60 +- src/pluto/kernel_noklips.h | 2 - src/pluto/kernel_pfkey.c | 1212 +++--- src/pluto/kernel_pfkey.h | 2 - src/pluto/keys.c | 2249 +++++----- src/pluto/keys.h | 79 +- src/pluto/lex.c | 268 +- src/pluto/lex.h | 20 +- src/pluto/log.c | 1115 ++--- src/pluto/log.h | 104 +- src/pluto/md2.c | 237 - src/pluto/md2.h | 72 - src/pluto/md5.c | 385 -- src/pluto/md5.h | 75 - src/pluto/modecfg.c | 1773 ++++---- src/pluto/modecfg.h | 2 - src/pluto/mp_defs.c | 70 - src/pluto/mp_defs.h | 36 - src/pluto/nat_traversal.c | 1279 +++--- src/pluto/nat_traversal.h | 62 +- src/pluto/ocsp.c | 2396 +++++------ src/pluto/ocsp.h | 64 +- src/pluto/packet.c | 1286 +++--- src/pluto/packet.h | 312 +- src/pluto/pem.c | 485 +-- src/pluto/pem.h | 10 +- src/pluto/pgp.c | 647 --- src/pluto/pgp.h | 54 - src/pluto/pgpcert.c | 496 +++ src/pluto/pgpcert.h | 56 + src/pluto/pkcs1.c | 676 --- src/pluto/pkcs1.h | 88 - src/pluto/pkcs7.c | 1341 +++--- src/pluto/pkcs7.h | 32 +- src/pluto/plutomain.c | 1125 ++--- src/pluto/primegen.c | 593 --- src/pluto/rcv_whack.c | 1013 +++-- src/pluto/rcv_whack.h | 2 - src/pluto/rnd.c | 250 -- src/pluto/rnd.h | 21 - src/pluto/server.c | 1434 +++---- src/pluto/server.h | 28 +- src/pluto/sha1.c | 193 - src/pluto/sha1.h | 16 - src/pluto/smallprime.c | 122 - src/pluto/smartcard.c | 2746 ++++++------ src/pluto/smartcard.h | 56 +- src/pluto/spdb.c | 3779 ++++++++-------- src/pluto/spdb.h | 84 +- src/pluto/state.c | 1358 +++--- src/pluto/state.h | 276 +- src/pluto/timer.c | 875 ++-- src/pluto/timer.h | 16 +- src/pluto/vendor.c | 795 ++-- src/pluto/vendor.h | 254 +- src/pluto/virtual.c | 411 +- src/pluto/virtual.h | 6 +- src/pluto/x509.c | 3375 +++++++-------- src/pluto/x509.h | 137 +- src/pluto/xauth.c | 74 +- src/pluto/xauth.h | 18 +- 123 files changed, 37963 insertions(+), 46691 deletions(-) delete mode 100644 src/pluto/TODO delete mode 100644 src/pluto/alg/ike_alg_aes.c delete mode 100644 src/pluto/alg/ike_alg_blowfish.c delete mode 100644 src/pluto/alg/ike_alg_serpent.c delete mode 100644 src/pluto/alg/ike_alg_sha2.c delete mode 100644 src/pluto/alg/ike_alg_twofish.c delete mode 100644 src/pluto/alg/ike_alginit.c delete mode 100644 src/pluto/asn1.c delete mode 100644 src/pluto/asn1.h delete mode 100644 src/pluto/dsa.c delete mode 100644 src/pluto/dsa.h delete mode 100644 src/pluto/elgamal.c delete mode 100644 src/pluto/elgamal.h delete mode 100644 src/pluto/gcryptfix.c delete mode 100644 src/pluto/gcryptfix.h delete mode 100644 src/pluto/md2.c delete mode 100644 src/pluto/md2.h delete mode 100644 src/pluto/md5.c delete mode 100644 src/pluto/md5.h delete mode 100644 src/pluto/mp_defs.c delete mode 100644 src/pluto/mp_defs.h delete mode 100644 src/pluto/pgp.c delete mode 100644 src/pluto/pgp.h create mode 100644 src/pluto/pgpcert.c create mode 100644 src/pluto/pgpcert.h delete mode 100644 src/pluto/pkcs1.c delete mode 100644 src/pluto/pkcs1.h delete mode 100644 src/pluto/primegen.c delete mode 100644 src/pluto/rnd.c delete mode 100644 src/pluto/rnd.h delete mode 100644 src/pluto/sha1.c delete mode 100644 src/pluto/sha1.h delete mode 100644 src/pluto/smallprime.c (limited to 'src/pluto') 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 @@ -25,10 +23,11 @@ #include -#include "constants.h" -#include "defs.h" -#include "asn1.h" +#include +#include +#include #include + #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 #include #include -#include /* ??? for h_errno */ +#include /* ??? for h_errno */ #include @@ -70,11 +68,11 @@ #endif #include "constants.h" -#include "adns.h" /* needs */ +#include "adns.h" /* needs */ /* 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 -#include -#include -#include -#include - -#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 -#include -#include -#include -#include - -#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 -#include -#include -#include -#include - -#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 -#include -#include -#include -#include - -#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 -#include -#include -#include -#include - -#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 + * Copyright (C) JuanJo Ciarlante + * 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 @@ -27,390 +26,187 @@ #include #include -#include #include +#include +#include +#include +#include +#include + + #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 -#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 6f3695874..000000000 --- a/src/pluto/asn1.c +++ /dev/null @@ -1,806 +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 . - * - * 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 -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "mp_defs.h" -#include "asn1.h" -#include -#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--; - } - if (len > blob->len) - { - DBG(DBG_PARSING, - DBG_log("length is larger than remaining blob size") - ) - return ASN1_INVALID_LENGTH; - } - 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; - - if (sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min) != 2) - { - return 0; /* error in positive timezone offset format */ - } - 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; - - if (sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min) != 2) - { - return 0; /* error in negative timezone offset format */ - } - 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"; - - if (sscanf(utctime->ptr, format, &t.tm_year, &t.tm_mon, &t.tm_mday, - &t.tm_hour, &t.tm_min) != 5) - { - return 0; /* error in time st [yy]yymmddhhmm time format */ - } - } - - /* is there a seconds field? */ - if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14)) - { - if (sscanf(eot-2, "%2d", &t.tm_sec) != 1) - { - return 0; /* error in ss seconds field format */ - } - } - 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) - { - 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 . - * - * 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 -#include - -#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 @@ -23,7 +21,6 @@ #include #include -#include #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 @@ -19,241 +19,251 @@ #include #include -#include + +#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 + #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 @@ -25,20 +23,21 @@ #include #include #include -#include /* missing from on old systems */ +#include /* missing from on old systems */ #include #include -#include #include "kameipsec.h" +#include + #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 */ -#include "dnskey.h" /* needs keys.h and adns.h */ +#include "adns.h" /* needs */ +#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) + { + /** + * 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 (prev != NULL) - { - prev->next = p->next; /* remove p from list */ - p->next = host_pairs; /* and stick it on front */ - host_pairs = p; - } - break; + 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; + 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) - { - if (strict) - whack_log(RC_UNKNOWN_NAME - , "no connection named \"%s\"", nm); - break; - } - if (streq(p->name, nm) - && (!strict || p->kind != CK_INSTANCE)) + for (prev = NULL, p = connections; ; prev = p, p = p->ac_next) { - 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); + struct connection **pp + , *p; - if (k <= CK_PERMANENT) + for (pp = &hp->connections; (p = *pp) != NULL; ) { - /* 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); + 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, "?"); + 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; } - } - - 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, "?"); + + 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)) - { - /* load cert from smartcard */ - valid_cert = scx_load_cert(filename, &dst->sc, &cert, &cached_cert); - } - else + if (filename != NULL) { - /* 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; + 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); - - 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); + + if (ugh != NULL) + { + loglog(RC_BADID, "bad %s --id: %s (ignored)", which, ugh); + dst->id = empty_id; /* ignore bad one */ + } } - } - dst->ca = empty_chunk; + 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]=""; - - 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]=""; - - 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]=""; + + 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]=""; + + 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]; -/* Derive a template connection from a group connection and target. - * Similar to instantiate(). Happens at whack --listen. + (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]; + + addrtot(our_client, 0, ocb, sizeof(ocb)); + addrtot(peer_client, 0, pcb, sizeof(pcb)); - for (; c != NULL; c = c->hp_next) + 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) + { + continue; + } + + for (sr = &c->spd; best!=c && sr; sr = sr->next) { - best = c; + 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; + + myid_state = try_state; - ugh = "no KEY RR found for us"; - for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next) + 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"; + } + 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; + 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; - ugh = "no TXT RR found for us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) + myid_state = try_state; + + 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"; + } + 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; + 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. + /* What connection shall we use? + * First try for one that explicitly handles the clients. */ - 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. - */ - - /* 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; - } + /* 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_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; - } + /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */ - 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) + if(c->kind == CK_INSTANCE) { - 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; + 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; */ } -#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; -#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) - { - 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; - - 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]; + + subnettot(our_net, 0, s1, sizeof(s1)); + subnettot(peer_net, 0, d1, sizeof(d1)); - /* give priority to current connection - * but even greater priority to a routed concrete connection - */ - { - struct connection *unrouted = NULL; - int srnum = -1; + 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) + for (pp = &st->st_connection->host_pair->pending; (p = *pp) != NULL; ) { - 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; + 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; + struct host_pair *hp = st->st_connection->host_pair; - if (hp != NULL) - { - struct pending **pp - , *p; - - 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 #include -#include #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< 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 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 +#include +#include + 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); * 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 @@ -23,45 +22,52 @@ #include +#include +#include + #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 -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 @@ -23,13 +23,15 @@ #include #include -#include + +#include +#include +#include +#include #include "constants.h" #include "defs.h" #include "log.h" -#include "asn1.h" -#include #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 -#include -#include -#include - #include -#define HEADER_DES_LOCL_H /* stupid trick to force prototype decl in */ -#include - -#include #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 /* GNU MP library */ +#include +#include +#include +#include +#include -#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 -#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 - * /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 + * /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 - * /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 + * /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 @@ -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 #include +#include + #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 #include #include -#include /* only used for belt-and-suspenders select call */ -#include /* only used for forensic poll call */ +#include /* only used for belt-and-suspenders select call */ +#include /* only used for forensic poll call */ #include #include #include @@ -119,9 +117,9 @@ #include #if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) -# include /* for __u8, __u32 */ +# include /* for __u8, __u32 */ # include -# include /* struct iovec */ +# include /* struct iovec */ #endif #include @@ -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), ] PubKey_r, PubKey_r - * SMF_RPKE_AUTH: - * --> HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<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), ] PubKey_r, PubKey_r - * --> HDR, KE, PubKey_i, PubKey_i - * SMF_RPKE_AUTH: - * HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<Ke_i] - * --> HDR, PubKey_i, Ke_r, 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, PubKey_i, PubKey_i - * --> HDR*, HASH_I - * SMF_RPKE_AUTH: HDR, PubKey_i, Ke_r, 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), ] PubKey_r, PubKey_r + * SMF_RPKE_AUTH: + * --> HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<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), ] PubKey_r, PubKey_r + * --> HDR, KE, PubKey_i, PubKey_i + * SMF_RPKE_AUTH: + * HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<Ke_i] + * --> HDR, PubKey_i, Ke_r, 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, PubKey_i, PubKey_i + * --> HDR*, HASH_I + * SMF_RPKE_AUTH: HDR, PubKey_i, Ke_r, 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; - - int from_len = sizeof(from); - - int packet_len; - - struct msghdr emh; - struct iovec eiov; - union { - /* force alignment (not documented as necessary) */ - struct cmsghdr ecms; + 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; - /* how much space is enough? */ - unsigned char space[256]; - } ecms_buf; + int from_len = sizeof(from); - struct cmsghdr *cm; - char fromstr[sizeof(" for message to port 65536") + INET6_ADDRSTRLEN]; - struct state *sender = NULL; + int packet_len; - zero(&from.sa); - from_len = sizeof(from); + struct msghdr emh; + struct iovec eiov; + union { + /* force alignment (not documented as necessary) */ + struct cmsghdr ecms; - 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; + /* how much space is enough? */ + unsigned char space[256]; + } ecms_buf; - eiov.iov_base = buffer; /* see readv(2) */ - eiov.iov_len = sizeof(buffer); + struct cmsghdr *cm; + char fromstr[sizeof(" for message to port 65536") + INET6_ADDRSTRLEN]; + struct state *sender = NULL; - packet_len = recvmsg(ifp->fd, &emh, MSG_ERRQUEUE); + zero(&from.sa); + from_len = sizeof(from); - 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); - } + 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; - 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 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); + eiov.iov_base = buffer; /* see readv(2) */ + eiov.iov_len = sizeof(buffer); - 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; - } + packet_len = recvmsg(ifp->fd, &emh, MSG_ERRQUEUE); - 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 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)); + 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: - offstr = inet_ntop(offender->sa_family - , &((const struct sockaddr_in6 *)offender)->sin6_addr - , offstrspace, sizeof(offstrspace)); + 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; - 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; } + for (cm = CMSG_FIRSTHDR(&emh) + ; cm != NULL + ; cm = CMSG_NXTHDR(&emh,cm)) { - 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 + { + 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_ugh = "unexpected Address Family"; + /* "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)) + if (ifp->ike_float == TRUE) { - 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; + 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); + }); -#define IKEV2_VERSION_OFFSET 17 -#define IKEV2_VERSION 0x20 + DBG(DBG_RAW, + DBG_dump("", md->packet_pbs.start, pbs_room(&md->packet_pbs))); - /* 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; - } + if ((pbs_room(&md->packet_pbs)==1) && (md->packet_pbs.start[0]==0xff)) + { + /** + * NAT-T Keep-alive packets should be discarded by kernel ESPinUDP + * layer. But bogus keep-alive packets (sent with a non-esp marker) + * can reach this point. Complain and discard them. + */ + DBG(DBG_NATT, + DBG_log("NAT-T keep-alive (bogus ?) should not reach this point. " + "Ignored. Sender: %s:%u", ip_str(cur_from), + (unsigned) cur_from_port); + ) + return FALSE; + } + +#define IKEV2_VERSION_OFFSET 17 +#define IKEV2_VERSION 0x20 + + /* ignore IKEv2 packets - they will be handled by charon */ + if (pbs_room(&md->packet_pbs) > IKEV2_VERSION_OFFSET + && md->packet_pbs.start[IKEV2_VERSION_OFFSET] == 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; + } + + st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie + , &md->sender, md->hdr.isa_msgid); + + if (st == NULL) + { + bool has_xauth_policy; + + /* No appropriate ModeCfg state. + * See if we have a Main Mode state. + * ??? what if this is a duplicate of another message? + */ + st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie + , &md->sender, 0); - set_cur_state(st); + 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; - /* 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; + /* + * 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)); + + 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; + } - /* Mark as encrypted */ - md->encrypted = TRUE; + /* Mark as encrypted */ + md->encrypted = TRUE; - DBG(DBG_CRYPT, DBG_log("decrypting %u bytes using algorithm %s" - , (unsigned) pbs_left(&md->message_pbs) - , enum_show(&oakley_enc_names, st->st_oakley.encrypt))); + DBG(DBG_CRYPT, DBG_log("decrypting %u bytes using algorithm %s" + , (unsigned) pbs_left(&md->message_pbs) + , enum_show(&oakley_enc_names, st->st_oakley.encrypt))); - /* do the specified decryption - * - * IV is from st->st_iv or (if new_iv_set) st->st_new_iv. - * The new IV is placed in st->st_new_iv - * - * See RFC 2409 "IKE" Appendix B - * - * XXX The IV should only be updated really if the packet - * is successfully processed. - * We should keep this value, check for a success return - * value from the parsing routines and then replace. - * - * Each post phase 1 exchange generates IVs from - * the last phase 1 block, not the last block sent. - */ - { - const struct encrypt_desc *e = st->st_oakley.encrypter; + /* 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; - 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; - } - } + 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); - DBG_cond_dump(DBG_CRYPT, "decrypted:\n", md->message_pbs.cur - , md->message_pbs.roof - md->message_pbs.cur); + 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, "next IV:" - , st->st_new_iv, st->st_new_iv_len); - } - else - { - /* packet was not encryped -- should it have been? */ + /* XXX Detect weak keys */ - if (smc->flags & SMF_INPUT_ENCRYPTED) - { - loglog(RC_LOG_SERIOUS, "packet rejected: should have been encrypted"); - SEND_NOTIFICATION(INVALID_FLAGS); - return; + /* grab a copy of raw packet (for duplicate packet detection) */ + md->raw_packet = chunk_create(md->packet_pbs.start, pbs_room(&md->packet_pbs)); + md->raw_packet = chunk_clone(md->raw_packet); + + data = chunk_create(md->message_pbs.cur, pbs_left(&md->message_pbs)); + + /* Decrypt everything after header */ + if (!new_iv_set) + { + /* use old IV */ + passert(st->st_iv_len <= sizeof(st->st_new_iv)); + st->st_new_iv_len = st->st_iv_len; + memcpy(st->st_new_iv, st->st_iv, st->st_new_iv_len); + } + + /* form iv by truncation */ + st->st_new_iv_len = crypter_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 @@ -26,32 +24,34 @@ #include #include #include -#include /* ??? for h_errno */ +#include /* ??? for h_errno */ #include #include -#include + +#include +#include #include "constants.h" -#include "adns.h" /* needs */ +#include "adns.h" /* needs */ #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 -#include -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "rnd.h" -#include "gcryptfix.h" -#else /*! PLUTO */ -/* #include */ -#endif /* !PLUTO */ - -#include -#include -#include - -#ifndef PLUTO -/* #include */ -/* #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 -#include -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "rnd.h" -#include "gcryptfix.h" -#else /*! PLUTO */ -/* #include */ -#endif /* !PLUTO */ - -#include -#include -#include - -#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 - * 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 @@ -25,24 +23,17 @@ #include #endif -#ifdef LIBCURL -#include -#endif - #include -#ifdef LIBLDAP -#ifndef LDAP_DEPRECATED -#define LDAP_DEPRECATED 1 -#endif -#include -#endif +#include +#include +#include +#include #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 @@ -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 . - * - * 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 - -#include -#include -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "rnd.h" -#include "gcryptfix.h" /* includes "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<= 0 && idx < (1<= 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 . - * - * 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 @@ -22,13 +20,12 @@ #include #include #include -#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says defines this */ -# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */ +#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says defines this */ +# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */ #endif #include #include -#include #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 + * Copyright (C) JuanJo Ciarlante + * 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 @@ -21,16 +20,19 @@ #include #include -#include + +#include +#include +#include +#include +#include #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 = ""; - } - -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 + #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 @@ -24,16 +23,22 @@ #include #include #include -#include /* missing from on old systems */ +#include /* missing from on old systems */ #include -#include /* for gettimeofday */ +#include /* for gettimeofday */ #include -#include + +#include +#include +#include +#include +#include +#include +#include #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 */ -#include "dnskey.h" /* needs keys.h and adns.h */ +#include "demux.h" /* needs packet.h */ +#include "adns.h" /* needs */ +#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) + if (ke_pd == NULL) { - loglog(RC_LOG_SERIOUS, "missing KE payload in %s message", msg_name); - return INVALID_KEY_INFORMATION; - } - } - else - { - if (st->st_pfs_group == NULL) - { - loglog(RC_LOG_SERIOUS, "%s message KE payload requires a GROUP_DESCRIPTION attribute in SA" - , msg_name); - return 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(); + } + + /* 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; - 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; - } + 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 */ + { + 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 { - 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); + while (ns != said) + { - 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); - } + 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 (d->isad_nospi == 0) + { + loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: no SPI"); + return; + } - if (nat_traversal_enabled) - nat_traversal_change_port_lookup(md, dst); + 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; + } - loglog(RC_LOG_SERIOUS, "received Delete SA payload: " - "deleting ISAKMP State #%lu", dst->st_serialno); - delete_state(dst); - set_cur_connection(oldc); - } + 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; } - else + + if (pbs_left(&p->pbs) != d->isad_nospi * 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: 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) + int whack_sock = dup_any(st->st_whack_sock); + lset_t policy = st->st_policy; + + if (IS_PHASE1(st->st_state)) { - policy |= POLICY_AUTHENTICATE; - if (st->st_ah.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_esp.present && st->st_esp.attrs.transid != ESP_NULL) + else { - policy |= POLICY_ENCRYPT; - if (st->st_esp.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); } - if (st->st_ipcomp.present) - { - policy |= POLICY_COMPRESS; - if (st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; - } - passert(HAS_IPSEC_POLICY(policy)); - ipsecdoi_initiate(whack_sock, st->st_connection, policy, try - , st->st_serialno); - } } /* SKEYID for preshared keys. * See draft-ietf-ipsec-ike-01.txt 4.1 */ -static bool -skeyid_preshared(struct state *st) +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 - -# 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); + prf = lib->crypto->create_prf(lib->crypto, prf_alg); + prf->set_key(prf, st->st_skeyid); - 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) + { + return 0; /* failure: no key to use */ + } + if (!private->sign(private, scheme, hash, &sig)) { - ugh = "4" "invalid Padding String"; - break; + 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; + + /* try all gateway records hung off c */ + if (c->policy & POLICY_OPPO) + { + struct gw_info *gw; - pp = &pubkeys; + 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; + } + } + } - for (p = pubkeys; p != NULL; p = *pp) + /* 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 - */ -#ifndef NO_IKE_ALG - if (st->st_connection) - st->st_pfs_group = ike_alg_pfsgroup(st->st_connection, policy); - if (!st->st_pfs_group) -#endif - /* If PFS specified, use the same group as during Phase 1: - * since no negotiation is possible, we pick one that is - * very likely supported. - */ - st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL; - - /* Emit SA payload based on a subset of the policy bits. - * POLICY_COMPRESS is considered iff we can do IPcomp. - */ - { - lset_t pm = POLICY_ENCRYPT | POLICY_AUTHENTICATE; - - if (can_do_IPcomp) - pm |= POLICY_COMPRESS; - - if (!out_sa(&rbody - , &ipsec_sadb[(st->st_policy & pm) >> POLICY_IPSEC_SHIFT] - , st, FALSE, ISAKMP_NEXT_NONCE)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Ni out */ - if (!build_and_ship_nonce(&st->st_ni, &rbody - , policy & POLICY_PFS? ISAKMP_NEXT_KE : has_client? ISAKMP_NEXT_ID : np - , "Ni")) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } + 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; - /* [ KE ] out (for PFS) */ + insert_state(st); /* needs cookies, connection, and msgid */ - 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 (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) { - reset_cur_state(); - return STF_INTERNAL_ERROR; + /* 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; - /* [ 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)) + /* 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))) { - reset_cur_state(); - return STF_INTERNAL_ERROR; + send_natoa = TRUE; + np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ? + ISAKMP_NEXT_NATOA_RFC : ISAKMP_NEXT_NATOA_DRAFTS; } - } - /* Send NAT-OA if our address is NATed */ - if (send_natoa) - { - if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &rbody, st)) + /* set up reply */ + init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet"); + + /* HDR* out */ { - reset_cur_state(); - return STF_INTERNAL_ERROR; + 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; + } } - } - /* finish computing HASH(1), inserting it in output */ - (void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur - , st, &st->st_msgid, FALSE); + /* HASH(1) -- create and note space to be filled later */ + START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA); - /* encrypt message, except for fixed part of header */ + /* SA out */ - 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); + /* + * See if pfs_group has been specified for this conn, + * if not, fallback to old use-same-as-P1 behaviour + */ +#ifndef NO_IKE_ALG + if (st->st_connection) + st->st_pfs_group = ike_alg_pfsgroup(st->st_connection, policy); + if (!st->st_pfs_group) +#endif + /* If PFS specified, use the same group as during Phase 1: + * since no negotiation is possible, we pick one that is + * very likely supported. + */ + st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL; - if (!encrypt_message(&rbody, st)) - { - 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; -} + /* 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; -/* - * Decode the CERT payload of Phase 1. - */ -static void -decode_cert(struct msg_digest *md) -{ - struct payload_digest *p; - - for (p = md->chain[ISAKMP_NEXT_CERT]; p != NULL; p = p->next) - { - struct isakmp_cert *const cert = &p->payload.cert; - chunk_t blob; - time_t valid_until; - blob.ptr = p->pbs.cur; - blob.len = pbs_left(&p->pbs); - if (cert->isacert_type == CERT_X509_SIGNATURE) - { - x509cert_t cert = empty_x509cert; - if (parse_x509cert(blob, 0, &cert)) - { - if (verify_x509cert(&cert, strict_crl_policy, &valid_until)) + if (!out_sa(&rbody + , &ipsec_sadb[(st->st_policy & pm) >> POLICY_IPSEC_SHIFT] + , st, FALSE, ISAKMP_NEXT_NONCE)) { - DBG(DBG_PARSING, - DBG_log("Public key validated") - ) - add_x509_public_key(&cert, valid_until, DAL_SIGNED); - } - else - { - plog("X.509 certificate rejected"); + reset_cur_state(); + return STF_INTERNAL_ERROR; } - 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 + /* Ni out */ + if (!build_and_ship_nonce(&st->st_ni, &rbody + , policy & POLICY_PFS? ISAKMP_NEXT_KE : has_client? ISAKMP_NEXT_ID : np + , "Ni")) { - 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); + reset_cur_state(); + return STF_INTERNAL_ERROR; } - } -} -/* - * Decode the CR payload of Phase 1. - */ -static void -decode_cr(struct msg_digest *md, struct connection *c) -{ - struct payload_digest *p; + /* [ KE ] out (for PFS) */ - 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; + if (st->st_pfs_group != NULL) + { + if (!build_and_ship_KE(st, &st->st_gi, st->st_pfs_group + , &rbody, has_client? ISAKMP_NEXT_ID : np)) + { + reset_cur_state(); + return STF_INTERNAL_ERROR; + } + } - DBG_cond_dump_chunk(DBG_PARSING, "CR", ca_name); + /* [ IDci, IDcr ] out */ + if (has_client) + { + /* IDci (we are initiator), then IDcr (peer is responder) */ + if (!emit_subnet_id(&c->spd.this.client + , ISAKMP_NEXT_ID, st->st_myuserprotoid, st->st_myuserport, &rbody) + || !emit_subnet_id(&c->spd.that.client + , np, st->st_peeruserprotoid, st->st_peeruserport, &rbody)) + { + reset_cur_state(); + return STF_INTERNAL_ERROR; + } + } - if (cr->isacr_type == CERT_X509_SIGNATURE) + /* Send NAT-OA if our address is NATed */ + if (send_natoa) { - char buf[BUF_LEN]; + if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &rbody, st)) + { + reset_cur_state(); + return STF_INTERNAL_ERROR; + } + } - 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); - ) + /* finish computing HASH(1), inserting it in output */ + (void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur + , st, &st->st_msgid, FALSE); + + /* encrypt message, except for fixed part of header */ + + init_phase2_iv(isakmp_sa, &st->st_msgid); + st->st_new_iv_len = isakmp_sa->st_new_iv_len; + memcpy(st->st_new_iv, isakmp_sa->st_new_iv, st->st_new_iv_len); + + if (!encrypt_message(&rbody, st)) + { + reset_cur_state(); + return STF_INTERNAL_ERROR; } + + /* save packet, now that we know its size */ + st->st_tpacket = chunk_create(reply.start, pbs_offset(&reply)); + st->st_tpacket = chunk_clone(st->st_tpacket); + + /* send the packet */ + + send_packet(st, "quick_outI1"); + + delete_event(st); + event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); + + if (replacing == SOS_NOBODY) + whack_log(RC_NEW_STATE + STATE_QUICK_I1 + , "%s: initiate" + , enum_name(&state_names, st->st_state)); else - loglog(RC_LOG_SERIOUS, "ignoring %s certificate request payload", - enum_show(&cert_type_names, cr->isacr_type)); - } + whack_log(RC_NEW_STATE + STATE_QUICK_I1 + , "%s: initiate to replace #%lu" + , enum_name(&state_names, st->st_state) + , replacing); + reset_cur_state(); + return STF_OK; } -/* Decode the 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. + +/* + * Decode the CERT payload of Phase 1. */ -static bool -decode_peer_id(struct msg_digest *md, struct id *peer) +static void decode_cert(struct msg_digest *md) { - 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; - } + 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) + { + 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); + } + } +} - peer->kind = id->isaid_idtype; +/* + * Decode the CR payload of Phase 1. + */ +static void decode_cr(struct msg_digest *md, struct connection *c) +{ + struct payload_digest *p; - switch (peer->kind) - { - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - /* failure mode for initaddr is probably inappropriate address length */ + for (p = md->chain[ISAKMP_NEXT_CR]; p != NULL; p = p->next) { - err_t ugh = initaddr(id_pbs->cur, pbs_left(id_pbs) - , peer->kind == ID_IPV4_ADDR? AF_INET : AF_INET6 - , &peer->ip_addr); + 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; - 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_cond_dump_chunk(DBG_PARSING, "CR", ca_name); + + 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 = 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)); } - break; +} - case ID_USER_FQDN: - if (memchr(id_pbs->cur, '@', pbs_left(id_pbs)) == NULL) +/* Decode the ID payload of Phase 1 (main_inI3_outR3 and main_inR3) + * Note: we may change connections as a result. + * We must be called before SIG or HASH are decoded since we + * may change the peer's public key or ID. + */ +static bool decode_peer_id(struct msg_digest *md, 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)) { - loglog(RC_LOG_SERIOUS, "peer's ID_USER_FQDN contains no @"); - 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); } - /* FALLTHROUGH */ - case ID_FQDN: - if (memchr(id_pbs->cur, '\0', 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, "Phase 1 ID Payload of type %s contains a NUL" - , enum_show(&ident_names, peer->kind)); - 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; } - /* ??? ought to do some more sanity check, but what? */ + 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 */ + { + 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; + } - setchunk(peer->name, id_pbs->cur, pbs_left(id_pbs)); - break; + /* ??? ought to do some more sanity check, but what? */ - 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; + peer->name = chunk_create(id_pbs->cur, pbs_left(id_pbs)); + 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_KEY_ID: + peer->name = chunk_create(id_pbs->cur, pbs_left(id_pbs)); + DBG(DBG_PARSING, + DBG_dump_chunk("KEY ID:", 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; - } + 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; - { - char buf[BUF_LEN]; + 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; + } - idtoa(peer, buf, sizeof(buf)); - plog("Peer ID is %s: '%s'", - enum_show(&ident_names, id->isaid_idtype), buf); - } + { + char buf[BUF_LEN]; - /* check for certificates */ - decode_cert(md); - return TRUE; + 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; } /* 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; + 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; + chunk_t peer_ca = (st->st_peer_pubkey != NULL) + ? st->st_peer_pubkey->issuer : chunk_empty; - DBG(DBG_CONTROL, - char buf[BUF_LEN]; - - 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; - /* more keying material needed: prepare to go around again */ + default: + bad_case(protoid); + } - hmac_reinit(&ctx_me); - hmac_reinit(&ctx_peer); + pi->keymat_len = needed_len; - 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); + /* 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); + + prf_our->get_bytes(prf_our, st->st_ni, NULL); + prf_peer->get_bytes(prf_peer, st->st_ni, NULL); + + 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; + } + + /* 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) + { + c = find_host_connection(&md->iface->addr, NAT_T_IKE_FLOAT_PORT + , &md->sender, md->sender_port, policy); + } + + if (c == NULL) { - struct connection *d; + /* 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); + 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), ] PubKey_r, PubKey_r - * --> HDR, KE, PubKey_i, PubKey_i + * --> HDR, KE, PubKey_i, PubKey_i * RPKE_AUTH: - * HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<Ke_i] - * --> HDR, PubKey_i, Ke_r, Ke_r + * HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<Ke_i] + * --> HDR, PubKey_i, Ke_r, 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; - u_int8_t np = ISAKMP_NEXT_NONE; + /* 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); - /* KE in */ - RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs)); + u_int8_t np = ISAKMP_NEXT_NONE; - /* Ni in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); + /* KE in */ + RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs)); + + /* Ni in */ + RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); - if (st->nat_traversal & NAT_T_WITH_NATD) - { - nat_traversal_natd_lookup(md); + 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, PubKey_i, PubKey_i - * --> HDR*, HASH_I + * --> HDR*, HASH_I * SMF_RPKE_AUTH: HDR, PubKey_i, Ke_r, 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); + + /* done parsing; initialize crypto */ + compute_dh_shared(st, st->st_gr); + if (!generate_skeyids_iv(st)) + return STF_FAIL + AUTHENTICATION_FAILED; - 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 (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; - - passert(cur_state == NULL); - - /* if st == NULL, our state has been deleted -- just clean up */ - if (st != NULL) - { - stf_status r; + struct key_continuation *kc = (void *)cr; + struct state *st = kc->md->st; - passert(st->st_suspended_md == kc->md); - st->st_suspended_md = NULL; /* no longer connected or suspended */ - cur_state = st; + passert(cur_state == NULL); - 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 st == NULL, our state has been deleted -- just clean up */ + if (st != NULL) { + stf_status r; + + passert(st->st_suspended_md == kc->md); + st->st_suspended_md = NULL; /* no longer connected or suspended */ + cur_state = st; + + if (!kc->failure_ok && ugh != NULL) + { + report_key_dns_failure(&st->st_connection->spd.that.id, ugh); + r = STF_FAIL + 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]; - case vos_our_txt: - next_step = vos_his_client; + 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) { - 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; - - /* 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"); + struct state *const st = md->st; + const struct connection *c = st->st_connection; - /* 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]; + + if (id_pd != NULL) + { + /* ??? we are assuming IPSEC_DOI */ - /* IDci (we are initiator) */ + /* IDci (we are initiator) */ - if (!check_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs - , &st->st_myuserprotoid, &st->st_myuserport - , &st->st_connection->spd.this.client - , "our client")) - return STF_FAIL + INVALID_ID_INFORMATION; + 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; - /* IDcr (responder is peer) */ + /* 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; - } + 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); + } - if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN) - return STF_INTERNAL_ERROR; + /* Encrypt message (preserve st_iv and st_new_iv) */ + { + u_char old_iv[MAX_DIGEST_LEN]; + u_char new_iv[MAX_DIGEST_LEN]; - memcpy(old_iv, st->st_iv, old_iv_len); - memcpy(new_iv, st->st_new_iv, new_iv_len); + u_int old_iv_len = st->st_iv_len; + u_int new_iv_len = st->st_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; - - setchunk(st->st_tpacket, reply.start, pbs_offset(&reply)); - send_packet(st, "ISAKMP notify"); - st->st_tpacket = saved_tpacket; - } - - return STF_IGNORE; + if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN) + return STF_INTERNAL_ERROR; + + memcpy(old_iv, st->st_iv, old_iv_len); + memcpy(new_iv, st->st_new_iv, new_iv_len); + + init_phase2_iv(st, &msgid); + if (!encrypt_message(&rbody, st)) + return STF_INTERNAL_ERROR; + + /* restore preserved st_iv and st_new_iv */ + memcpy(st->st_iv, old_iv, old_iv_len); + memcpy(st->st_new_iv, new_iv, new_iv_len); + st->st_iv_len = old_iv_len; + st->st_new_iv_len = new_iv_len; + } + + /* Send packet (preserve st_tpacket) */ + { + chunk_t saved_tpacket = st->st_tpacket; + + st->st_tpacket = chunk_create(reply.start, pbs_offset(&reply)); + send_packet(st, "ISAKMP notify"); + st->st_tpacket = saved_tpacket; + } + + return STF_IGNORE; } /* * DPD Out Initiator */ -void -dpd_outI(struct state *p2st) +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 @@ -31,12 +29,14 @@ #include #include -#include + +#include +#include #ifdef KLIPS #include -#include /* for select(2) */ -#include /* for select(2) */ +#include /* for select(2) */ +#include /* for select(2) */ #include #include #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); -bool no_klips = FALSE; /* don't actually use KLIPS */ +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 */ 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,1003 +388,992 @@ 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; - - /* figure out which verb suffix applies */ - { - const char *hs, *cs; + char cmd[1536]; /* arbitrary limit on shell command length */ + const char *verb_suffix; - 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)); - -#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"); + const char *hs, *cs; - 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]; - - 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]; + char text_said[SATOT_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); - }); + set_text_said(text_said, that_host, spi, 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) -{ - /* 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) -{ - 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) +bool assign_hold(struct connection *c USED_BY_DEBUG, struct spd_route *sr, + int transport_proto, + const ip_address *src, + const ip_address *dst) { - /* 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]; -} + /* 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 */ -/* Add/replace/delete a shunt eroute. - * Such an eroute determines the fate of packets without the use - * of any SAs. These are defaults, in effect. - * If a negotiation has not been attempted, use %trap. - * If negotiation has failed, the choice between %trap/%pass/%drop/%reject - * is specified in the policy of connection c. - */ -static bool -shunt_eroute(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; + 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: - bad_case(op); + /* no change: this %hold is old news and should just be deleted */ + break; } - } - 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 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. */ - 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); + 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; + } } - } - 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 (!replace_bare_shunt(src, dst, BOTTOM_PRIO, SPI_HOLD, FALSE + , transport_proto, "delete narrow %hold")) + { + return FALSE; + } + sr->routing = rn; + return TRUE; } - -/* - * This is only called when s is a likely SAID with trailing protocol i.e. - * it has the form :- - * - * %:p - * @a.b.c.d:p - * - * 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) +/* install or remove eroute for SA Group */ +static bool sag_eroute(struct state *st, struct spd_route *sr, + unsigned op, const char *opname) { - 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; -} + 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; -/* scan /proc/net/ipsec_eroute every once in a while, looking for: + 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]; +} + +/* Add/replace/delete a shunt eroute. + * Such an eroute determines the fate of packets without the use + * of any SAs. These are defaults, in effect. + * If a negotiation has not been attempted, use %trap. + * If negotiation has failed, the choice between %trap/%pass/%drop/%reject + * is specified in the policy of connection c. + */ +static bool shunt_eroute(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. + */ + 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; +} + + +/* + * This is only called when s is a likely SAID with trailing protocol i.e. + * it has the form :- + * + * %:p + * @a.b.c.d:p + * + * 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) +{ + 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; +} + + +/* scan /proc/net/ipsec_eroute every once in a while, looking for: * * - %hold shunts of which Pluto isn't aware. This situation could * be caused by lost ACQUIRE messages. When found, they will @@ -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) - { - bs->count = eri.count; - bs->last_activity = nw; - } - else if (nw - bs->last_activity > SHUNT_PATIENCE) + /* shunt eroute */ + switch (ntohl(eri.said.spi)) { - eri.next = expired; - expired = clone_thing(eri, "expired %pass"); + 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)); } - } } - 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 */ + + 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; - ipsec_spi_t ipip_spi; + /* SPIs, saved for spigrouping or undoing, if necessary */ + struct kernel_sa + said[EM_MAXRELSPIS], + *said_next = said; - /* 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. - */ + 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)); + + /* 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! + */ - 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; + ipsec_spi_t ipip_spi; - if (!kernel_ops->add_sa(said_next, replace)) - goto fail; + /* 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; - said_next++; + ipip_spi = htonl(++last_tunnel_spi); + if (inbound) + st->st_tunnel_in_spi = ipip_spi; + else + st->st_tunnel_out_spi = ipip_spi; + } - inner_spi = ipip_spi; - proto = SA_IPIP; - satype = SADB_X_SATYPE_IPIP; - } + set_text_said(text_said + , &c->spd.that.host_addr, ipip_spi, SA_IPIP); - /* set up IPCOMP SA, if any */ + 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 (st->st_ipcomp.present) - { - ipsec_spi_t ipcomp_spi = inbound? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi; - unsigned compalg; + if (!kernel_ops->add_sa(said_next, replace)) + goto fail; - switch (st->st_ipcomp.attrs.transid) - { - case IPCOMP_DEFLATE: - compalg = SADB_X_CALG_DEFLATE; - break; + said_next++; - default: - loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented" - , enum_name(&ipcomp_transformid_names, st->st_ipcomp.attrs.transid)); - goto fail; + inner_spi = ipip_spi; + proto = SA_IPIP; + satype = SADB_X_SATYPE_IPIP; } - set_text_said(text_said, &dst.addr, ipcomp_spi, SA_COMP); - - 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; + /* set up IPCOMP SA, if any */ - if (!kernel_ops->add_sa(said_next, replace)) - goto fail; + if (st->st_ipcomp.present) + { + ipsec_spi_t ipcomp_spi = inbound? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi; + unsigned compalg; - said_next++; + 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; + } - encapsulation = ENCAPSULATION_MODE_TRANSPORT; - } + set_text_said(text_said, &dst.addr, ipcomp_spi, SA_COMP); - /* set up ESP SA, if any */ + 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; - 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 }, - }; + if (!kernel_ops->add_sa(said_next, replace)) + goto fail; - u_int8_t natt_type = 0; - u_int16_t natt_sport = 0; - u_int16_t natt_dport = 0; - ip_address natt_oa; + said_next++; - 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; + 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; - - *use_time = UNDEFINED_TIME; + char text_said[SATOT_BUF]; + struct kernel_sa sa; + struct connection *c = st->st_connection; - if (kernel_ops->get_sa == NULL || !st->st_esp.present) - return FALSE; + *use_time = UNDEFINED_TIME; - 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 (kernel_ops->get_sa == NULL || !st->st_esp.present) + return FALSE; - 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(" use_time: %s", timetoa(use_time, FALSE)) + DBG_log("get %s", text_said) ) - } - return TRUE; + 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; + + 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)) + { + 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)) { - return FALSE; + if (st->st_esp.present && !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 { - return FALSE; + DBG_log("assert failed at %s:%d st_state=%d", __FILE__, __LINE__, st->st_state); + return FALSE; } - } - else - { - DBG_log("assert failed at %s:%d st_state=%d", __FILE__, __LINE__, st->st_state); - return FALSE; - } - return TRUE; + 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) - { - /* 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) + if (get_sa_info(st, TRUE, &bytes, &use_time) + && use_time != UNDEFINED_TIME) { - ret = TRUE; - break; + *idle_time = time(NULL) - use_time; + ret = *idle_time >= idle_max; } - 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 + * Copyright (C) JuanJo Ciarlante + * 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 @@ -27,7 +26,6 @@ #include #include -#include #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 -#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_")*/ - : "" - : "" - ); + 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) : + "" : ""; + + 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 @@ -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 @@ -25,33 +23,34 @@ #include #include #include -#include /* missing from on old systems */ +#include /* missing from on old systems */ #include #include #ifndef GLOB_ABORTED -# define GLOB_ABORTED GLOB_ABEND /* fix for old versions */ +# define GLOB_ABORTED GLOB_ABEND /* fix for old versions */ #endif #include -#include + +#include +#include #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 */ -#include "dnskey.h" /* needs keys.h and adns.h */ +#include "adns.h" /* needs */ +#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:"; - - 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 , %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:"; + + 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 , %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 /* GNU Multi-Precision library */ +#include +#include -#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 @@ -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 @@ -23,13 +22,15 @@ #include #include #include -#include /* used only if MSG_NOSIGNAL not defined */ +#include /* used only if MSG_NOSIGNAL not defined */ #include #include #include #include #include +#include +#include #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 @@ -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 -#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 -#include -#include /* for u_int*_t */ -#include /* 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 -#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 +#include +#include + #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 . - * - * 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 - -#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 . - * - * 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 - -#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 @@ -26,10 +25,12 @@ #include #include -#include #include #include +#include +#include + #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 @@ -24,7 +22,13 @@ #include #include -#include + +#include +#include +#include +#include +#include +#include #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 #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 @@ -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 #include -#define HEADER_DES_LOCL_H /* stupid trick to force prototype decl in */ -#include + +#include +#include #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 . - * - * 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 -#include -#include - -#include -#include - -#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/pgp.h b/src/pluto/pgp.h deleted file mode 100644 index 514265086..000000000 --- a/src/pluto/pgp.h +++ /dev/null @@ -1,54 +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 . - * - * 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.h 3252 2007-10-06 21:24:50Z andreas $ - */ - -#ifndef _PGP_H -#define _PGP_H - -#include "pkcs1.h" -/* - * Length of PGP V3 fingerprint - */ -#define PGP_FINGERPRINT_SIZE MD5_DIGEST_SIZE - -typedef char fingerprint_t[PGP_FINGERPRINT_SIZE]; - -/* access structure for an OpenPGP certificate */ - -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; -}; - -extern const pgpcert_t empty_pgpcert; -extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_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); -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 */ 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 . + * + * 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 +#include +#include + +#include + +#include +#include +#include + +#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/pgpcert.h b/src/pluto/pgpcert.h new file mode 100644 index 000000000..727648391 --- /dev/null +++ b/src/pluto/pgpcert.h @@ -0,0 +1,56 @@ +/* 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef _PGPCERT_H +#define _PGPCERT_H + +#include +#include +#include + +/* + * Length of PGP V3 fingerprint + */ +#define PGP_FINGERPRINT_SIZE HASH_SIZE_MD5 + +typedef char fingerprint_t[PGP_FINGERPRINT_SIZE]; + +/* access structure for an OpenPGP certificate */ + +typedef struct pgpcert pgpcert_t; + +struct pgpcert { + 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 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); +extern void list_pgp_end_certs(bool utc); +extern void release_pgpcert(pgpcert_t *cert); +extern void free_pgpcert(pgpcert_t *cert); + +#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 . - * - * 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 -#include -#include - -#include -#include - -#include "constants.h" -#include "defs.h" -#include "mp_defs.h" -#include "asn1.h" -#include -#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 . - * - * 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 /* 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 #include -#include #include +#include +#include +#include +#include +#include +#include +#include + #include "constants.h" #include "defs.h" -#include "asn1.h" -#include -#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 +#include #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 @@ -27,7 +26,7 @@ #include #include #include -#include /* missing from on old systems */ +#include /* missing from on old systems */ #include #include #include @@ -39,6 +38,16 @@ #include +#include +#include +#include +#include + +#ifdef INTEGRITY_TEST +#include +#include +#endif /* INTEGRITY_TEST */ + #include #include @@ -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 */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "rnd.h" +#include "adns.h" /* needs */ +#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 ]" - " \\\n\t" - "[--nofork]" - " [--stderrlog]" - " [--noklips]" - " [--nocrsend]" - " \\\n\t" - "[--strictcrlpolicy]" - " [--crlcheckinterval ]" - " [--cachecrls]" - " [--uniqueids]" - " \\\n\t" - "[--interface ]" - " [--ikeport ]" - " \\\n\t" - "[--ctlbase ]" - " \\\n\t" - "[--perpeerlogbase ] [--perpeerlog]" - " \\\n\t" - "[--secretsfile ]" - " [--policygroupsdir ]" - " \\\n\t" - "[--adns ]" - "[--pkcs11module ]" - "[--pkcs11keepstate]" - "[--pkcs11initargs ]" + if (mess != NULL && *mess != '\0') + fprintf(stderr, "%s\n", mess); + fprintf(stderr + , "Usage: pluto" + " [--help]" + " [--version]" + " [--optionsfrom ]" + " \\\n\t" + "[--nofork]" + " [--stderrlog]" + " [--noklips]" + " [--nocrsend]" + " \\\n\t" + "[--strictcrlpolicy]" + " [--crlcheckinterval ]" + " [--cachecrls]" + " [--uniqueids]" + " \\\n\t" + "[--interface ]" + " [--ikeport ]" + " \\\n\t" + "[--ctlbase ]" + " \\\n\t" + "[--perpeerlogbase ] [--perpeerlog]" + " \\\n\t" + "[--secretsfile ]" + " [--policygroupsdir ]" + " \\\n\t" + "[--adns ]" + "[--pkcs11module ]" + "[--pkcs11keepstate]" + "[--pkcs11initargs ]" #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 ]" - " \\\n\t" - "[--force_keepalive] [--disable_port_floating]" - " \\\n\t" - "[--virtual_private ]" - "\n" - "strongSwan %s\n" - , ipsec_version_code()); - exit_pluto(mess == NULL? 0 : 1); + " \\\n\t" + "[--nat_traversal] [--keep_alive ]" + " \\\n\t" + "[--force_keepalive] [--disable_port_floating]" + " \\\n\t" + "[--virtual_private ]" + "\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 "\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 "\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 */ - 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